[vala] Support GVariant casts and GDBus clients and servers



commit f0615f3438758c60a7f7860c992d27ee447af964
Author: Jürg Billeter <j bitron ch>
Date:   Sat Jun 19 21:43:44 2010 +0200

    Support GVariant casts and GDBus clients and servers

 codegen/Makefile.am                       |    6 +-
 codegen/valaccodebasemodule.vala          |  113 +++
 codegen/valaccodegenerator.vala           |   17 +-
 codegen/valagdbusclientmodule.vala        |  908 ++++++++++++++++++++++
 codegen/valagdbusmodule.vala              |  110 +++
 codegen/valagdbusservermodule.vala        | 1186 +++++++++++++++++++++++++++++
 codegen/valagvariantmodule.vala           |  788 +++++++++++++++++++
 vala/valaarraytype.vala                   |    5 +
 vala/valadatatype.vala                    |    7 +-
 vapi/gio-2.0.vapi                         |    4 +-
 vapi/packages/gio-2.0/gio-2.0-custom.vala |    6 +
 vapi/packages/gio-2.0/gio-2.0.metadata    |    1 +
 12 files changed, 3145 insertions(+), 6 deletions(-)
---
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
index 7581eb6..49406d1 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -47,12 +47,16 @@ libvala_la_VALASOURCES = \
 	valadovastructmodule.vala \
 	valadovavaluemodule.vala \
 	valaenumregisterfunction.vala \
+	valagasyncmodule.vala \
+	valagdbusclientmodule.vala \
+	valagdbusmodule.vala \
+	valagdbusservermodule.vala \
 	valagerrormodule.vala \
 	valagirwriter.vala \
 	valagobjectmodule.vala \
 	valagsignalmodule.vala \
 	valagtypemodule.vala \
-	valagasyncmodule.vala \
+	valagvariantmodule.vala \
 	valainterfaceregisterfunction.vala \
 	valastructregisterfunction.vala \
 	valatyperegisterfunction.vala \
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 63f8795..1d2691f 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -196,8 +196,10 @@ public class Vala.CCodeBaseModule : CCodeModule {
 	public DataType gquark_type;
 	public DataType genumvalue_type;
 	public Struct gvalue_type;
+	public Class gvariant_type;
 	public Struct mutex_type;
 	public TypeSymbol type_module_type;
+	public TypeSymbol dbus_proxy_type;
 	public TypeSymbol dbus_object_type;
 
 	public bool in_plugin = false;
@@ -336,6 +338,7 @@ public class Vala.CCodeBaseModule : CCodeModule {
 			gquark_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Quark"));
 			genumvalue_type = new ObjectType ((Class) glib_ns.scope.lookup ("EnumValue"));
 			gvalue_type = (Struct) glib_ns.scope.lookup ("Value");
+			gvariant_type = (Class) glib_ns.scope.lookup ("Variant");
 			mutex_type = (Struct) glib_ns.scope.lookup ("StaticRecMutex");
 
 			type_module_type = (TypeSymbol) glib_ns.scope.lookup ("TypeModule");
@@ -355,6 +358,8 @@ public class Vala.CCodeBaseModule : CCodeModule {
 				}
 			}
 
+			dbus_proxy_type = (TypeSymbol) glib_ns.scope.lookup ("DBusProxy");
+
 			var dbus_ns = root_symbol.scope.lookup ("DBus");
 			if (dbus_ns != null) {
 				dbus_object_type = (TypeSymbol) dbus_ns.scope.lookup ("Object");
@@ -4428,6 +4433,66 @@ public class Vala.CCodeBaseModule : CCodeModule {
 		return rv;
 	}
 
+	int next_variant_function_id = 0;
+
+	public CCodeExpression? try_cast_variant_to_type (CCodeExpression ccodeexpr, DataType from, DataType to, Expression? expr = null) {
+		if (from == null || gvariant_type == null || from.data_type != gvariant_type) {
+			return null;
+		}
+
+		string variant_func = "_variant_get%d".printf (++next_variant_function_id);
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
+		ccall.add_argument (ccodeexpr);
+
+		var cfunc = new CCodeFunction (variant_func);
+		cfunc.modifiers = CCodeModifiers.STATIC;
+		cfunc.add_parameter (new CCodeFormalParameter ("value", "GVariant*"));
+
+		if (!to.is_real_non_null_struct_type ()) {
+			cfunc.return_type = to.get_cname ();
+		}
+
+		if (to.is_real_non_null_struct_type ()) {
+			// structs are returned via out parameter
+			cfunc.add_parameter (new CCodeFormalParameter ("result", to.get_cname () + "*"));
+		} else if (to is ArrayType) {
+			// return array length if appropriate
+			var array_type = (ArrayType) to;
+
+			for (int dim = 1; dim <= array_type.rank; dim++) {
+				var temp_decl = get_temp_variable (int_type, false, expr);
+				temp_vars.add (temp_decl);
+
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
+				cfunc.add_parameter (new CCodeFormalParameter (head.get_array_length_cname ("result", dim), "int*"));
+				expr.append_array_size (new CCodeIdentifier (temp_decl.name));
+			}
+		}
+
+		var block = new CCodeBlock ();
+		var fragment = new CCodeFragment ();
+		var result = deserialize_expression (fragment, to, new CCodeIdentifier ("value"), new CCodeIdentifier ("*result"));
+
+		block.add_statement (fragment);
+		block.add_statement (new CCodeReturnStatement (result));
+
+		source_declarations.add_type_member_declaration (cfunc.copy ());
+
+		cfunc.block = block;
+		source_type_member_definition.append (cfunc);
+
+		return ccall;
+	}
+
+	public virtual CCodeExpression? deserialize_expression (CCodeFragment fragment, DataType type, CCodeExpression variant_expr, CCodeExpression? expr) {
+		return null;
+	}
+
+	public virtual CCodeExpression? serialize_expression (CCodeFragment fragment, DataType type, CCodeExpression expr) {
+		return null;
+	}
+
 	public override void visit_cast_expression (CastExpression expr) {
 		var valuecast = try_cast_value_to_type ((CCodeExpression) expr.inner.ccodenode, expr.inner.value_type, expr.type_reference, expr);
 		if (valuecast != null) {
@@ -4435,6 +4500,12 @@ public class Vala.CCodeBaseModule : CCodeModule {
 			return;
 		}
 
+		var variantcast = try_cast_variant_to_type ((CCodeExpression) expr.inner.ccodenode, expr.inner.value_type, expr.type_reference, expr);
+		if (variantcast != null) {
+			expr.ccodenode = variantcast;
+			return;
+		}
+
 		generate_type_declaration (expr.type_reference, source_declarations);
 
 		var cl = expr.type_reference.data_type as Class;
@@ -4908,6 +4979,10 @@ public class Vala.CCodeBaseModule : CCodeModule {
 		                      && target_type.data_type == gvalue_type
 		                      && !(expression_type is NullType)
 		                      && expression_type.get_type_id () != "G_TYPE_VALUE");
+		bool gvariant_boxing = (context.profile == Profile.GOBJECT
+		                        && target_type != null
+		                        && target_type.data_type == gvariant_type
+		                        && expression_type.data_type != gvariant_type);
 
 		if (expression_type.value_owned
 		    && (target_type == null || !target_type.value_owned || boxing || unboxing)) {
@@ -5002,6 +5077,44 @@ public class Vala.CCodeBaseModule : CCodeModule {
 			cexpr = ccomma;
 
 			return cexpr;
+		} else if (gvariant_boxing) {
+			// implicit conversion to GVariant
+			string variant_func = "_variant_new%d".printf (++next_variant_function_id);
+
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier (variant_func));
+			ccall.add_argument (cexpr);
+
+			var cfunc = new CCodeFunction (variant_func, "GVariant*");
+			cfunc.modifiers = CCodeModifiers.STATIC;
+			cfunc.add_parameter (new CCodeFormalParameter ("value", expression_type.get_cname ()));
+
+			if (expression_type is ArrayType) {
+				// return array length if appropriate
+				var array_type = (ArrayType) expression_type;
+
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					ccall.add_argument (head.get_array_length_cexpression (expr, dim));
+					cfunc.add_parameter (new CCodeFormalParameter (head.get_array_length_cname ("value", dim), "gint"));
+				}
+			}
+
+			var block = new CCodeBlock ();
+			var fragment = new CCodeFragment ();
+			var result = serialize_expression (fragment, expression_type, new CCodeIdentifier ("value"));
+
+			// sink floating reference
+			var sink = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_ref_sink"));
+			sink.add_argument (result);
+
+			block.add_statement (fragment);
+			block.add_statement (new CCodeReturnStatement (sink));
+
+			source_declarations.add_type_member_declaration (cfunc.copy ());
+
+			cfunc.block = block;
+			source_type_member_definition.append (cfunc);
+
+			return ccall;
 		} else if (boxing) {
 			// value needs to be boxed
 
diff --git a/codegen/valaccodegenerator.vala b/codegen/valaccodegenerator.vala
index b32ba3c..d621f04 100644
--- a/codegen/valaccodegenerator.vala
+++ b/codegen/valaccodegenerator.vala
@@ -1,6 +1,6 @@
 /* valaccodegenerator.vala
  *
- * Copyright (C) 2006-2009  Jürg Billeter
+ * Copyright (C) 2006-2010  Jürg Billeter
  * Copyright (C) 2006-2008  Raffaele Sandrini
  *
  * This library is free software; you can redistribute it and/or
@@ -50,9 +50,20 @@ public class Vala.CCodeGenerator : CodeGenerator {
 			head = new GObjectModule (this, head);
 			head = new GSignalModule (this, head);
 			head = new GAsyncModule (this, head);
-			head = new DBusClientModule (this, head);
 			*/
-			head = new DBusServerModule (this, head);
+			if (context.has_package ("dbus-glib-1")) {
+				/*
+				head = new DBusModule (this, head);
+				head = new DBusClientModule (this, head);
+				*/
+				head = new DBusServerModule (this, head);
+			} else {
+				/*
+				head = new GVariantModule (this, head);
+				head = new GDBusClientModule (this, head);
+				*/
+				head = new GDBusServerModule (this, head);
+			}
 		} else if (context.profile == Profile.DOVA) {
 			/* included by inheritance
 			head = new DovaBaseModule (this, head);
diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala
new file mode 100644
index 0000000..673e792
--- /dev/null
+++ b/codegen/valagdbusclientmodule.vala
@@ -0,0 +1,908 @@
+/* valagdbusclientmodule.vala
+ *
+ * Copyright (C) 2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ * 	Philip Van Hoof <pvanhoof gnome org>
+ */
+
+public class Vala.GDBusClientModule : GDBusModule {
+	public GDBusClientModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public CCodeConstant get_dbus_timeout (Symbol symbol) {
+		int timeout = -1;
+
+		var dbus = symbol.get_attribute ("DBus");
+		if (dbus != null && dbus.has_argument ("timeout")) {
+			timeout = dbus.get_integer ("timeout");
+		} else if (symbol.parent_symbol != null) {
+			return get_dbus_timeout (symbol.parent_symbol);
+		}
+
+		return new CCodeConstant (timeout.to_string ());
+	}
+
+	public override void generate_dynamic_method_wrapper (DynamicMethod method) {
+		var dynamic_method = (DynamicMethod) method;
+
+		var func = new CCodeFunction (method.get_cname ());
+		func.modifiers = CCodeModifiers.STATIC;
+
+		var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+		generate_cparameters (method, source_declarations, cparam_map, func);
+
+		var block = new CCodeBlock ();
+		if (dynamic_method.dynamic_type.data_type == dbus_proxy_type) {
+			generate_dbus_method_wrapper (method, block);
+		} else {
+			Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ()));
+		}
+
+		// append to C source file
+		source_declarations.add_type_member_declaration (func.copy ());
+
+		func.block = block;
+		source_type_member_definition.append (func);
+	}
+
+	void generate_dbus_method_wrapper (Method m, CCodeBlock block) {
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		var cdecl = new CCodeDeclaration ("GVariant");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
+		block.add_statement (cdecl);
+
+		generate_marshalling (m, prefragment, postfragment);
+
+		block.add_statement (prefragment);
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
+		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
+		ccall.add_argument (new CCodeConstant ("\"%s\"".printf (m.name)));
+		ccall.add_argument (new CCodeIdentifier ("_arguments"));
+		ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
+		ccall.add_argument (get_dbus_timeout (m));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+		ccall.add_argument (new CCodeConstant ("error"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
+
+		// return on error
+		var error_block = new CCodeBlock ();
+		if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
+			error_block.add_statement (new CCodeReturnStatement ());
+		} else {
+			error_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
+		}
+		block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
+
+		block.add_statement (postfragment);
+
+		var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+		unref_reply.add_argument (new CCodeIdentifier ("_reply"));
+		block.add_statement (new CCodeExpressionStatement (unref_reply));
+
+		if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
+			block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
+		}
+	}
+
+	void generate_proxy_interface_init (Interface main_iface, Interface iface) {
+		// also generate proxy for prerequisites
+		foreach (var prereq in iface.get_prerequisites ()) {
+			if (prereq.data_type is Interface) {
+				generate_proxy_interface_init (main_iface, (Interface) prereq.data_type);
+			}
+		}
+
+		string lower_cname = main_iface.get_lower_case_cprefix () + "proxy";
+
+		var proxy_iface_init = new CCodeFunction (lower_cname + "_" + iface.get_lower_case_cprefix () + "interface_init", "void");
+		proxy_iface_init.add_parameter (new CCodeFormalParameter ("iface", iface.get_cname () + "Iface*"));
+
+		var iface_block = new CCodeBlock ();
+
+		foreach (Method m in iface.get_methods ()) {
+			var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.vfunc_name);
+			if (!m.coroutine) {
+				iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (main_iface, iface, m)))));
+			} else {
+				iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_async_dbus_proxy_method (main_iface, iface, m)))));
+				vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.get_finish_vfunc_name ());
+				iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_finish_dbus_proxy_method (main_iface, iface, m)))));
+			}
+		}
+
+		foreach (Property prop in iface.get_properties ()) {
+			if (prop.get_accessor != null) {
+				var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "get_" + prop.name);
+				iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_get (main_iface, iface, prop)))));
+			}
+			if (prop.set_accessor != null) {
+				var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "set_" + prop.name);
+				iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_set (main_iface, iface, prop)))));
+			}
+		}
+
+		proxy_iface_init.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_type_member_declaration (proxy_iface_init.copy ());
+		proxy_iface_init.block = iface_block;
+		source_type_member_definition.append (proxy_iface_init);
+	}
+
+	string implement_interface (CCodeFunctionCall define_type, Interface main_iface, Interface iface) {
+		string result = "";
+
+		// also implement prerequisites
+		foreach (var prereq in iface.get_prerequisites ()) {
+			if (prereq.data_type is Interface) {
+				result += implement_interface (define_type, main_iface, (Interface) prereq.data_type);
+			}
+		}
+
+		result += "G_IMPLEMENT_INTERFACE (%s, %sproxy_%sinterface_init) ".printf (
+			iface.get_upper_case_cname ("TYPE_"),
+			main_iface.get_lower_case_cprefix (),
+			iface.get_lower_case_cprefix ());
+		return result;
+	}
+
+	public override void generate_interface_declaration (Interface iface, CCodeDeclarationSpace decl_space) {
+		base.generate_interface_declaration (iface, decl_space);
+
+		string dbus_iface_name = get_dbus_name (iface);
+		if (dbus_iface_name == null) {
+			return;
+		}
+
+		string get_type_name = "%sproxy_get_type".printf (iface.get_lower_case_cprefix ());
+
+		if (decl_space.add_symbol_declaration (iface, get_type_name)) {
+			return;
+		}
+
+		decl_space.add_type_declaration (new CCodeNewline ());
+		var macro = "(%s ())".printf (get_type_name);
+		decl_space.add_type_declaration (new CCodeMacroReplacement ("%s_PROXY".printf (iface.get_type_id ()), macro));
+
+		// declare proxy_get_type function
+		var proxy_get_type = new CCodeFunction (get_type_name, "GType");
+		decl_space.add_type_member_declaration (proxy_get_type);
+	}
+
+	public override void visit_interface (Interface iface) {
+		base.visit_interface (iface);
+
+		string dbus_iface_name = get_dbus_name (iface);
+		if (dbus_iface_name == null) {
+			return;
+		}
+
+		// create proxy class
+		string cname = iface.get_cname () + "Proxy";
+		string lower_cname = iface.get_lower_case_cprefix () + "proxy";
+
+		source_declarations.add_type_declaration (new CCodeTypeDefinition ("GDBusProxy", new CCodeVariableDeclarator (cname)));
+		source_declarations.add_type_declaration (new CCodeTypeDefinition ("GDBusProxyClass", new CCodeVariableDeclarator (cname + "Class")));
+
+		var define_type = new CCodeFunctionCall (new CCodeIdentifier ("G_DEFINE_TYPE_EXTENDED"));
+		define_type.add_argument (new CCodeIdentifier (cname));
+		define_type.add_argument (new CCodeIdentifier (lower_cname));
+		define_type.add_argument (new CCodeIdentifier ("G_TYPE_DBUS_PROXY"));
+		define_type.add_argument (new CCodeConstant ("0"));
+		define_type.add_argument (new CCodeIdentifier (implement_interface (define_type, iface, iface)));
+
+		source_type_member_definition.append (new CCodeExpressionStatement (define_type));
+
+		var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void");
+		proxy_class_init.add_parameter (new CCodeFormalParameter ("klass", cname + "Class*"));
+		proxy_class_init.modifiers = CCodeModifiers.STATIC;
+		proxy_class_init.block = new CCodeBlock ();
+		var proxy_class = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY_CLASS"));
+		proxy_class.add_argument (new CCodeIdentifier ("klass"));
+		proxy_class_init.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (proxy_class, "g_signal"), new CCodeIdentifier (lower_cname + "_g_signal"))));
+		source_type_member_definition.append (proxy_class_init);
+
+		generate_signal_handler_function (iface);
+
+		var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void");
+		proxy_instance_init.add_parameter (new CCodeFormalParameter ("self", cname + "*"));
+		proxy_instance_init.modifiers = CCodeModifiers.STATIC;
+		proxy_instance_init.block = new CCodeBlock ();
+		source_type_member_definition.append (proxy_instance_init);
+
+		generate_proxy_interface_init (iface, iface);
+	}
+
+	public override void visit_method_call (MethodCall expr) {
+		var mtype = expr.call.value_type as MethodType;
+		bool get_proxy_sync = (mtype != null && mtype.method_symbol.get_cname () == "g_bus_get_proxy_sync");
+		if (!get_proxy_sync) {
+			base.visit_method_call (expr);
+			return;
+		}
+
+		var ma = (MemberAccess) expr.call;
+		var type_arg = (ObjectType) ma.get_type_arguments ().get (0);
+		var iface = (Interface) type_arg.type_symbol;
+
+		var args = expr.get_argument_list ();
+		Expression bus_type = args.get (0);
+		Expression name = args.get (1);
+		Expression object_path = args.get (2);
+		Expression cancellable = args.get (3);
+
+		// method can fail
+		current_method_inner_error = true;
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_initable_new"));
+		ccall.add_argument (new CCodeIdentifier ("%s_PROXY".printf (iface.get_type_id ())));
+		cancellable.accept (codegen);
+		ccall.add_argument ((CCodeExpression) cancellable.ccodenode);
+		ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
+		ccall.add_argument (new CCodeConstant ("\"g-flags\""));
+		ccall.add_argument (new CCodeConstant ("G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES"));
+		ccall.add_argument (new CCodeConstant ("\"g-name\""));
+		name.accept (codegen);
+		ccall.add_argument ((CCodeExpression) name.ccodenode);
+		ccall.add_argument (new CCodeConstant ("\"g-bus-type\""));
+		bus_type.accept (codegen);
+		ccall.add_argument ((CCodeExpression) bus_type.ccodenode);
+		ccall.add_argument (new CCodeConstant ("\"g-object-path\""));
+		object_path.accept (codegen);
+		ccall.add_argument ((CCodeExpression) object_path.ccodenode);
+		ccall.add_argument (new CCodeConstant ("\"g-interface-name\""));
+		ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name (iface))));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+		expr.ccodenode = ccall;
+	}
+
+	string generate_dbus_signal_handler (Signal sig, ObjectTypeSymbol sym) {
+		string wrapper_name = "_dbus_handle_%s_%s".printf (sym.get_lower_case_cname (), sig.get_cname ());
+
+		// declaration
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (wrapper_name);
+		function.modifiers = CCodeModifiers.STATIC;
+		function.add_parameter (new CCodeFormalParameter ("self", sym.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("parameters", "GVariant*"));
+		var block = new CCodeBlock ();
+
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		block.add_statement (prefragment);
+
+		cdecl = new CCodeDeclaration ("GVariantIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_iter"));
+		block.add_statement (cdecl);
+
+		var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
+		iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_iter")));
+		iter_init.add_argument (new CCodeIdentifier ("parameters"));
+		prefragment.append (new CCodeExpressionStatement (iter_init));
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
+		ccall.add_argument (new CCodeIdentifier ("self"));
+		ccall.add_argument (sig.get_canonical_cconstant ());
+
+		foreach (FormalParameter param in sig.get_parameters ()) {
+			var owned_type = param.parameter_type.copy ();
+			owned_type.value_owned = true;
+
+			cdecl = new CCodeDeclaration (owned_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator.zero (param.name, default_value_for_type (param.parameter_type, true)));
+			prefragment.append (cdecl);
+
+			var st = param.parameter_type.data_type as Struct;
+			if (st != null && !st.is_simple_type ()) {
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
+			} else {
+				ccall.add_argument (new CCodeIdentifier (param.name));
+			}
+
+			if (param.parameter_type is ArrayType) {
+				var array_type = (ArrayType) param.parameter_type;
+
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					string length_cname = get_array_length_cname (param.name, dim);
+
+					cdecl = new CCodeDeclaration ("int");
+					cdecl.add_declarator (new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
+					prefragment.append (cdecl);
+					ccall.add_argument (new CCodeIdentifier (length_cname));
+				}
+			}
+
+			read_expression (prefragment, param.parameter_type, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param.name));
+
+			if (requires_destroy (owned_type)) {
+				// keep local alive (symbol_reference is weak)
+				var local = new LocalVariable (owned_type, param.name);
+				var ma = new MemberAccess.simple (param.name);
+				ma.symbol_reference = local;
+				var stmt = new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (param.name), owned_type, ma));
+				postfragment.append (stmt);
+			}
+		}
+
+		block.add_statement (new CCodeExpressionStatement (ccall));
+
+		block.add_statement (postfragment);
+
+		source_declarations.add_type_member_declaration (function.copy ());
+
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return wrapper_name;
+	}
+
+	void generate_signal_handler_function (ObjectTypeSymbol sym) {
+		var cfunc = new CCodeFunction (sym.get_lower_case_cprefix () + "proxy_g_signal", "void");
+		cfunc.add_parameter (new CCodeFormalParameter ("proxy", "GDBusProxy*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("sender_name", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("signal_name", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("parameters", "GVariant*"));
+
+		cfunc.modifiers |= CCodeModifiers.STATIC;
+
+		source_declarations.add_type_member_declaration (cfunc.copy ());
+
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		CCodeIfStatement clastif = null;
+
+		foreach (Signal sig in sym.get_signals ()) {
+			if (sig.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+
+			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
+			ccheck.add_argument (new CCodeIdentifier ("signal_name"));
+			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
+
+			var callblock = new CCodeBlock ();
+
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_signal_handler (sig, sym)));
+			ccall.add_argument (new CCodeIdentifier ("proxy"));
+			ccall.add_argument (new CCodeIdentifier ("parameters"));
+
+			callblock.add_statement (new CCodeExpressionStatement (ccall));
+
+			var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")), callblock);
+			if (clastif == null) {
+				block.add_statement (cif);
+			} else {
+				clastif.false_statement = cif;
+			}
+
+			clastif = cif;
+		}
+
+		source_type_member_definition.append (cfunc);
+	}
+
+	void generate_marshalling (Method m, CCodeFragment prefragment, CCodeFragment postfragment) {
+		CCodeDeclaration cdecl;
+
+		cdecl = new CCodeDeclaration ("GVariantBuilder");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_builder"));
+		prefragment.append (cdecl);
+
+		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
+		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
+		prefragment.append (new CCodeExpressionStatement (builder_init));
+
+		cdecl = new CCodeDeclaration ("GVariantIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_reply_iter"));
+		postfragment.append (cdecl);
+
+		var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
+		iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_iter")));
+		iter_init.add_argument (new CCodeIdentifier ("_reply"));
+		postfragment.append (new CCodeExpressionStatement (iter_init));
+
+		foreach (FormalParameter param in m.get_parameters ()) {
+			if (param.direction == ParameterDirection.IN) {
+				CCodeExpression expr = new CCodeIdentifier (param.name);
+				if (param.parameter_type.is_real_struct_type ()) {
+					expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
+				}
+				write_expression (prefragment, param.parameter_type, new CCodeIdentifier ("_arguments_builder"), expr);
+			} else {
+				cdecl = new CCodeDeclaration (param.parameter_type.get_cname ());
+				cdecl.add_declarator (new CCodeVariableDeclarator ("_" + param.name));
+				postfragment.append (cdecl);
+
+				var array_type = param.parameter_type as ArrayType;
+
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						cdecl = new CCodeDeclaration ("int");
+						cdecl.add_declarator (new CCodeVariableDeclarator ("_%s_length%d".printf (param.name, dim), new CCodeConstant ("0")));
+						postfragment.append (cdecl);
+					}
+				}
+
+				var target = new CCodeIdentifier ("_" + param.name);
+				read_expression (postfragment, param.parameter_type, new CCodeIdentifier ("_reply_iter"), target);
+
+				// TODO check that parameter is not NULL (out parameters are optional)
+				// free value if parameter is NULL
+				postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), target)));
+
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						// TODO check that parameter is not NULL (out parameters are optional)
+						postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("%s_length%d".printf (param.name, dim))), new CCodeIdentifier ("_%s_length%d".printf (param.name, dim)))));
+					}
+				}
+			}
+		}
+
+		if (!(m.return_type is VoidType)) {
+			if (m.return_type.is_real_non_null_struct_type ()) {
+				var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
+				read_expression (postfragment, m.return_type, new CCodeIdentifier ("_reply_iter"), target);
+			} else {
+				cdecl = new CCodeDeclaration (m.return_type.get_cname ());
+				cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
+				postfragment.append (cdecl);
+
+				var array_type = m.return_type as ArrayType;
+
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						cdecl = new CCodeDeclaration ("int");
+						cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
+						postfragment.append (cdecl);
+					}
+				}
+
+				read_expression (postfragment, m.return_type, new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"));
+
+				if (array_type != null) {
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						// TODO check that parameter is not NULL (out parameters are optional)
+						postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)))));
+					}
+				}
+			}
+		}
+
+		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
+		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_arguments"), builder_end)));
+	}
+
+	string generate_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
+		string proxy_name = "%sproxy_%s".printf (main_iface.get_lower_case_cprefix (), m.name);
+
+		string dbus_iface_name = get_dbus_name (iface);
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (proxy_name);
+		function.modifiers = CCodeModifiers.STATIC;
+
+		var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+		generate_cparameters (m, source_declarations, cparam_map, function);
+
+		var block = new CCodeBlock ();
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		cdecl = new CCodeDeclaration ("GVariant");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
+		block.add_statement (cdecl);
+
+		generate_marshalling (m, prefragment, postfragment);
+
+		block.add_statement (prefragment);
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
+		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
+		ccall.add_argument (new CCodeConstant ("\"%s.%s\"".printf (dbus_iface_name, get_dbus_name_for_member (m))));
+		ccall.add_argument (new CCodeIdentifier ("_arguments"));
+		ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
+		ccall.add_argument (get_dbus_timeout (m));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+		ccall.add_argument (new CCodeConstant ("error"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
+
+		// return on error
+		var error_block = new CCodeBlock ();
+		if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
+			error_block.add_statement (new CCodeReturnStatement ());
+		} else {
+			error_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
+		}
+		block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
+
+		block.add_statement (postfragment);
+
+		var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+		unref_reply.add_argument (new CCodeIdentifier ("_reply"));
+		block.add_statement (new CCodeExpressionStatement (unref_reply));
+
+		if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
+			block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
+		}
+
+		source_declarations.add_type_member_declaration (function.copy ());
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return proxy_name;
+	}
+
+	string generate_async_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
+		string proxy_name = "%sproxy_%s_async".printf (main_iface.get_lower_case_cprefix (), m.name);
+
+		string dbus_iface_name = get_dbus_name (iface);
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (proxy_name, "void");
+		function.modifiers = CCodeModifiers.STATIC;
+
+		var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+		cparam_map.set (get_param_pos (-1), new CCodeFormalParameter ("_callback_", "GAsyncReadyCallback"));
+		cparam_map.set (get_param_pos (-0.9), new CCodeFormalParameter ("_user_data_", "gpointer"));
+
+		generate_cparameters (m, source_declarations, cparam_map, function, null, null, null, 1);
+
+		var block = new CCodeBlock ();
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		cdecl = new CCodeDeclaration ("GVariant");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
+		block.add_statement (cdecl);
+
+		generate_marshalling (m, prefragment, postfragment);
+
+		block.add_statement (prefragment);
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call"));
+		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
+		ccall.add_argument (new CCodeConstant ("\"%s.%s\"".printf (dbus_iface_name, get_dbus_name_for_member (m))));
+		ccall.add_argument (new CCodeIdentifier ("_arguments"));
+		ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
+		ccall.add_argument (get_dbus_timeout (m));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+		ccall.add_argument (new CCodeIdentifier ("_callback_"));
+		ccall.add_argument (new CCodeIdentifier ("_user_data_"));
+		block.add_statement (new CCodeExpressionStatement (ccall));
+
+		source_declarations.add_type_member_declaration (function.copy ());
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return proxy_name;
+	}
+
+	string generate_finish_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
+		string proxy_name = "%sproxy_%s_finish".printf (main_iface.get_lower_case_cprefix (), m.name);
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (proxy_name);
+		function.modifiers = CCodeModifiers.STATIC;
+
+		var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+		cparam_map.set (get_param_pos (0.1), new CCodeFormalParameter ("_res_", "GAsyncResult*"));
+
+		generate_cparameters (m, source_declarations, cparam_map, function, null, null, null, 2);
+
+		var block = new CCodeBlock ();
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		cdecl = new CCodeDeclaration ("GVariant");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
+		block.add_statement (cdecl);
+
+		generate_marshalling (m, prefragment, postfragment);
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_finish"));
+		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
+		ccall.add_argument (new CCodeIdentifier ("_res_"));
+		ccall.add_argument (new CCodeConstant ("error"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
+
+		// return on error
+		var error_block = new CCodeBlock ();
+		if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
+			error_block.add_statement (new CCodeReturnStatement ());
+		} else {
+			error_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
+		}
+		block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
+
+		block.add_statement (postfragment);
+
+		var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+		unref_reply.add_argument (new CCodeIdentifier ("_reply"));
+		block.add_statement (new CCodeExpressionStatement (unref_reply));
+
+		if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
+			block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
+		}
+
+		source_declarations.add_type_member_declaration (function.copy ());
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return proxy_name;
+	}
+
+	string generate_dbus_proxy_property_get (Interface main_iface, Interface iface, Property prop) {
+		string proxy_name = "%sdbus_proxy_get_%s".printf (main_iface.get_lower_case_cprefix (), prop.name);
+
+		string dbus_iface_name = get_dbus_name (iface);
+
+		var owned_type = prop.get_accessor.value_type.copy ();
+		owned_type.value_owned = true;
+		if (owned_type.is_disposable () && !prop.get_accessor.value_type.value_owned) {
+			Report.error (prop.get_accessor.value_type.source_reference, "Properties used in D-Bus clients require owned get accessor");
+		}
+
+		var array_type = prop.get_accessor.value_type as ArrayType;
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (proxy_name);
+		function.modifiers = CCodeModifiers.STATIC;
+
+		function.add_parameter (new CCodeFormalParameter ("self", "%s*".printf (iface.get_cname ())));
+
+		if (prop.property_type.is_real_non_null_struct_type ()) {
+			function.add_parameter (new CCodeFormalParameter ("result", "%s*".printf (prop.get_accessor.value_type.get_cname ())));
+		} else {
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					function.add_parameter (new CCodeFormalParameter ("result_length%d".printf (dim), "int*"));
+				}
+			}
+
+			function.return_type = prop.get_accessor.value_type.get_cname ();
+		}
+
+		var block = new CCodeBlock ();
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		cdecl = new CCodeDeclaration ("GVariant");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_inner_reply"));
+		block.add_statement (cdecl);
+
+		block.add_statement (prefragment);
+
+		cdecl = new CCodeDeclaration ("GVariantBuilder");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_builder"));
+		prefragment.append (cdecl);
+
+		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
+		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
+		prefragment.append (new CCodeExpressionStatement (builder_init));
+
+		// interface name
+		write_expression (prefragment, string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
+		// property name
+		write_expression (prefragment, string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
+
+		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
+		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_arguments"), builder_end)));
+
+		cdecl = new CCodeDeclaration ("GVariantIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_reply_iter"));
+		postfragment.append (cdecl);
+
+		var get_variant = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_child_value"));
+		get_variant.add_argument (new CCodeIdentifier ("_reply"));
+		get_variant.add_argument (new CCodeConstant ("0"));
+		postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_inner_reply"), get_variant)));
+
+		var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
+		iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_iter")));
+		iter_init.add_argument (new CCodeIdentifier ("_inner_reply"));
+		postfragment.append (new CCodeExpressionStatement (iter_init));
+
+		if (prop.property_type.is_real_non_null_struct_type ()) {
+			var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
+			read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_reply_iter"), target);
+		} else {
+			cdecl = new CCodeDeclaration (prop.get_accessor.value_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
+			postfragment.append (cdecl);
+
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					cdecl = new CCodeDeclaration ("int");
+					cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
+					postfragment.append (cdecl);
+				}
+			}
+
+			read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"));
+
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					// TODO check that parameter is not NULL (out parameters are optional)
+					postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)))));
+				}
+			}
+		}
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
+		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
+		ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Get\""));
+		ccall.add_argument (new CCodeIdentifier ("_arguments"));
+		ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
+		ccall.add_argument (get_dbus_timeout (prop));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
+
+		// return on error
+		var error_block = new CCodeBlock ();
+		if (prop.property_type.is_real_non_null_struct_type ()) {
+			error_block.add_statement (new CCodeReturnStatement ());
+		} else {
+			error_block.add_statement (new CCodeReturnStatement (default_value_for_type (prop.property_type, false)));
+		}
+		block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
+
+		block.add_statement (postfragment);
+
+		var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+		unref_reply.add_argument (new CCodeIdentifier ("_reply"));
+		block.add_statement (new CCodeExpressionStatement (unref_reply));
+
+		if (prop.property_type.is_real_non_null_struct_type ()) {
+			block.add_statement (new CCodeReturnStatement ());
+		} else {
+			block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
+		}
+
+		source_declarations.add_type_member_declaration (function.copy ());
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return proxy_name;
+	}
+
+	string generate_dbus_proxy_property_set (Interface main_iface, Interface iface, Property prop) {
+		string proxy_name = "%sdbus_proxy_set_%s".printf (main_iface.get_lower_case_cprefix (), prop.name);
+
+		string dbus_iface_name = get_dbus_name (iface);
+
+		var array_type = prop.set_accessor.value_type as ArrayType;
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (proxy_name);
+		function.modifiers = CCodeModifiers.STATIC;
+
+		function.add_parameter (new CCodeFormalParameter ("self", "%s*".printf (iface.get_cname ())));
+
+		if (prop.property_type.is_real_non_null_struct_type ()) {
+			function.add_parameter (new CCodeFormalParameter ("value", "%s*".printf (prop.set_accessor.value_type.get_cname ())));
+		} else {
+			function.add_parameter (new CCodeFormalParameter ("value", prop.set_accessor.value_type.get_cname ()));
+
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					function.add_parameter (new CCodeFormalParameter ("value_length%d".printf (dim), "int"));
+				}
+			}
+		}
+
+		var block = new CCodeBlock ();
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		cdecl = new CCodeDeclaration ("GVariant");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
+		block.add_statement (cdecl);
+
+		block.add_statement (prefragment);
+
+		cdecl = new CCodeDeclaration ("GVariantBuilder");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_builder"));
+		prefragment.append (cdecl);
+
+		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
+		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
+		prefragment.append (new CCodeExpressionStatement (builder_init));
+
+		// interface name
+		write_expression (prefragment, string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
+		// property name
+		write_expression (prefragment, string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
+
+		// property value (as variant)
+		var builder_open = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_open"));
+		builder_open.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		builder_open.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_VARIANT"));
+		prefragment.append (new CCodeExpressionStatement (builder_open));
+
+		if (prop.property_type.is_real_non_null_struct_type ()) {
+			write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value")));
+		} else {
+			write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeIdentifier ("value"));
+		}
+
+		var builder_close = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_close"));
+		builder_close.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		prefragment.append (new CCodeExpressionStatement (builder_close));
+
+		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
+		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_arguments"), builder_end)));
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
+		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
+		ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Set\""));
+		ccall.add_argument (new CCodeIdentifier ("_arguments"));
+		ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
+		ccall.add_argument (get_dbus_timeout (prop));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
+
+		// return on error
+		var error_block = new CCodeBlock ();
+		error_block.add_statement (new CCodeReturnStatement ());
+		block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
+
+		block.add_statement (postfragment);
+
+		var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+		unref_reply.add_argument (new CCodeIdentifier ("_reply"));
+		block.add_statement (new CCodeExpressionStatement (unref_reply));
+
+		source_declarations.add_type_member_declaration (function.copy ());
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return proxy_name;
+	}
+}
diff --git a/codegen/valagdbusmodule.vala b/codegen/valagdbusmodule.vala
new file mode 100644
index 0000000..1e32ea7
--- /dev/null
+++ b/codegen/valagdbusmodule.vala
@@ -0,0 +1,110 @@
+/* valagdbusmodule.vala
+ *
+ * Copyright (C) 2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+public class Vala.GDBusModule : GVariantModule {
+	public GDBusModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public static string? get_dbus_name (TypeSymbol symbol) {
+		var dbus = symbol.get_attribute ("DBus");
+		if (dbus == null) {
+			return null;
+		}
+
+		return dbus.get_string ("name");
+	}
+
+	public static string get_dbus_name_for_member (Symbol symbol) {
+		var dbus = symbol.get_attribute ("DBus");
+		if (dbus != null && dbus.has_argument ("name")) {
+			return dbus.get_string ("name");
+		}
+
+		return Symbol.lower_case_to_camel_case (symbol.name);
+	}
+
+	public override void visit_error_domain (ErrorDomain edomain) {
+		var edomain_dbus_name = get_dbus_name (edomain);
+		if (edomain_dbus_name == null) {
+			base.visit_error_domain (edomain);
+			return;
+		}
+
+		generate_error_domain_declaration (edomain, source_declarations);
+
+		if (!edomain.is_internal_symbol ()) {
+			generate_error_domain_declaration (edomain, header_declarations);
+		}
+		if (!edomain.is_private_symbol ()) {
+			generate_error_domain_declaration (edomain, internal_header_declarations);
+		}
+
+		var error_entries = new CCodeInitializerList ();
+		foreach (ErrorCode ecode in edomain.get_codes ()) {
+			var ecode_dbus_name = get_dbus_name (ecode);
+			if (ecode_dbus_name == null) {
+				ecode_dbus_name = Symbol.lower_case_to_camel_case (ecode.name.down ());
+			}
+
+			var error_entry = new CCodeInitializerList ();
+			error_entry.append (new CCodeIdentifier (ecode.get_cname ()));
+			error_entry.append (new CCodeConstant ("\"%s\"".printf (ecode_dbus_name)));
+			error_entries.append (error_entry);
+		}
+
+		var cdecl = new CCodeDeclaration ("const GDBusErrorEntry");
+		cdecl.add_declarator (new CCodeVariableDeclarator (edomain.get_lower_case_cname () + "_entries[]", error_entries));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_constant_declaration (cdecl);
+
+		string quark_fun_name = edomain.get_lower_case_cprefix () + "quark";
+
+		var cquark_fun = new CCodeFunction (quark_fun_name, gquark_type.data_type.get_cname ());
+		var cquark_block = new CCodeBlock ();
+
+		string quark_name = "%squark_volatile".printf (edomain.get_lower_case_cprefix ());
+
+		cdecl = new CCodeDeclaration ("gsize");
+		cdecl.add_declarator (new CCodeVariableDeclarator (quark_name, new CCodeConstant ("0")));
+		cdecl.modifiers = CCodeModifiers.STATIC | CCodeModifiers.VOLATILE;
+		cquark_block.add_statement (cdecl);
+
+		var register_call = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_error_register_error_domain"));
+		register_call.add_argument (new CCodeConstant ("\"" + edomain.get_lower_case_cname () + "-quark\""));
+		register_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (quark_name)));
+		register_call.add_argument (new CCodeIdentifier (edomain.get_lower_case_cname () + "_entries"));
+		var nentries = new CCodeFunctionCall (new CCodeIdentifier ("G_N_ELEMENTS"));
+		nentries.add_argument (new CCodeIdentifier (edomain.get_lower_case_cname () + "_entries"));
+		register_call.add_argument (nentries);
+		cquark_block.add_statement (new CCodeExpressionStatement (register_call));
+
+		cquark_block.add_statement (new CCodeReturnStatement (new CCodeCastExpression (new CCodeIdentifier (quark_name), "GQuark")));
+
+		cquark_fun.block = cquark_block;
+		source_type_member_definition.append (cquark_fun);
+	}
+
+	public override CCodeFragment register_dbus_info (ObjectTypeSymbol sym) {
+		return new CCodeFragment ();
+	}
+}
diff --git a/codegen/valagdbusservermodule.vala b/codegen/valagdbusservermodule.vala
new file mode 100644
index 0000000..3914117
--- /dev/null
+++ b/codegen/valagdbusservermodule.vala
@@ -0,0 +1,1186 @@
+/* valagdbusservermodule.vala
+ *
+ * Copyright (C) 2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+public class Vala.GDBusServerModule : GDBusClientModule {
+	public GDBusServerModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	public static bool is_dbus_visible (CodeNode node) {
+		var dbus_attribute = node.get_attribute ("DBus");
+		if (dbus_attribute != null
+		    && dbus_attribute.has_argument ("visible")
+		    && !dbus_attribute.get_bool ("visible")) {
+			return false;
+		}
+
+		return true;
+	}
+
+	public static string dbus_result_name (Method m) {
+		var dbus_attribute = m.get_attribute ("DBus");
+		if (dbus_attribute != null
+		    && dbus_attribute.has_argument ("result")) {
+			var result_name = dbus_attribute.get_string ("result");
+			if (result_name != null && result_name != "") {
+				return result_name;
+			}
+		}
+
+		return "result";
+	}
+
+	string generate_dbus_wrapper (Method m, ObjectTypeSymbol sym) {
+		string wrapper_name = "_dbus_%s".printf (m.get_cname ());
+
+		// declaration
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (wrapper_name);
+		function.modifiers = CCodeModifiers.STATIC;
+		function.add_parameter (new CCodeFormalParameter ("self", sym.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("parameters", "GVariant*"));
+		function.add_parameter (new CCodeFormalParameter ("invocation", "GDBusMethodInvocation*"));
+		var block = new CCodeBlock ();
+
+		CCodeFunction ready_function = null;
+		CCodeBlock ready_block = null;
+		if (m.coroutine) {
+			// GAsyncResult
+			source_declarations.add_include ("gio/gio.h");
+
+			ready_function = new CCodeFunction (wrapper_name + "_ready", "void");
+			ready_function.modifiers = CCodeModifiers.STATIC;
+			ready_function.add_parameter (new CCodeFormalParameter ("source_object", "GObject *"));
+			ready_function.add_parameter (new CCodeFormalParameter ("_res_", "GAsyncResult *"));
+			ready_function.add_parameter (new CCodeFormalParameter ("_user_data_", "gpointer *"));
+			ready_block = new CCodeBlock ();
+
+			cdecl = new CCodeDeclaration ("GDBusMethodInvocation *");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("invocation", new CCodeIdentifier ("_user_data_")));
+			ready_block.add_statement (cdecl);
+		}
+
+		var in_prefragment = new CCodeFragment ();
+		var in_postfragment = new CCodeFragment ();
+		var out_prefragment = in_prefragment;
+		var out_postfragment = in_postfragment;
+		if (m.coroutine) {
+			out_prefragment = new CCodeFragment ();
+			out_postfragment = new CCodeFragment ();
+		}
+
+		cdecl = new CCodeDeclaration ("GError*");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("error", new CCodeConstant ("NULL")));
+		if (m.coroutine) {
+			ready_block.add_statement (cdecl);
+		} else {
+			block.add_statement (cdecl);
+		}
+
+		block.add_statement (in_prefragment);
+		if (m.coroutine) {
+			ready_block.add_statement (out_prefragment);
+		}
+
+		cdecl = new CCodeDeclaration ("GVariant*");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_reply"));
+		out_postfragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariantIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_iter"));
+		block.add_statement (cdecl);
+
+		var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
+		iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_iter")));
+		iter_init.add_argument (new CCodeIdentifier ("parameters"));
+		in_prefragment.append (new CCodeExpressionStatement (iter_init));
+
+		cdecl = new CCodeDeclaration ("GVariantBuilder");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_reply_builder"));
+		out_postfragment.append (cdecl);
+
+		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
+		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_builder")));
+		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
+		out_postfragment.append (new CCodeExpressionStatement (builder_init));
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
+
+		CCodeFunctionCall finish_ccall = null;
+		if (m.coroutine) {
+			finish_ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_finish_cname ()));
+			finish_ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("source_object"), sym.get_cname () + "*"));
+			finish_ccall.add_argument (new CCodeIdentifier ("_res_"));
+		}
+
+		ccall.add_argument (new CCodeIdentifier ("self"));
+
+		foreach (FormalParameter param in m.get_parameters ()) {
+			var owned_type = param.parameter_type.copy ();
+			owned_type.value_owned = true;
+
+			cdecl = new CCodeDeclaration (owned_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator.zero (param.name, default_value_for_type (param.parameter_type, true)));
+			if (param.direction == ParameterDirection.IN) {
+				in_prefragment.append (cdecl);
+			} else {
+				out_prefragment.append (cdecl);
+			}
+
+			if (!m.coroutine || param.direction == ParameterDirection.IN) {
+				var st = param.parameter_type.data_type as Struct;
+				if (param.direction != ParameterDirection.IN
+				    || (st != null && !st.is_simple_type ())) {
+					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
+				} else {
+					ccall.add_argument (new CCodeIdentifier (param.name));
+				}
+			} else {
+				finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
+			}
+
+			if (param.parameter_type is ArrayType) {
+				var array_type = (ArrayType) param.parameter_type;
+
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					string length_cname = get_array_length_cname (param.name, dim);
+
+					cdecl = new CCodeDeclaration ("int");
+					cdecl.add_declarator (new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
+					if (!m.coroutine || param.direction == ParameterDirection.IN) {
+						if (param.direction != ParameterDirection.IN) {
+							out_prefragment.append (cdecl);
+							ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+						} else {
+							in_prefragment.append (cdecl);
+							ccall.add_argument (new CCodeIdentifier (length_cname));
+						}
+					} else {
+						out_prefragment.append (cdecl);
+						finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+					}
+				}
+			}
+
+			if (param.direction == ParameterDirection.IN) {
+				read_expression (in_prefragment, param.parameter_type, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param.name));
+			} else {
+				write_expression (out_postfragment, param.parameter_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier (param.name));
+			}
+
+			if (requires_destroy (owned_type)) {
+				// keep local alive (symbol_reference is weak)
+				var local = new LocalVariable (owned_type, param.name);
+				var ma = new MemberAccess.simple (param.name);
+				ma.symbol_reference = local;
+				var stmt = new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (param.name), owned_type, ma));
+				if (param.direction == ParameterDirection.IN) {
+					in_postfragment.append (stmt);
+				} else {
+					out_postfragment.append (stmt);
+				}
+			}
+		}
+
+		if (!(m.return_type is VoidType)) {
+			if (m.return_type.is_real_non_null_struct_type ()) {
+				cdecl = new CCodeDeclaration (m.return_type.get_cname ());
+				cdecl.add_declarator (new CCodeVariableDeclarator.zero ("result", default_value_for_type (m.return_type, true)));
+				out_prefragment.append (cdecl);
+
+				if (!m.coroutine) {
+					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
+				} else {
+					finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
+				}
+
+				write_expression (out_postfragment, m.return_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier ("result"));
+
+				if (requires_destroy (m.return_type)) {
+					// keep local alive (symbol_reference is weak)
+					// space before `result' is work around to not trigger
+					// variable renaming, we really mean C identifier `result' here
+					var local = new LocalVariable (m.return_type, " result");
+					var ma = new MemberAccess.simple ("result");
+					ma.symbol_reference = local;
+					out_postfragment.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("result"), m.return_type, ma)));
+				}
+
+				block.add_statement (new CCodeExpressionStatement (ccall));
+				if (m.coroutine) {
+					ready_block.add_statement (new CCodeExpressionStatement (finish_ccall));
+				}
+			} else {
+				cdecl = new CCodeDeclaration (m.return_type.get_cname ());
+				cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+				out_prefragment.append (cdecl);
+				if (!m.coroutine) {
+					block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
+				} else {
+					block.add_statement (new CCodeExpressionStatement (ccall));
+					ready_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), finish_ccall)));
+				}
+
+				if (m.return_type is ArrayType) {
+					var array_type = (ArrayType) m.return_type;
+
+					for (int dim = 1; dim <= array_type.rank; dim++) {
+						string length_cname = get_array_length_cname ("result", dim);
+
+						cdecl = new CCodeDeclaration ("int");
+						cdecl.add_declarator (new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
+						out_prefragment.append (cdecl);
+						if (!m.coroutine) {
+							ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+						} else {
+							finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+						}
+					}
+				}
+
+				write_expression (out_postfragment, m.return_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier ("result"));
+
+				if (requires_destroy (m.return_type)) {
+					// keep local alive (symbol_reference is weak)
+					// space before `result' is work around to not trigger
+					// variable renaming, we really mean C identifier `result' here
+					var local = new LocalVariable (m.return_type, " result");
+					var ma = new MemberAccess.simple ("result");
+					ma.symbol_reference = local;
+					out_postfragment.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("result"), m.return_type, ma)));
+				}
+			}
+		} else {
+			block.add_statement (new CCodeExpressionStatement (ccall));
+			if (m.coroutine) {
+				ready_block.add_statement (new CCodeExpressionStatement (finish_ccall));
+			}
+		}
+
+		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
+		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_builder")));
+		out_postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), builder_end)));
+
+		if (m.coroutine) {
+			ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (wrapper_name + "_ready"), "GAsyncReadyCallback"));
+
+			var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
+			ref_call.add_argument (new CCodeIdentifier ("invocation"));
+
+			ccall.add_argument (ref_call);
+		}
+
+		if (m.get_error_types ().size > 0) {
+			if (m.coroutine) {
+				finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
+			} else {
+				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
+			}
+
+			var error_block = new CCodeBlock ();
+
+			var return_error = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_return_gerror"));
+			return_error.add_argument (new CCodeIdentifier ("invocation"));
+			return_error.add_argument (new CCodeIdentifier ("error"));
+
+			error_block.add_statement (new CCodeReturnStatement ());
+
+			if (m.coroutine) {
+				ready_block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("error"), error_block));
+			} else {
+				block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("error"), error_block));
+			}
+		}
+
+		block.add_statement (in_postfragment);
+
+		if (!m.coroutine) {
+			var return_value = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_return_value"));
+			return_value.add_argument (new CCodeIdentifier ("invocation"));
+			return_value.add_argument (new CCodeIdentifier ("_reply"));
+			block.add_statement (new CCodeExpressionStatement (return_value));
+		} else {
+			ready_block.add_statement (out_postfragment);
+
+			var return_value = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_return_value"));
+			return_value.add_argument (new CCodeIdentifier ("invocation"));
+			return_value.add_argument (new CCodeIdentifier ("_reply"));
+			ready_block.add_statement (new CCodeExpressionStatement (return_value));
+
+			var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
+			unref_call.add_argument (new CCodeIdentifier ("invocation"));
+			ready_block.add_statement (new CCodeExpressionStatement (unref_call));
+
+			unref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+			unref_call.add_argument (new CCodeIdentifier ("_reply"));
+			ready_block.add_statement (new CCodeExpressionStatement (unref_call));
+		}
+
+		source_declarations.add_type_member_declaration (function.copy ());
+
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		if (m.coroutine) {
+			source_declarations.add_type_member_declaration (ready_function.copy ());
+
+			ready_function.block = ready_block;
+			source_type_member_definition.append (ready_function);
+		}
+
+		return wrapper_name;
+	}
+
+	string generate_dbus_signal_wrapper (Signal sig, ObjectTypeSymbol sym, string dbus_iface_name) {
+		string wrapper_name = "_dbus_%s_%s".printf (sym.get_lower_case_cname (), sig.get_cname ());
+
+		// declaration
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (wrapper_name, "void");
+		function.modifiers = CCodeModifiers.STATIC;
+
+		function.add_parameter (new CCodeFormalParameter ("_sender", "GObject*"));
+
+		foreach (var param in sig.get_parameters ()) {
+			// ensure ccodenode of parameter is set
+			generate_parameter (param, source_declarations, new HashMap<int,CCodeFormalParameter> (), null);
+
+			function.add_parameter ((CCodeFormalParameter) get_ccodenode (param));
+			if (param.parameter_type is ArrayType) {
+				var array_type = (ArrayType) param.parameter_type;
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					function.add_parameter (new CCodeFormalParameter (head.get_array_length_cname (param.name, dim), "int"));
+				}
+			}
+		}
+
+		function.add_parameter (new CCodeFormalParameter ("_data", "gpointer*"));
+
+		var block = new CCodeBlock ();
+		var prefragment = new CCodeFragment ();
+
+		cdecl = new CCodeDeclaration ("GDBusConnection *");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_connection", new CCodeElementAccess (new CCodeIdentifier ("_data"), new CCodeConstant ("1"))));
+		block.add_statement (cdecl);
+
+		cdecl = new CCodeDeclaration ("const gchar *");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_path", new CCodeElementAccess (new CCodeIdentifier ("_data"), new CCodeConstant ("2"))));
+		block.add_statement (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariant");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
+		block.add_statement (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariantBuilder");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_builder"));
+		prefragment.append (cdecl);
+
+		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
+		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
+		prefragment.append (new CCodeExpressionStatement (builder_init));
+
+		foreach (FormalParameter param in sig.get_parameters ()) {
+			CCodeExpression expr = new CCodeIdentifier (param.name);
+			if (param.parameter_type.is_real_struct_type ()) {
+				expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
+			}
+			write_expression (prefragment, param.parameter_type, new CCodeIdentifier ("_arguments_builder"), expr);
+		}
+
+		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
+		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
+		prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_arguments"), builder_end)));
+
+		block.add_statement (prefragment);
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_emit_signal"));
+		ccall.add_argument (new CCodeIdentifier ("_connection"));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+		ccall.add_argument (new CCodeIdentifier ("_path"));
+		ccall.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
+		ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
+		ccall.add_argument (new CCodeIdentifier ("_arguments"));
+		ccall.add_argument (new CCodeConstant ("NULL"));
+		block.add_statement (new CCodeExpressionStatement (ccall));
+
+		source_declarations.add_type_member_declaration (function.copy ());
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return wrapper_name;
+	}
+
+	string generate_dbus_property_get_wrapper (Property prop, ObjectTypeSymbol sym) {
+		string wrapper_name = "_dbus_%s".printf (prop.get_accessor.get_cname ());
+
+		// declaration
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (wrapper_name, "GVariant*");
+		function.modifiers = CCodeModifiers.STATIC;
+		function.add_parameter (new CCodeFormalParameter ("self", sym.get_cname () + "*"));
+		var block = new CCodeBlock ();
+
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		block.add_statement (prefragment);
+
+		cdecl = new CCodeDeclaration ("GVariant*");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_reply"));
+		postfragment.append (cdecl);
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier (prop.get_accessor.get_cname ()));
+		ccall.add_argument (new CCodeIdentifier ("self"));
+
+		if (prop.property_type.is_real_non_null_struct_type ()) {
+			cdecl = new CCodeDeclaration (prop.property_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator.zero ("result", default_value_for_type (prop.property_type, true)));
+			prefragment.append (cdecl);
+
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
+
+			block.add_statement (new CCodeExpressionStatement (ccall));
+		} else {
+			cdecl = new CCodeDeclaration (prop.property_type.get_cname ());
+			cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+			prefragment.append (cdecl);
+
+			block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
+
+			var array_type = prop.property_type as ArrayType;
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					string length_cname = get_array_length_cname ("result", dim);
+
+					cdecl = new CCodeDeclaration ("int");
+					cdecl.add_declarator (new CCodeVariableDeclarator (length_cname));
+					postfragment.append (cdecl);
+
+					ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
+				}
+			}
+		}
+
+		var reply_expr = serialize_expression (postfragment, prop.property_type, new CCodeIdentifier ("result"));
+
+		postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), reply_expr)));
+
+		if (requires_destroy (prop.property_type)) {
+			// keep local alive (symbol_reference is weak)
+			// space before `result' is work around to not trigger
+			// variable renaming, we really mean C identifier `result' here
+			var local = new LocalVariable (prop.property_type, " result");
+			var ma = new MemberAccess.simple ("result");
+			ma.symbol_reference = local;
+			postfragment.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("result"), prop.property_type, ma)));
+		}
+
+		block.add_statement (postfragment);
+
+		block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_reply")));
+
+		source_declarations.add_type_member_declaration (function.copy ());
+
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return wrapper_name;
+	}
+
+	string generate_dbus_property_set_wrapper (Property prop, ObjectTypeSymbol sym) {
+		string wrapper_name = "_dbus_%s".printf (prop.set_accessor.get_cname ());
+
+		// declaration
+
+		CCodeDeclaration cdecl;
+
+		var function = new CCodeFunction (wrapper_name);
+		function.modifiers = CCodeModifiers.STATIC;
+		function.add_parameter (new CCodeFormalParameter ("self", sym.get_cname () + "*"));
+		function.add_parameter (new CCodeFormalParameter ("_value", "GVariant*"));
+		var block = new CCodeBlock ();
+
+		var prefragment = new CCodeFragment ();
+		var postfragment = new CCodeFragment ();
+
+		block.add_statement (prefragment);
+
+		var ccall = new CCodeFunctionCall (new CCodeIdentifier (prop.set_accessor.get_cname ()));
+		ccall.add_argument (new CCodeIdentifier ("self"));
+
+		var owned_type = prop.property_type.copy ();
+		owned_type.value_owned = true;
+
+		cdecl = new CCodeDeclaration (owned_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator.zero ("value", default_value_for_type (prop.property_type, true)));
+		prefragment.append (cdecl);
+
+		var st = prop.property_type.data_type as Struct;
+		if (st != null && !st.is_simple_type ()) {
+			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
+		} else {
+			ccall.add_argument (new CCodeIdentifier ("value"));
+
+			var array_type = prop.property_type as ArrayType;
+			if (array_type != null) {
+				for (int dim = 1; dim <= array_type.rank; dim++) {
+					cdecl = new CCodeDeclaration ("int");
+					cdecl.add_declarator (new CCodeVariableDeclarator (head.get_array_length_cname ("value", dim)));
+					prefragment.append (cdecl);
+
+					ccall.add_argument (new CCodeIdentifier (head.get_array_length_cname ("value", dim)));
+				}
+			}
+		}
+
+		var target = new CCodeIdentifier ("value");
+		var expr = deserialize_expression (prefragment, prop.property_type, new CCodeIdentifier ("_value"), target);
+		prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
+
+		if (requires_destroy (owned_type)) {
+			// keep local alive (symbol_reference is weak)
+			var local = new LocalVariable (owned_type, "value");
+			var ma = new MemberAccess.simple ("value");
+			ma.symbol_reference = local;
+			var stmt = new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("value"), owned_type, ma));
+			postfragment.append (stmt);
+		}
+
+		block.add_statement (new CCodeExpressionStatement (ccall));
+
+		block.add_statement (postfragment);
+
+		source_declarations.add_type_member_declaration (function.copy ());
+
+		function.block = block;
+		source_type_member_definition.append (function);
+
+		return wrapper_name;
+	}
+
+	void handle_signals (ObjectTypeSymbol sym, CCodeBlock block) {
+		string dbus_iface_name = get_dbus_name (sym);
+		if (dbus_iface_name == null) {
+			return;
+		}
+
+		foreach (Signal sig in sym.get_signals ()) {
+			if (sig.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+			if (!is_dbus_visible (sig)) {
+				continue;
+			}
+
+			var connect = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_connect"));
+			connect.add_argument (new CCodeIdentifier ("object"));
+			connect.add_argument (sig.get_canonical_cconstant (null));
+			connect.add_argument (new CCodeCastExpression (new CCodeIdentifier (generate_dbus_signal_wrapper (sig, sym, dbus_iface_name)), "GCallback"));
+			connect.add_argument (new CCodeIdentifier ("data"));
+			block.add_statement (new CCodeExpressionStatement (connect));
+		}
+	}
+
+	void generate_interface_method_call_function (ObjectTypeSymbol sym) {
+		var cfunc = new CCodeFunction (sym.get_lower_case_cprefix () + "dbus_interface_method_call", "void");
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "GDBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("sender", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("object_path", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("interface_name", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("method_name", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("parameters", "GVariant*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("invocation", "GDBusMethodInvocation*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("data", "gpointer*"));
+
+		cfunc.modifiers |= CCodeModifiers.STATIC;
+
+		source_declarations.add_type_member_declaration (cfunc.copy ());
+
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		var cdecl = new CCodeDeclaration ("gpointer");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
+		block.add_statement (cdecl);
+
+		CCodeIfStatement clastif = null;
+
+		foreach (Method m in sym.get_methods ()) {
+			if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
+			    || m.overrides || m.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+			if (!is_dbus_visible (m)) {
+				continue;
+			}
+
+			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
+			ccheck.add_argument (new CCodeIdentifier ("method_name"));
+			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (m))));
+
+			var callblock = new CCodeBlock ();
+
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_wrapper (m, sym)));
+			ccall.add_argument (new CCodeIdentifier ("object"));
+			ccall.add_argument (new CCodeIdentifier ("parameters"));
+			ccall.add_argument (new CCodeIdentifier ("invocation"));
+
+			callblock.add_statement (new CCodeExpressionStatement (ccall));
+
+			var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")), callblock);
+			if (clastif == null) {
+				block.add_statement (cif);
+			} else {
+				clastif.false_statement = cif;
+			}
+
+			clastif = cif;
+		}
+
+		source_type_member_definition.append (cfunc);
+	}
+
+	void generate_interface_get_property_function (ObjectTypeSymbol sym) {
+		var cfunc = new CCodeFunction (sym.get_lower_case_cprefix () + "dbus_interface_get_property", "GVariant*");
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "GDBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("sender", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("object_path", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("interface_name", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("property_name", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("error", "GError**"));
+		cfunc.add_parameter (new CCodeFormalParameter ("data", "gpointer*"));
+
+		cfunc.modifiers |= CCodeModifiers.STATIC;
+
+		source_declarations.add_type_member_declaration (cfunc.copy ());
+
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		var cdecl = new CCodeDeclaration ("gpointer");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
+		block.add_statement (cdecl);
+
+		CCodeIfStatement clastif = null;
+
+		foreach (Property prop in sym.get_properties ()) {
+			if (prop.binding != MemberBinding.INSTANCE
+			    || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+			if (!is_dbus_visible (prop)) {
+				continue;
+			}
+			if (prop.get_accessor == null) {
+				continue;
+			}
+
+			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
+			ccheck.add_argument (new CCodeIdentifier ("property_name"));
+			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
+
+			var callblock = new CCodeBlock ();
+
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_property_get_wrapper (prop, sym)));
+			ccall.add_argument (new CCodeIdentifier ("object"));
+
+			callblock.add_statement (new CCodeReturnStatement (ccall));
+
+			var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")), callblock);
+			if (clastif == null) {
+				block.add_statement (cif);
+			} else {
+				clastif.false_statement = cif;
+			}
+
+			clastif = cif;
+		}
+
+		block.add_statement (new CCodeReturnStatement (new CCodeConstant ("NULL")));
+
+		source_type_member_definition.append (cfunc);
+	}
+
+	void generate_interface_set_property_function (ObjectTypeSymbol sym) {
+		var cfunc = new CCodeFunction (sym.get_lower_case_cprefix () + "dbus_interface_set_property", "gboolean");
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "GDBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("sender", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("object_path", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("interface_name", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("property_name", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("value", "GVariant*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("error", "GError**"));
+		cfunc.add_parameter (new CCodeFormalParameter ("data", "gpointer*"));
+
+		cfunc.modifiers |= CCodeModifiers.STATIC;
+
+		source_declarations.add_type_member_declaration (cfunc.copy ());
+
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		var cdecl = new CCodeDeclaration ("gpointer");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
+		block.add_statement (cdecl);
+
+		CCodeIfStatement clastif = null;
+
+		foreach (Property prop in sym.get_properties ()) {
+			if (prop.binding != MemberBinding.INSTANCE
+			    || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+			if (!is_dbus_visible (prop)) {
+				continue;
+			}
+			if (prop.set_accessor == null) {
+				continue;
+			}
+
+			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
+			ccheck.add_argument (new CCodeIdentifier ("property_name"));
+			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
+
+			var callblock = new CCodeBlock ();
+
+			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_property_set_wrapper (prop, sym)));
+			ccall.add_argument (new CCodeIdentifier ("object"));
+			ccall.add_argument (new CCodeIdentifier ("value"));
+
+			callblock.add_statement (new CCodeExpressionStatement (ccall));
+			callblock.add_statement (new CCodeReturnStatement (new CCodeConstant ("TRUE")));
+
+			var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")), callblock);
+			if (clastif == null) {
+				block.add_statement (cif);
+			} else {
+				clastif.false_statement = cif;
+			}
+
+			clastif = cif;
+		}
+
+		block.add_statement (new CCodeReturnStatement (new CCodeConstant ("FALSE")));
+
+		source_type_member_definition.append (cfunc);
+	}
+
+	CCodeExpression get_method_info (ObjectTypeSymbol sym) {
+		var infos = new CCodeInitializerList ();
+
+		foreach (Method m in sym.get_methods ()) {
+			if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
+			    || m.overrides || m.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+			if (!is_dbus_visible (m)) {
+				continue;
+			}
+
+			var in_args_info = new CCodeInitializerList ();
+			var out_args_info = new CCodeInitializerList ();
+
+			foreach (FormalParameter param in m.get_parameters ()) {
+				var info = new CCodeInitializerList ();
+				info.append (new CCodeConstant ("-1"));
+				info.append (new CCodeConstant ("\"%s\"".printf (param.name)));
+				info.append (new CCodeConstant ("\"%s\"".printf (get_type_signature (param.parameter_type))));
+
+				var cdecl = new CCodeDeclaration ("const GDBusArgInfo");
+				cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_" + param.name, info));
+				cdecl.modifiers = CCodeModifiers.STATIC;
+				source_declarations.add_constant_declaration (cdecl);
+
+				if (param.direction == ParameterDirection.IN) {
+					in_args_info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_" + param.name)));
+				} else {
+					out_args_info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_" + param.name)));
+				}
+			}
+
+			if (!(m.return_type is VoidType)) {
+				var info = new CCodeInitializerList ();
+				info.append (new CCodeConstant ("-1"));
+				info.append (new CCodeConstant ("\"%s\"".printf (dbus_result_name (m))));
+				info.append (new CCodeConstant ("\"%s\"".printf (get_type_signature (m.return_type))));
+
+				var cdecl = new CCodeDeclaration ("const GDBusArgInfo");
+				cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_result", info));
+				cdecl.modifiers = CCodeModifiers.STATIC;
+				source_declarations.add_constant_declaration (cdecl);
+
+				out_args_info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_result")));
+			}
+
+			in_args_info.append (new CCodeConstant ("NULL"));
+			out_args_info.append (new CCodeConstant ("NULL"));
+
+			var cdecl = new CCodeDeclaration ("const GDBusArgInfo * const");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_in[]", in_args_info));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_constant_declaration (cdecl);
+
+			cdecl = new CCodeDeclaration ("const GDBusArgInfo * const");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_out[]", out_args_info));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_constant_declaration (cdecl);
+
+			var info = new CCodeInitializerList ();
+			info.append (new CCodeConstant ("-1"));
+			info.append (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (m))));
+			info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_in")));
+			info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + m.name + "_out")));
+
+			cdecl = new CCodeDeclaration ("const GDBusMethodInfo");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_method_info_" + m.name, info));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_constant_declaration (cdecl);
+
+			infos.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_method_info_" + m.name)));
+		}
+
+		infos.append (new CCodeConstant ("NULL"));
+
+		var cdecl = new CCodeDeclaration ("const GDBusMethodInfo * const");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_method_info[]", infos));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_constant_declaration (cdecl);
+
+		return new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_method_info");
+	}
+
+	CCodeExpression get_signal_info (ObjectTypeSymbol sym) {
+		var infos = new CCodeInitializerList ();
+
+		foreach (Signal sig in sym.get_signals ()) {
+			if (sig.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+			if (!is_dbus_visible (sig)) {
+				continue;
+			}
+
+			var args_info = new CCodeInitializerList ();
+
+			foreach (FormalParameter param in sig.get_parameters ()) {
+				var info = new CCodeInitializerList ();
+				info.append (new CCodeConstant ("-1"));
+				info.append (new CCodeConstant ("\"%s\"".printf (param.name)));
+				info.append (new CCodeConstant ("\"%s\"".printf (get_type_signature (param.parameter_type))));
+
+				var cdecl = new CCodeDeclaration ("const GDBusArgInfo");
+				cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + sig.get_cname () + "_" + param.name, info));
+				cdecl.modifiers = CCodeModifiers.STATIC;
+				source_declarations.add_constant_declaration (cdecl);
+
+				args_info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + sig.get_cname () + "_" + param.name)));
+			}
+
+			args_info.append (new CCodeConstant ("NULL"));
+
+			var cdecl = new CCodeDeclaration ("const GDBusArgInfo * const");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + sig.get_cname () + "[]", args_info));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_constant_declaration (cdecl);
+
+			var info = new CCodeInitializerList ();
+			info.append (new CCodeConstant ("-1"));
+			info.append (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
+			info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_arg_info_" + sig.get_cname ())));
+
+			cdecl = new CCodeDeclaration ("const GDBusSignalInfo");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_signal_info_" + sig.get_cname (), info));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_constant_declaration (cdecl);
+
+			infos.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_signal_info_" + sig.get_cname ())));
+		}
+
+		infos.append (new CCodeConstant ("NULL"));
+
+		var cdecl = new CCodeDeclaration ("const GDBusSignalInfo * const");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_signal_info[]", infos));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_constant_declaration (cdecl);
+
+		return new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_signal_info");
+	}
+
+	CCodeExpression get_property_info (ObjectTypeSymbol sym) {
+		var infos = new CCodeInitializerList ();
+
+		foreach (Property prop in sym.get_properties ()) {
+			if (prop.binding != MemberBinding.INSTANCE
+			    || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+			if (!is_dbus_visible (prop)) {
+				continue;
+			}
+
+			var info = new CCodeInitializerList ();
+			info.append (new CCodeConstant ("-1"));
+			info.append (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
+			info.append (new CCodeConstant ("\"%s\"".printf (get_type_signature (prop.property_type))));
+			if (prop.get_accessor != null && prop.set_accessor != null) {
+				info.append (new CCodeConstant ("G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE"));
+			} else if (prop.get_accessor != null) {
+				info.append (new CCodeConstant ("G_DBUS_PROPERTY_INFO_FLAGS_READABLE"));
+			} else if (prop.set_accessor != null) {
+				info.append (new CCodeConstant ("G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE"));
+			} else {
+				info.append (new CCodeConstant ("G_DBUS_PROPERTY_INFO_FLAGS_NONE"));
+			}
+
+			var cdecl = new CCodeDeclaration ("const GDBusPropertyInfo");
+			cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_property_info_" + prop.name, info));
+			cdecl.modifiers = CCodeModifiers.STATIC;
+			source_declarations.add_constant_declaration (cdecl);
+
+			infos.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_property_info_" + prop.name)));
+		}
+
+		infos.append (new CCodeConstant ("NULL"));
+
+		var cdecl = new CCodeDeclaration ("const GDBusPropertyInfo * const");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_property_info[]", infos));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_constant_declaration (cdecl);
+
+		return new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_property_info");
+	}
+
+	CCodeExpression get_interface_info (ObjectTypeSymbol sym) {
+		var info = new CCodeInitializerList ();
+		info.append (new CCodeConstant ("-1"));
+		info.append (new CCodeConstant ("\"%s\"".printf (get_dbus_name (sym))));
+		info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_method_info (sym)));
+		info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_signal_info (sym)));
+		info.append (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_property_info (sym)));
+
+		var cdecl = new CCodeDeclaration ("const GDBusInterfaceInfo");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_interface_info", info));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_constant_declaration (cdecl);
+
+		return new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_interface_info");
+	}
+
+	CCodeExpression get_interface_vtable (ObjectTypeSymbol sym) {
+		var vtable = new CCodeInitializerList ();
+		vtable.append (new CCodeIdentifier (sym.get_lower_case_cprefix () + "dbus_interface_method_call"));
+		vtable.append (new CCodeIdentifier (sym.get_lower_case_cprefix () + "dbus_interface_get_property"));
+		vtable.append (new CCodeIdentifier (sym.get_lower_case_cprefix () + "dbus_interface_set_property"));
+
+		generate_interface_method_call_function (sym);
+		generate_interface_get_property_function (sym);
+		generate_interface_set_property_function (sym);
+
+		var cdecl = new CCodeDeclaration ("const GDBusInterfaceVTable");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_interface_vtable", vtable));
+		cdecl.modifiers = CCodeModifiers.STATIC;
+		source_declarations.add_constant_declaration (cdecl);
+
+		return new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_interface_vtable");
+	}
+
+	public override void visit_method_call (MethodCall expr) {
+		var mtype = expr.call.value_type as MethodType;
+		if (mtype == null || mtype.method_symbol.get_cname () != "g_dbus_connection_register_object") {
+			base.visit_method_call (expr);
+			return;
+		}
+
+		expr.accept_children (codegen);
+
+		var ma = (MemberAccess) expr.call;
+		var type_arg = (ObjectType) ma.get_type_arguments ().get (0);
+
+		var args = expr.get_argument_list ();
+		var path_arg = args[0];
+		var obj_arg = args[1];
+
+		// method can fail
+		current_method_inner_error = true;
+
+		var cregister = new CCodeFunctionCall (new CCodeIdentifier ("%sregister_object".printf (type_arg.type_symbol.get_lower_case_cprefix ())));
+		cregister.add_argument ((CCodeExpression) obj_arg.ccodenode);
+		cregister.add_argument ((CCodeExpression) ma.inner.ccodenode);
+		cregister.add_argument ((CCodeExpression) path_arg.ccodenode);
+		cregister.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
+		expr.ccodenode = cregister;
+	}
+
+	public override void generate_class_declaration (Class cl, CCodeDeclarationSpace decl_space) {
+		base.generate_class_declaration (cl, decl_space);
+
+		generate_object_type_symbol_declaration (cl, decl_space);
+	}
+
+	public override void generate_interface_declaration (Interface iface, CCodeDeclarationSpace decl_space) {
+		base.generate_interface_declaration (iface, decl_space);
+
+		generate_object_type_symbol_declaration (iface, decl_space);
+	}
+
+	public override void visit_class (Class cl) {
+		base.visit_class (cl);
+
+		visit_object_type_symbol (cl);
+	}
+
+	public override void visit_interface (Interface iface) {
+		base.visit_interface (iface);
+
+		visit_object_type_symbol (iface);
+	}
+
+	void generate_object_type_symbol_declaration (ObjectTypeSymbol sym, CCodeDeclarationSpace decl_space) {
+		string dbus_iface_name = get_dbus_name (sym);
+		if (dbus_iface_name == null) {
+			return;
+		}
+
+		string register_object_name = "%sregister_object".printf (sym.get_lower_case_cprefix ());
+
+		if (decl_space.add_symbol_declaration (sym, register_object_name)) {
+			return;
+		}
+
+		// declare register_object function
+		var cfunc = new CCodeFunction (register_object_name, "guint");
+		cfunc.add_parameter (new CCodeFormalParameter ("object", "void*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "GDBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("path", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("error", "GError**"));
+		if (sym.is_private_symbol ()) {
+			cfunc.modifiers |= CCodeModifiers.STATIC;
+		}
+		decl_space.add_type_member_declaration (cfunc);
+	}
+
+	void visit_object_type_symbol (ObjectTypeSymbol sym) {
+		// only support registering a single D-Bus interface at a time (unlike old D-Bus support)
+		// however, register_object can be invoked multiple times for the same object path with different interfaces
+		string dbus_iface_name = get_dbus_name (sym);
+		if (dbus_iface_name == null) {
+			return;
+		}
+
+		var cfunc = new CCodeFunction (sym.get_lower_case_cprefix () + "register_object", "guint");
+		cfunc.add_parameter (new CCodeFormalParameter ("object", "gpointer"));
+		cfunc.add_parameter (new CCodeFormalParameter ("connection", "GDBusConnection*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("path", "const gchar*"));
+		cfunc.add_parameter (new CCodeFormalParameter ("error", "GError**"));
+		if (sym.is_private_symbol ()) {
+			cfunc.modifiers |= CCodeModifiers.STATIC;
+		}
+
+		var block = new CCodeBlock ();
+		cfunc.block = block;
+
+		var cdecl = new CCodeDeclaration ("guint");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+		block.add_statement (cdecl);
+
+
+		// data consists of 3 pointers: object, connection, path
+		cdecl = new CCodeDeclaration ("gpointer");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("*data"));
+		block.add_statement (cdecl);
+
+		var alloc_data = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
+		alloc_data.add_argument (new CCodeIdentifier ("gpointer"));
+		alloc_data.add_argument (new CCodeConstant ("3"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data"), alloc_data)));
+
+		var ref_object = new CCodeFunctionCall (new CCodeIdentifier (sym.get_ref_function ()));
+		ref_object.add_argument (new CCodeIdentifier ("object"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0")), ref_object)));
+
+		ref_object = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
+		ref_object.add_argument (new CCodeIdentifier ("connection"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("1")), ref_object)));
+
+		var dup_path = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup"));
+		dup_path.add_argument (new CCodeIdentifier ("path"));
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("2")), dup_path)));
+
+
+		var cregister = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_register_object"));
+		cregister.add_argument (new CCodeIdentifier ("connection"));
+		cregister.add_argument (new CCodeIdentifier ("path"));
+
+		cregister.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_interface_info (sym)));
+		cregister.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_interface_vtable (sym)));
+
+		cregister.add_argument (new CCodeIdentifier ("data"));
+		cregister.add_argument (new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "unregister_object"));
+		cregister.add_argument (new CCodeIdentifier ("error"));
+
+		block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), cregister)));
+
+		var error_block = new CCodeBlock ();
+		error_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("0")));
+		block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("result")), error_block));
+
+		handle_signals (sym, block);
+
+		block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+
+		source_type_member_definition.append (cfunc);
+
+
+		cfunc = new CCodeFunction ("_" + sym.get_lower_case_cprefix () + "unregister_object");
+		cfunc.add_parameter (new CCodeFormalParameter ("data", "gpointer*"));
+		cfunc.modifiers |= CCodeModifiers.STATIC;
+		source_declarations.add_type_member_declaration (cfunc.copy ());
+
+		block = new CCodeBlock ();
+		cfunc.block = block;
+
+		var unref_object = new CCodeFunctionCall (new CCodeIdentifier (sym.get_unref_function ()));
+		unref_object.add_argument (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0")));
+		block.add_statement (new CCodeExpressionStatement (unref_object));
+
+		unref_object = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
+		unref_object.add_argument (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("1")));
+		block.add_statement (new CCodeExpressionStatement (unref_object));
+
+		var free_path = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
+		free_path.add_argument (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("2")));
+		block.add_statement (new CCodeExpressionStatement (free_path));
+
+		var free_data = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
+		free_data.add_argument (new CCodeIdentifier ("data"));
+		block.add_statement (new CCodeExpressionStatement (free_data));
+
+		source_type_member_definition.append (cfunc);
+	}
+}
diff --git a/codegen/valagvariantmodule.vala b/codegen/valagvariantmodule.vala
new file mode 100644
index 0000000..0f3861e
--- /dev/null
+++ b/codegen/valagvariantmodule.vala
@@ -0,0 +1,788 @@
+/* valagvariantmodule.vala
+ *
+ * Copyright (C) 2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Jürg Billeter <j bitron ch>
+ */
+
+public class Vala.GVariantModule : GAsyncModule {
+	struct BasicTypeInfo {
+		public unowned string signature;
+		public unowned string type_name;
+		public bool is_string;
+	}
+
+	const BasicTypeInfo[] basic_types = {
+		{ "y", "byte", false },
+		{ "b", "boolean", false },
+		{ "n", "int16", false },
+		{ "q", "uint16", false },
+		{ "i", "int32", false },
+		{ "u", "uint32", false },
+		{ "x", "int64", false },
+		{ "t", "uint64", false },
+		{ "d", "double", false },
+		{ "s", "string", true },
+		{ "o", "object_path", true },
+		{ "g", "signature", true }
+	};
+
+	public GVariantModule (CCodeGenerator codegen, CCodeModule? next) {
+		base (codegen, next);
+	}
+
+	static bool is_string_marshalled_enum (TypeSymbol? symbol) {
+		if (symbol != null && symbol is Enum) {
+			var dbus = symbol.get_attribute ("DBus");
+			return dbus != null && dbus.get_bool ("use_string_marshalling");
+		}
+		return false;
+	}
+
+	string get_dbus_value (EnumValue value, string default_value) {
+			var dbus = value.get_attribute ("DBus");
+			if (dbus == null) {
+				return default_value;
+			}
+
+			string dbus_value = dbus.get_string ("value");
+			if (dbus_value == null) {
+				return default_value;
+			}
+			return dbus_value;
+	}
+
+	bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
+		foreach (BasicTypeInfo info in basic_types) {
+			if (info.signature == signature) {
+				basic_type = info;
+				return true;
+			}
+		}
+		return false;
+	}
+
+	public static string? get_type_signature (DataType datatype) {
+		var array_type = datatype as ArrayType;
+
+		if (array_type != null) {
+			string element_type_signature = get_type_signature (array_type.element_type);
+
+			if (element_type_signature == null) {
+				return null;
+			}
+
+			return string.nfill (array_type.rank, 'a') + element_type_signature;
+		} else if (is_string_marshalled_enum (datatype.data_type)) {
+			return "s";
+		} else if (datatype.data_type != null) {
+			string sig = null;
+
+			var ccode = datatype.data_type.get_attribute ("CCode");
+			if (ccode != null) {
+				sig = ccode.get_string ("type_signature");
+			}
+
+			var st = datatype.data_type as Struct;
+			var en = datatype.data_type as Enum;
+			if (sig == null && st != null) {
+				var str = new StringBuilder ();
+				str.append_c ('(');
+				foreach (Field f in st.get_fields ()) {
+					if (f.binding == MemberBinding.INSTANCE) {
+						str.append (get_type_signature (f.field_type));
+					}
+				}
+				str.append_c (')');
+				sig = str.str;
+			} else if (sig == null && en != null) {
+				if (en.is_flags) {
+					return "u";
+				} else {
+					return "i";
+				}
+			}
+
+			var type_args = datatype.get_type_arguments ();
+			if (sig != null && sig.str ("%s") != null && type_args.size > 0) {
+				string element_sig = "";
+				foreach (DataType type_arg in type_args) {
+					var s = get_type_signature (type_arg);
+					if (s != null) {
+						element_sig += s;
+					}
+				}
+
+				sig = sig.printf (element_sig);
+			}
+
+			return sig;
+		} else {
+			return null;
+		}
+	}
+
+	public override void visit_enum (Enum en) {
+		base.visit_enum (en);
+
+		if (is_string_marshalled_enum (en)) {
+			// strcmp
+			source_declarations.add_include ("string.h");
+
+			source_type_member_definition.append (generate_enum_from_string_function (en));
+			source_type_member_definition.append (generate_enum_to_string_function (en));
+		}
+	}
+
+	public override bool generate_enum_declaration (Enum en, CCodeDeclarationSpace decl_space) {
+		if (base.generate_enum_declaration (en, decl_space)) {
+			if (is_string_marshalled_enum (en)) {
+				decl_space.add_type_member_declaration (generate_enum_from_string_function_declaration (en));
+				decl_space.add_type_member_declaration (generate_enum_to_string_function_declaration (en));
+			}
+			return true;
+		}
+		return false;
+	}
+
+	CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
+		var id = expr as CCodeIdentifier;
+		var ma = expr as CCodeMemberAccess;
+		if (id != null) {
+			return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
+		} else if (ma != null) {
+			if (ma.is_pointer) {
+				return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
+			} else {
+				return new CCodeMemberAccess (ma.inner, "%s_length%d".printf (ma.member_name, dim));
+			}
+		} else {
+			// must be NULL-terminated
+			var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
+			len_call.add_argument (expr);
+			return len_call;
+		}
+	}
+
+	CCodeExpression? generate_enum_value_from_string (CCodeFragment fragment, EnumValueType type, CCodeExpression? expr) {
+		var en = type.type_symbol as Enum;
+		var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
+
+		var from_string_call = new CCodeFunctionCall (new CCodeIdentifier (from_string_name));
+		from_string_call.add_argument (expr);
+
+		return from_string_call;
+	}
+
+	public CCodeFunction generate_enum_from_string_function_declaration (Enum en) {
+		var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
+
+		var from_string_func = new CCodeFunction (from_string_name, en.get_cname ());
+		from_string_func.add_parameter (new CCodeFormalParameter ("str", "const char*"));
+
+		return from_string_func;
+	}
+
+	public CCodeFunction generate_enum_from_string_function (Enum en) {
+		var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
+
+		var from_string_func = new CCodeFunction (from_string_name, en.get_cname ());
+		from_string_func.add_parameter (new CCodeFormalParameter ("str", "const char*"));
+
+		var from_string_block = new CCodeBlock ();
+		from_string_func.block = from_string_block;
+
+		var cdecl = new CCodeDeclaration (en.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator ("value"));
+		from_string_block.add_statement (cdecl);
+
+		CCodeStatement if_else_if = null;
+		CCodeIfStatement last_statement = null;
+		foreach (EnumValue enum_value in en.get_values ()) {
+			var true_block = new CCodeBlock ();
+			true_block.suppress_newline = true;
+			true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("value"), new CCodeIdentifier (enum_value.get_cname ()))));
+
+			string dbus_value = get_dbus_value (enum_value, enum_value.name);
+			var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
+			string_comparison.add_argument (new CCodeIdentifier ("str"));
+			string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_value)));
+			var stmt = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0")), true_block);
+
+			if (last_statement != null) {
+				last_statement.false_statement = stmt;
+			} else {
+				if_else_if = stmt;
+			}
+			last_statement = stmt;
+		}
+
+		from_string_block.add_statement (if_else_if);
+
+		from_string_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
+
+		return from_string_func;
+	}
+
+	CCodeExpression deserialize_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression variant_expr, bool transfer = false) {
+		var get_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_" + basic_type.type_name));
+		get_call.add_argument (variant_expr);
+
+		if (basic_type.is_string) {
+			if (transfer) {
+				get_call.call = new CCodeIdentifier ("g_variant_get_string");
+			} else {
+				get_call.call = new CCodeIdentifier ("g_variant_dup_string");
+			}
+			get_call.add_argument (new CCodeConstant ("NULL"));
+		}
+
+		return get_call;
+	}
+
+	CCodeExpression deserialize_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression variant_expr, CCodeExpression? expr) {
+		string temp_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
+		new_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+		// add one extra element for NULL-termination
+		new_call.add_argument (new CCodeConstant ("5"));
+
+		var cdecl = new CCodeDeclaration (array_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name, new_call));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("4")));
+		fragment.append (cdecl);
+
+		deserialize_array_dim (fragment, array_type, 1, temp_name, variant_expr, expr);
+
+		if (array_type.element_type.is_reference_type_or_type_parameter ()) {
+			// NULL terminate array
+			var length = new CCodeIdentifier (temp_name + "_length");
+			var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), length);
+			fragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, new CCodeIdentifier ("NULL"))));
+		}
+
+		return new CCodeIdentifier (temp_name);
+	}
+
+	void deserialize_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, string temp_name, CCodeExpression variant_expr, CCodeExpression? expr) {
+		string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
+		string element_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariantIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariant*");
+		cdecl.add_declarator (new CCodeVariableDeclarator (element_name));
+		fragment.append (cdecl);
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
+		iter_call.add_argument (variant_expr);
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
+
+		var cforblock = new CCodeBlock ();
+		var cforfragment = new CCodeFragment ();
+		cforblock.add_statement (cforfragment);
+		var cfor = new CCodeForStatement (new CCodeAssignment (new CCodeIdentifier (element_name), iter_call), cforblock);
+		cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim))));
+
+		if (dim < array_type.rank) {
+			deserialize_array_dim (cforfragment, array_type, dim + 1, temp_name, new CCodeIdentifier (element_name), expr);
+		} else {
+			var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
+			var renew_block = new CCodeBlock ();
+
+			// tmp_size = (2 * tmp_size);
+			var new_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size"));
+			renew_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name + "_size"), new_size)));
+
+			var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
+			renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+			renew_call.add_argument (new CCodeIdentifier (temp_name));
+			// add one extra element for NULL-termination
+			renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("1")));
+			var renew_stmt = new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), renew_call));
+			renew_block.add_statement (renew_stmt);
+
+			var cif = new CCodeIfStatement (size_check, renew_block);
+			cforfragment.append (cif);
+
+			var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
+			var element_expr = deserialize_expression (cforfragment, array_type.element_type, new CCodeIdentifier (element_name), null);
+			cforfragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, element_expr)));
+		}
+
+		var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+		unref.add_argument (new CCodeIdentifier (element_name));
+		cforfragment.append (new CCodeExpressionStatement (unref));
+
+		fragment.append (cfor);
+
+		if (expr != null) {
+			fragment.append (new CCodeExpressionStatement (new CCodeAssignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)))));
+		}
+	}
+
+	CCodeExpression? deserialize_struct (CCodeFragment fragment, Struct st, CCodeExpression variant_expr) {
+		string temp_name = "_tmp%d_".printf (next_temp_var_id++);
+		string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var cdecl = new CCodeDeclaration (st.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariantIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
+		fragment.append (cdecl);
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
+		iter_call.add_argument (variant_expr);
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		bool field_found = false;;
+
+		foreach (Field f in st.get_fields ()) {
+			if (f.binding != MemberBinding.INSTANCE) {
+				continue;
+			}
+
+			field_found = true;
+
+			read_expression (fragment, f.field_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()));
+		}
+
+		if (!field_found) {
+			return null;
+		}
+
+		return new CCodeIdentifier (temp_name);
+	}
+
+	CCodeExpression deserialize_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression variant_expr) {
+		string temp_name = "_tmp%d_".printf (next_temp_var_id++);
+		string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
+		string key_name = "_tmp%d_".printf (next_temp_var_id++);
+		string value_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var type_args = type.get_type_arguments ();
+		assert (type_args.size == 2);
+		var key_type = type_args.get (0);
+		var value_type = type_args.get (1);
+
+		var cdecl = new CCodeDeclaration ("GHashTable*");
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariantIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariant*");
+		cdecl.add_declarator (new CCodeVariableDeclarator (key_name));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("GVariant*");
+		cdecl.add_declarator (new CCodeVariableDeclarator (value_name));
+		fragment.append (cdecl);
+
+		var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
+		if (key_type.data_type == string_type.data_type) {
+			hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
+			hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
+		} else {
+			hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
+			hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
+		}
+		if (key_type.data_type == string_type.data_type) {
+			hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
+		} else {
+			hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
+		}
+		if (value_type.data_type == string_type.data_type) {
+			hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
+		} else {
+			hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
+		}
+		fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), hash_table_new)));
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
+		iter_call.add_argument (variant_expr);
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_loop"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
+		iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
+
+		var cwhileblock = new CCodeBlock ();
+		var cwhilefragment = new CCodeFragment ();
+		cwhileblock.add_statement (cwhilefragment);
+		var cwhile = new CCodeWhileStatement (iter_call, cwhileblock);
+
+		var key_expr = deserialize_expression (cwhilefragment, key_type, new CCodeIdentifier (key_name), null);
+		var value_expr = deserialize_expression (cwhilefragment, value_type, new CCodeIdentifier (value_name), null);
+
+		var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
+		hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
+		hash_table_insert.add_argument (convert_to_generic_pointer (key_expr, key_type));
+		hash_table_insert.add_argument (convert_to_generic_pointer (value_expr, value_type));
+		cwhilefragment.append (new CCodeExpressionStatement (hash_table_insert));
+
+		fragment.append (cwhile);
+
+		return new CCodeIdentifier (temp_name);
+	}
+
+	public override CCodeExpression? deserialize_expression (CCodeFragment fragment, DataType type, CCodeExpression variant_expr, CCodeExpression? expr) {
+		BasicTypeInfo basic_type;
+		CCodeExpression result = null;
+		if (is_string_marshalled_enum (type.data_type)) {
+			get_basic_type_info ("s", out basic_type);
+			result = deserialize_basic (fragment, basic_type, variant_expr, true);
+			result = generate_enum_value_from_string (fragment, type as EnumValueType, result);
+		} else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
+			result = deserialize_basic (fragment, basic_type, variant_expr);
+		} else if (type is ArrayType) {
+			result = deserialize_array (fragment, (ArrayType) type, variant_expr, expr);
+		} else if (type.data_type is Struct) {
+			var st = (Struct) type.data_type;
+			result = deserialize_struct (fragment, st, variant_expr);
+			if (result != null && type.nullable) {
+				var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+				csizeof.add_argument (new CCodeIdentifier (st.get_cname ()));
+				var cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
+				cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
+				cdup.add_argument (csizeof);
+				result = cdup;
+			}
+		} else if (type is ObjectType) {
+			if (type.data_type.get_full_name () == "GLib.Variant") {
+				var variant_get = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_variant"));
+				variant_get.add_argument (variant_expr);
+				result = variant_get;
+			} else if (type.data_type.get_full_name () == "GLib.HashTable") {
+				result = deserialize_hash_table (fragment, (ObjectType) type, variant_expr);
+			}
+		}
+
+		if (result == null) {
+			Report.error (type.source_reference, "GVariant deserialization of type `%s' is not supported".printf (type.to_string ()));
+		}
+
+		return result;
+	}
+
+	public void read_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression target_expr) {
+		string temp_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var cdecl = new CCodeDeclaration ("GVariant*");
+		cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
+		fragment.append (cdecl);
+
+		var variant_expr = new CCodeIdentifier (temp_name);
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next_value"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
+		fragment.append (new CCodeExpressionStatement (new CCodeAssignment (variant_expr, iter_call)));
+
+		var result = deserialize_expression (fragment, type, variant_expr, target_expr);
+		fragment.append (new CCodeExpressionStatement (new CCodeAssignment (target_expr, result)));
+
+		var unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+		unref.add_argument (variant_expr);
+		fragment.append (new CCodeExpressionStatement (unref));
+	}
+
+	CCodeExpression? generate_enum_value_to_string (CCodeFragment fragment, EnumValueType type, CCodeExpression? expr) {
+		var en = type.type_symbol as Enum;
+		var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
+
+		var to_string_call = new CCodeFunctionCall (new CCodeIdentifier (to_string_name));
+		to_string_call.add_argument (expr);
+
+		return to_string_call;
+	}
+
+	public CCodeFunction generate_enum_to_string_function_declaration (Enum en) {
+		var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
+
+		var to_string_func = new CCodeFunction (to_string_name, "const char*");
+		to_string_func.add_parameter (new CCodeFormalParameter ("value", en.get_cname ()));
+
+		return to_string_func;
+	}
+
+	public CCodeFunction generate_enum_to_string_function (Enum en) {
+		var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
+
+		var to_string_func = new CCodeFunction (to_string_name, "const char*");
+		to_string_func.add_parameter (new CCodeFormalParameter ("value", en.get_cname ()));
+
+		var to_string_block = new CCodeBlock ();
+		to_string_func.block = to_string_block;
+
+		var cdecl = new CCodeDeclaration ("const char *");
+		cdecl.add_declarator (new CCodeVariableDeclarator ("str"));
+		to_string_block.add_statement (cdecl);
+
+		var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("value"));
+		foreach (EnumValue enum_value in en.get_values ()) {
+			string dbus_value = get_dbus_value (enum_value, enum_value.name);
+			cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value.get_cname ())));
+			cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("str"), new CCodeConstant ("\"%s\"".printf (dbus_value)))));
+			cswitch.add_statement (new CCodeBreakStatement ());
+		}
+		to_string_block.add_statement (cswitch);
+
+		to_string_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("str")));
+
+		return to_string_func;
+	}
+
+	CCodeExpression? serialize_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression expr) {
+		var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_" + basic_type.type_name));
+		new_call.add_argument (expr);
+		return new_call;
+	}
+
+	CCodeExpression? serialize_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression array_expr) {
+		string array_iter_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var cdecl = new CCodeDeclaration (array_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator (array_iter_name));
+		fragment.append (cdecl);
+
+		fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (array_iter_name), array_expr)));
+
+		return serialize_array_dim (fragment, array_type, 1, array_expr, new CCodeIdentifier (array_iter_name));
+	}
+
+	CCodeExpression? serialize_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
+		string builder_name = "_tmp%d_".printf (next_temp_var_id++);
+		string index_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var cdecl = new CCodeDeclaration ("GVariantBuilder");
+		cdecl.add_declarator (new CCodeVariableDeclarator (builder_name));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("int");
+		cdecl.add_declarator (new CCodeVariableDeclarator (index_name));
+		fragment.append (cdecl);
+
+		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
+		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
+		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_ARRAY"));
+		fragment.append (new CCodeExpressionStatement (builder_init));
+
+		var cforblock = new CCodeBlock ();
+		var cforfragment = new CCodeFragment ();
+		cforblock.add_statement (cforfragment);
+		var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim)), cforblock);
+		cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0")));
+		cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name)));
+
+		CCodeExpression element_variant;
+		if (dim < array_type.rank) {
+			element_variant = serialize_array_dim (cforfragment, array_type, dim + 1, array_expr, array_iter_expr);
+		} else {
+			var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
+			element_variant = serialize_expression (cforfragment, array_type.element_type, element_expr);
+		}
+
+		var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
+		builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
+		builder_add.add_argument (element_variant);
+		cforfragment.append (new CCodeExpressionStatement (builder_add));
+
+		if (dim == array_type.rank) {
+			var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
+			cforfragment.append (new CCodeExpressionStatement (array_iter_incr));
+		}
+
+		fragment.append (cfor);
+
+		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
+		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
+		return builder_end;
+	}
+
+	CCodeExpression? serialize_struct (CCodeFragment fragment, Struct st, CCodeExpression struct_expr) {
+		string builder_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var cdecl = new CCodeDeclaration ("GVariantBuilder");
+		cdecl.add_declarator (new CCodeVariableDeclarator (builder_name));
+		fragment.append (cdecl);
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
+		iter_call.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		bool field_found = false;;
+
+		foreach (Field f in st.get_fields ()) {
+			if (f.binding != MemberBinding.INSTANCE) {
+				continue;
+			}
+
+			field_found = true;
+
+			write_expression (fragment, f.field_type, new CCodeIdentifier (builder_name), new CCodeMemberAccess (struct_expr, f.get_cname ()));
+		}
+
+		if (!field_found) {
+			return null;
+		}
+
+		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
+		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (builder_name)));
+		return builder_end;
+	}
+
+	CCodeExpression serialize_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression hash_table_expr) {
+		string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
+		string tableiter_name = "_tmp%d_".printf (next_temp_var_id++);
+		string key_name = "_tmp%d_".printf (next_temp_var_id++);
+		string value_name = "_tmp%d_".printf (next_temp_var_id++);
+
+		var type_args = type.get_type_arguments ();
+		assert (type_args.size == 2);
+		var key_type = type_args.get (0);
+		var value_type = type_args.get (1);
+
+		var cdecl = new CCodeDeclaration ("GVariantBuilder");
+		cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("GHashTableIter");
+		cdecl.add_declarator (new CCodeVariableDeclarator (tableiter_name));
+		fragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration ("gpointer");
+		cdecl.add_declarator (new CCodeVariableDeclarator (key_name));
+		cdecl.add_declarator (new CCodeVariableDeclarator (value_name));
+		fragment.append (cdecl);
+
+		var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
+		iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
+		iter_init_call.add_argument (hash_table_expr);
+		fragment.append (new CCodeExpressionStatement (iter_init_call));
+
+		var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
+		iter_call.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_DICTIONARY"));
+		fragment.append (new CCodeExpressionStatement (iter_call));
+
+		var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
+		iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
+		iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
+		iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
+
+		var cwhileblock = new CCodeBlock ();
+		var cwhilefragment = new CCodeFragment ();
+		cwhileblock.add_statement (cwhilefragment);
+		var cwhile = new CCodeWhileStatement (iter_next_call, cwhileblock);
+
+		cdecl = new CCodeDeclaration (key_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
+		cwhilefragment.append (cdecl);
+
+		cdecl = new CCodeDeclaration (value_type.get_cname ());
+		cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
+		cwhilefragment.append (cdecl);
+
+		cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type))));
+		cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type))));
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
+		iter_call.add_argument (new CCodeConstant ("\"{?*}\""));
+		iter_call.add_argument (serialize_expression (cwhilefragment, key_type, new CCodeIdentifier ("_key")));
+		iter_call.add_argument (serialize_expression (cwhilefragment, value_type, new CCodeIdentifier ("_value")));
+		cwhilefragment.append (new CCodeExpressionStatement (iter_call));
+
+		fragment.append (cwhile);
+
+		iter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
+		iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
+		return iter_call;
+	}
+
+	public override CCodeExpression? serialize_expression (CCodeFragment fragment, DataType type, CCodeExpression expr) {
+		BasicTypeInfo basic_type;
+		CCodeExpression result = null;
+		if (is_string_marshalled_enum (type.data_type)) {
+			get_basic_type_info ("s", out basic_type);
+			result = generate_enum_value_to_string (fragment, type as EnumValueType, expr);
+			result = serialize_basic (fragment, basic_type, result);
+		} else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
+			result = serialize_basic (fragment, basic_type, expr);
+		} else if (type is ArrayType) {
+			result = serialize_array (fragment, (ArrayType) type, expr);
+		} else if (type.data_type is Struct) {
+			var st_expr = expr;
+			if (type.nullable) {
+				st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
+			}
+			result = serialize_struct (fragment, (Struct) type.data_type, st_expr);
+		} else if (type is ObjectType) {
+			if (type.data_type.get_full_name () == "GLib.Variant") {
+				var variant_new = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new_variant"));
+				variant_new.add_argument (expr);
+				result = variant_new;
+			} else if (type.data_type.get_full_name () == "GLib.HashTable") {
+				result = serialize_hash_table (fragment, (ObjectType) type, expr);
+			}
+		}
+
+		if (result == null) {
+			Report.error (type.source_reference, "GVariant serialization of type `%s' is not supported".printf (type.to_string ()));
+		}
+
+		return result;
+	}
+
+	public void write_expression (CCodeFragment fragment, DataType type, CCodeExpression builder_expr, CCodeExpression expr) {
+		var variant_expr = serialize_expression (fragment, type, expr);
+		if (variant_expr != null) {
+			var builder_add = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_add_value"));
+			builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, builder_expr));
+			builder_add.add_argument (variant_expr);
+			fragment.append (new CCodeExpressionStatement (builder_add));
+		}
+	}
+}
diff --git a/vala/valaarraytype.vala b/vala/valaarraytype.vala
index be626f5..c1d9e0e 100644
--- a/vala/valaarraytype.vala
+++ b/vala/valaarraytype.vala
@@ -186,6 +186,11 @@ public class Vala.ArrayType : ReferenceType {
 			return true;
 		}
 
+		if (target_type.get_type_id () == "G_TYPE_VARIANT") {
+			// allow implicit conversion to GVariant
+			return true;
+		}
+
 		if (target_type is PointerType || (target_type.data_type != null && target_type.data_type.get_attribute ("PointerType") != null)) {
 			/* any array type can be cast to a generic pointer */
 			return true;
diff --git a/vala/valadatatype.vala b/vala/valadatatype.vala
index 2027bb9..f756415 100644
--- a/vala/valadatatype.vala
+++ b/vala/valadatatype.vala
@@ -1,6 +1,6 @@
 /* valadatatype.vala
  *
- * Copyright (C) 2006-2009  Jürg Billeter
+ * Copyright (C) 2006-2010  Jürg Billeter
  * Copyright (C) 2006-2008  Raffaele Sandrini
  *
  * This library is free software; you can redistribute it and/or
@@ -314,6 +314,11 @@ public abstract class Vala.DataType : CodeNode {
 			return true;
 		}
 
+		if (target_type.get_type_id () == "G_TYPE_VARIANT") {
+			// allow implicit conversion to GVariant
+			return true;
+		}
+
 		if (target_type is DelegateType && this is DelegateType) {
 			return ((DelegateType) target_type).delegate_symbol == ((DelegateType) this).delegate_symbol;
 		}
diff --git a/vapi/gio-2.0.vapi b/vapi/gio-2.0.vapi
index 5b744a8..e038979 100644
--- a/vapi/gio-2.0.vapi
+++ b/vapi/gio-2.0.vapi
@@ -7,6 +7,8 @@ namespace GLib {
 		[CCode (cheader_filename = "gio/gio.h")]
 		public static async GLib.DBusConnection @get (GLib.BusType bus_type, GLib.Cancellable? cancellable = null) throws GLib.IOError;
 		[CCode (cheader_filename = "gio/gio.h")]
+		public static T get_proxy_sync<T> (GLib.BusType bus_type, string name, string object_path, GLib.Cancellable? cancellable = null) throws GLib.IOError;
+		[CCode (cheader_filename = "gio/gio.h")]
 		public static GLib.DBusConnection get_sync (GLib.BusType bus_type, GLib.Cancellable? cancellable = null) throws GLib.IOError;
 		[CCode (cheader_filename = "gio/gio.h")]
 		public static uint own_name (GLib.BusType bus_type, string name, GLib.BusNameOwnerFlags flags, GLib.BusAcquiredCallback bus_acquired_handler, GLib.BusNameAcquiredCallback name_acquired_handler, GLib.BusNameLostCallback name_lost_handler);
@@ -206,7 +208,7 @@ namespace GLib {
 		public unowned GLib.IOStream get_stream ();
 		public unowned string get_unique_name ();
 		public bool is_closed ();
-		public uint register_object (string object_path, GLib.DBusInterfaceInfo introspection_data, GLib.DBusInterfaceVTable vtable, GLib.DestroyNotify user_data_free_func) throws GLib.Error;
+		public uint register_object<T> (string object_path, T object) throws GLib.IOError;
 		public uint register_subtree (string object_path, GLib.DBusSubtreeVTable vtable, GLib.DBusSubtreeFlags flags, GLib.DestroyNotify user_data_free_func) throws GLib.Error;
 		public void remove_filter (uint filter_id);
 		public bool send_message (GLib.DBusMessage message, uint32 out_serial) throws GLib.Error;
diff --git a/vapi/packages/gio-2.0/gio-2.0-custom.vala b/vapi/packages/gio-2.0/gio-2.0-custom.vala
index 02e9294..9cea5a0 100644
--- a/vapi/packages/gio-2.0/gio-2.0-custom.vala
+++ b/vapi/packages/gio-2.0/gio-2.0-custom.vala
@@ -56,6 +56,7 @@ namespace GLib {
 	namespace Bus {
 		public async GLib.DBusConnection get (GLib.BusType bus_type, GLib.Cancellable? cancellable = null) throws GLib.IOError;
 		public GLib.DBusConnection get_sync (GLib.BusType bus_type, GLib.Cancellable? cancellable = null) throws GLib.IOError;
+		public T get_proxy_sync<T> (GLib.BusType bus_type, string name, string object_path, GLib.Cancellable? cancellable = null) throws GLib.IOError;
 		public uint own_name (GLib.BusType bus_type, string name, GLib.BusNameOwnerFlags flags, GLib.BusAcquiredCallback bus_acquired_handler, GLib.BusNameAcquiredCallback name_acquired_handler, GLib.BusNameLostCallback name_lost_handler);
 		public uint own_name_on_connection (GLib.DBusConnection connection, string name, GLib.BusNameOwnerFlags flags, GLib.BusNameAcquiredCallback name_acquired_handler, GLib.BusNameLostCallback name_lost_handler);
 		public uint own_name_on_connection_with_closures (GLib.DBusConnection connection, string name, GLib.BusNameOwnerFlags flags, GLib.Closure name_acquired_closure, GLib.Closure name_lost_closure);
@@ -67,4 +68,9 @@ namespace GLib {
 		public uint watch_name_on_connection_with_closures (GLib.DBusConnection connection, string name, GLib.BusNameWatcherFlags flags, GLib.Closure name_appeared_closure, GLib.Closure name_vanished_closure);
 		public uint watch_name_with_closures (GLib.BusType bus_type, string name, GLib.BusNameWatcherFlags flags, GLib.Closure name_appeared_closure, GLib.Closure name_vanished_closure);
 	}
+
+	[CCode (cname = "GDBusConnection")]
+	public class DBusConnection {
+		public uint register_object<T> (string object_path, T object) throws GLib.IOError;
+	}
 }
diff --git a/vapi/packages/gio-2.0/gio-2.0.metadata b/vapi/packages/gio-2.0/gio-2.0.metadata
index 2333be8..8a0dd55 100644
--- a/vapi/packages/gio-2.0/gio-2.0.metadata
+++ b/vapi/packages/gio-2.0/gio-2.0.metadata
@@ -202,3 +202,4 @@ g_zlib_compressor_new.level default_value="-1"
 uid_t name="uint"
 
 g_bus_* hidden="1"
+g_dbus_connection_register_object hidden="1"



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]