[vala/wip/transform: 32/52] GDBus client transformer



commit 2a764e49159ca826c2a3ff8520452a8923402523
Author: Luca Bruno <lucabru src gnome org>
Date:   Tue Jan 3 17:22:35 2012 +0100

    GDBus client transformer

 codegen/Makefile.am                     |    1 +
 codegen/valagdbusclientmodule.vala      |  870 +------------------------------
 codegen/valagdbusclienttransformer.vala |  346 ++++++++++++
 codegen/valagvariantmodule.vala         |    8 -
 codegen/valagvarianttransformer.vala    |    4 +-
 compiler/valacompiler.vala              |    2 +-
 vala/valacodebuilder.vala               |    2 +-
 vala/valacodetransformer.vala           |   16 +-
 vapi/gio-2.0.vapi                       |    2 +-
 9 files changed, 362 insertions(+), 889 deletions(-)
---
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
index 6933602..5356346 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -31,6 +31,7 @@ libvala_la_VALASOURCES = \
 	valaenumregisterfunction.vala \
 	valagasyncmodule.vala \
 	valagdbusclientmodule.vala \
+	valagdbusclienttransformer.vala \
 	valagdbusmodule.vala \
 	valagdbusservermodule.vala \
 	valagerrormodule.vala \
diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala
index a47b95c..9899130 100644
--- a/codegen/valagdbusclientmodule.vala
+++ b/codegen/valagdbusclientmodule.vala
@@ -22,26 +22,6 @@
  */
 
 public class Vala.GDBusClientModule : GDBusModule {
-	enum CallType {
-		SYNC,
-		ASYNC,
-		FINISH,
-		NO_REPLY
-	}
-
-	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;
 
@@ -55,7 +35,7 @@ public class Vala.GDBusClientModule : GDBusModule {
 		push_function (func);
 
 		if (dynamic_method.dynamic_type.data_type == dbus_proxy_type) {
-			generate_marshalling (method, CallType.SYNC, null, method.name);
+			//generate_marshalling (method, CallType.SYNC, null, method.name);
 		} else {
 			Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ()));
 		}
@@ -66,144 +46,6 @@ public class Vala.GDBusClientModule : GDBusModule {
 		cfile.add_function (func);
 	}
 
-	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 = get_ccode_lower_case_prefix (main_iface) + "proxy";
-
-		var proxy_iface_init = new CCodeFunction (lower_cname + "_" + get_ccode_lower_case_prefix (iface) + "interface_init", "void");
-		proxy_iface_init.add_parameter (new CCodeParameter ("iface", get_ccode_name (iface) + "Iface*"));
-
-		push_function (proxy_iface_init);
-
-		foreach (Method m in iface.get_methods ()) {
-			if (!m.is_abstract) {
-				continue;
-			}
-
-			var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), get_ccode_vfunc_name (m));
-			if (!m.coroutine) {
-				ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (main_iface, iface, m)));
-			} else {
-				ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_async_dbus_proxy_method (main_iface, iface, m)));
-				vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), get_ccode_finish_vfunc_name (m));
-				ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_finish_dbus_proxy_method (main_iface, iface, m)));
-			}
-		}
-
-		foreach (Property prop in iface.get_properties ()) {
-			if (!prop.is_abstract) {
-				continue;
-			}
-
-			if (prop.get_accessor != null) {
-				var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "get_" + prop.name);
-				ccode.add_assignment (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);
-				ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_set (main_iface, iface, prop)));
-			}
-		}
-
-		proxy_iface_init.modifiers = CCodeModifiers.STATIC;
-		pop_function ();
-		cfile.add_function_declaration (proxy_iface_init);
-		cfile.add_function (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 (
-			get_ccode_upper_case_name (iface, "TYPE_"),
-			get_ccode_lower_case_prefix (main_iface),
-			get_ccode_lower_case_prefix (iface));
-		return result;
-	}
-
-	public override void generate_interface_declaration (Interface iface, CCodeFile 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 (get_ccode_lower_case_prefix (iface));
-
-		if (add_symbol_declaration (decl_space, 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 (get_ccode_type_id (iface)), macro));
-
-		// declare proxy_get_type function
-		var proxy_get_type = new CCodeFunction (get_type_name, "GType");
-		proxy_get_type.attributes = "G_GNUC_CONST";
-		decl_space.add_function_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;
-		}
-
-		cfile.add_include ("gio/gio.h");
-
-		// create proxy class
-		string cname = get_ccode_name (iface) + "Proxy";
-		string lower_cname = get_ccode_lower_case_prefix (iface) + "proxy";
-
-		cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxy", new CCodeVariableDeclarator (cname)));
-		cfile.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)));
-
-		cfile.add_type_member_definition (define_type);
-
-		var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void");
-		proxy_class_init.add_parameter (new CCodeParameter ("klass", cname + "Class*"));
-		proxy_class_init.modifiers = CCodeModifiers.STATIC;
-		push_function (proxy_class_init);
-		var proxy_class = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY_CLASS"));
-		proxy_class.add_argument (new CCodeIdentifier ("klass"));
-		ccode.add_assignment (new CCodeMemberAccess.pointer (proxy_class, "g_signal"), new CCodeIdentifier (lower_cname + "_g_signal"));
-		pop_function ();
-		cfile.add_function (proxy_class_init);
-
-		generate_signal_handler_function (iface);
-
-		var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void");
-		proxy_instance_init.add_parameter (new CCodeParameter ("self", cname + "*"));
-		proxy_instance_init.modifiers = CCodeModifiers.STATIC;
-		cfile.add_function (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 bus_get_proxy_async = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_bus_get_proxy");
@@ -382,716 +224,6 @@ public class Vala.GDBusClientModule : GDBusModule {
 		set_cvalue (expr, temp_ref);
 	}
 
-	string generate_dbus_signal_handler (Signal sig, ObjectTypeSymbol sym) {
-		string wrapper_name = "_dbus_handle_%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_name (sig));
-
-		var function = new CCodeFunction (wrapper_name);
-		function.modifiers = CCodeModifiers.STATIC;
-		function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*"));
-		function.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
-
-		push_function (function);
-
-		ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_arguments_iter"));
-
-		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"));
-		ccode.add_expression (iter_init);
-
-		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
-		ccall.add_argument (new CCodeIdentifier ("self"));
-		ccall.add_argument (get_signal_canonical_constant (sig));
-
-		foreach (Parameter param in sig.get_parameters ()) {
-			var param_name = get_variable_cname (param.name);
-			var owned_type = param.variable_type.copy ();
-			owned_type.value_owned = true;
-
-			ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero (param_name, default_value_for_type (param.variable_type, true)));
-
-			var st = param.variable_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.variable_type is ArrayType) {
-				var array_type = (ArrayType) param.variable_type;
-
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					string length_cname = get_parameter_array_length_cname (param, dim);
-
-					ccode.add_declaration ("int", new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
-					ccall.add_argument (new CCodeIdentifier (length_cname));
-				}
-			}
-
-			read_expression (param.variable_type, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param_name), param);
-		}
-
-		ccode.add_expression (ccall);
-
-		foreach (Parameter param in sig.get_parameters ()) {
-			var owned_type = param.variable_type.copy ();
-			owned_type.value_owned = true;
-
-			if (requires_destroy (owned_type)) {
-				// keep local alive (symbol_reference is weak)
-				var local = new LocalVariable (owned_type, param.name);
-				ccode.add_expression (destroy_local (local));
-			}
-		}
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (function);
-
-		return wrapper_name;
-	}
-
-	void generate_signal_handler_function (ObjectTypeSymbol sym) {
-		var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "proxy_g_signal", "void");
-		cfunc.add_parameter (new CCodeParameter ("proxy", "GDBusProxy*"));
-		cfunc.add_parameter (new CCodeParameter ("sender_name", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("signal_name", "const gchar*"));
-		cfunc.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
-
-		cfunc.modifiers |= CCodeModifiers.STATIC;
-
-		cfile.add_function_declaration (cfunc);
-
-		push_function (cfunc);
-
-		bool firstif = true;
-
-		foreach (Signal sig in sym.get_signals ()) {
-			if (sig.access != SymbolAccessibility.PUBLIC) {
-				continue;
-			}
-
-			cfile.add_include ("string.h");
-
-			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 cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0"));
-			if (firstif) {
-				ccode.open_if (cond);
-				firstif = false;
-			} else {
-				ccode.else_if (cond);
-			}
-
-			var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_signal_handler (sig, sym)));
-			ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("proxy"), get_ccode_name (sym) + "*"));
-			ccall.add_argument (new CCodeIdentifier ("parameters"));
-
-			ccode.add_expression (ccall);
-		}
-		if (!firstif) {
-			ccode.close ();
-		}
-
-		pop_function ();
-
-		cfile.add_function (cfunc);
-	}
-
-	void generate_marshalling (Method m, CallType call_type, string? iface_name, string? method_name) {
-		var gdbusproxy = new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *");
-
-		var connection = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_connection"));
-		connection.add_argument (gdbusproxy);
-
-		bool uses_fd = dbus_method_uses_file_descriptor (m);
-		if (uses_fd) {
-			cfile.add_include ("gio/gunixfdlist.h");
-		}
-
-		if (call_type != CallType.FINISH) {
-			var destination = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_name"));
-			destination.add_argument (gdbusproxy);
-
-			var interface_name = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_interface_name"));
-			interface_name.add_argument (gdbusproxy);
-
-			var object_path = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_object_path"));
-			object_path.add_argument (gdbusproxy);
-
-			var timeout = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_default_timeout"));
-			timeout.add_argument (gdbusproxy);
-
-			// register errors
-			var error_types = new ArrayList<DataType> ();
-			m.get_error_types (error_types);
-			foreach (var error_type in error_types) {
-				var errtype = (ErrorType) error_type;
-				if (errtype.error_domain != null) {
-					ccode.add_expression (new CCodeIdentifier (get_ccode_upper_case_name (errtype.error_domain)));
-				}
-			}
-
-			// build D-Bus message
-
-			ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_message"));
-
-			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_new_method_call"));
-			ccall.add_argument (destination);
-			ccall.add_argument (object_path);
-			if (iface_name != null) {
-				ccall.add_argument (new CCodeConstant ("\"%s\"".printf (iface_name)));
-			} else {
-				ccall.add_argument (interface_name);
-			}
-			ccall.add_argument (new CCodeConstant ("\"%s\"".printf (method_name)));
-			ccode.add_assignment (new CCodeIdentifier ("_message"), ccall);
-
-			ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
-			ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
-
-			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"));
-			ccode.add_expression (builder_init);
-
-			if (uses_fd) {
-				ccode.add_declaration ("GUnixFDList", new CCodeVariableDeclarator ("*_fd_list"));
-				ccode.add_assignment (new CCodeIdentifier ("_fd_list"), new CCodeFunctionCall (new CCodeIdentifier ("g_unix_fd_list_new")));
-			}
-
-			CCodeExpression cancellable = new CCodeConstant ("NULL");
-
-			foreach (Parameter param in m.get_parameters ()) {
-				if (param.direction == ParameterDirection.IN) {
-					CCodeExpression expr = new CCodeIdentifier (get_variable_cname (param.name));
-					if (param.variable_type.is_real_struct_type ()) {
-						expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
-					}
-
-					if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
-						cancellable = expr;
-						continue;
-					}
-
-					if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.BusName") {
-						// ignore BusName sender parameters
-						continue;
-					}
-
-					send_dbus_value (param.variable_type, new CCodeIdentifier ("_arguments_builder"), expr, param);
-				}
-			}
-
-			var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
-			builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
-			ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
-
-			var set_body = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_body"));
-			set_body.add_argument (new CCodeIdentifier ("_message"));
-			set_body.add_argument (new CCodeIdentifier ("_arguments"));
-			ccode.add_expression (set_body);
-
-			if (uses_fd) {
-				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_unix_fd_list"));
-				ccall.add_argument (new CCodeIdentifier ("_message"));
-				ccall.add_argument (new CCodeIdentifier ("_fd_list"));
-				ccode.add_expression (ccall);
-
-				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
-				ccall.add_argument (new CCodeIdentifier ("_fd_list"));
-				ccode.add_expression (ccall);
-			}
-
-			// send D-Bus message
-
-			if (call_type == CallType.SYNC) {
-				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_sync"));
-				ccall.add_argument (connection);
-				ccall.add_argument (new CCodeIdentifier ("_message"));
-				ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
-				ccall.add_argument (timeout);
-				ccall.add_argument (new CCodeConstant ("NULL"));
-				ccall.add_argument (cancellable);
-				ccall.add_argument (new CCodeIdentifier ("error"));
-				ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
-			} else if (call_type == CallType.NO_REPLY) {
-				var set_flags = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_flags"));
-				set_flags.add_argument (new CCodeIdentifier ("_message"));
-				set_flags.add_argument (new CCodeConstant ("G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED"));
-				ccode.add_expression (set_flags);
-
-				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message"));
-				ccall.add_argument (connection);
-				ccall.add_argument (new CCodeIdentifier ("_message"));
-				ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
-				ccall.add_argument (new CCodeConstant ("NULL"));
-				ccall.add_argument (new CCodeIdentifier ("error"));
-				ccode.add_expression (ccall);
-			} else if (call_type == CallType.ASYNC) {
-				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply"));
-				ccall.add_argument (connection);
-				ccall.add_argument (new CCodeIdentifier ("_message"));
-				ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
-				ccall.add_argument (timeout);
-				ccall.add_argument (new CCodeConstant ("NULL"));
-				ccall.add_argument (cancellable);
-
-				// use wrapper as source_object wouldn't be correct otherwise
-				ccall.add_argument (new CCodeIdentifier (generate_async_callback_wrapper ()));
-				var res_wrapper = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_new"));
-				res_wrapper.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
-				res_wrapper.add_argument (new CCodeIdentifier ("_callback_"));
-				res_wrapper.add_argument (new CCodeIdentifier ("_user_data_"));
-				res_wrapper.add_argument (new CCodeConstant ("NULL"));
-				ccall.add_argument (res_wrapper);
-
-				ccode.add_expression (ccall);
-			}
-
-			// free D-Bus message
-
-			ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
-			ccall.add_argument (new CCodeIdentifier ("_message"));
-			ccode.add_expression (ccall);
-		} else {
-			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_finish"));
-			ccall.add_argument (connection);
-
-			// unwrap async result
-			var inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_get_op_res_gpointer"));
-			inner_res.add_argument (new CCodeCastExpression (new CCodeIdentifier ("_res_"), "GSimpleAsyncResult *"));
-			ccall.add_argument (inner_res);
-
-			ccall.add_argument (new CCodeConstant ("error"));
-			ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
-		}
-
-		if (call_type == CallType.SYNC || call_type == CallType.FINISH) {
-			ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_reply_message"));
-
-			var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
-			unref_reply.add_argument (new CCodeIdentifier ("_reply_message"));
-
-			// return on io error
-			var reply_is_null = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply_message"));
-			ccode.open_if (reply_is_null);
-			return_default_value (m.return_type);
-			ccode.close ();
-
-			// return on remote error
-			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_to_gerror"));
-			ccall.add_argument (new CCodeIdentifier ("_reply_message"));
-			ccall.add_argument (new CCodeIdentifier ("error"));
-			ccode.open_if (ccall);
-			ccode.add_expression (unref_reply);
-			return_default_value (m.return_type);
-			ccode.close ();
-
-			bool has_result = !(m.return_type is VoidType);
-
-			if (uses_fd) {
-				ccode.add_declaration ("gint", new CCodeVariableDeclarator.zero ("_fd_index", new CCodeConstant ("0")));
-			}
-
-			foreach (Parameter param in m.get_parameters ()) {
-				if (param.direction == ParameterDirection.OUT) {
-					has_result = true;
-				}
-			}
-
-			if (has_result) {
-				ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
-				ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_reply_iter"));
-
-				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_get_body"));
-				ccall.add_argument (new CCodeIdentifier ("_reply_message"));
-				ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
-
-				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"));
-				ccode.add_expression (iter_init);
-
-				foreach (Parameter param in m.get_parameters ()) {
-					if (param.direction == ParameterDirection.OUT) {
-						ccode.add_declaration (get_ccode_name (param.variable_type), new CCodeVariableDeclarator ("_vala_" + param.name));
-
-						var array_type = param.variable_type as ArrayType;
-
-						if (array_type != null) {
-							for (int dim = 1; dim <= array_type.rank; dim++) {
-								ccode.add_declaration ("int", new CCodeVariableDeclarator ("_vala_%s_length%d".printf (param.name, dim), new CCodeConstant ("0")));
-							}
-						}
-
-						var target = new CCodeIdentifier ("_vala_" + param.name);
-						bool may_fail;
-						receive_dbus_value (param.variable_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, param, new CCodeIdentifier ("error"), out may_fail);
-
-						// TODO check that parameter is not NULL (out parameters are optional)
-						// free value if parameter is NULL
-						ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_variable_cname (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)
-								ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("%s_length%d".printf (param.name, dim))), new CCodeIdentifier ("_vala_%s_length%d".printf (param.name, dim)));
-							}
-						}
-
-						if (may_fail) {
-							ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error"))));
-							ccode.add_expression (unref_reply);
-							return_default_value (m.return_type);
-							ccode.close ();
-						}
-					}
-				}
-
-				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"));
-						receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, m);
-					} else {
-						ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator ("_result"));
-
-						var array_type = m.return_type as ArrayType;
-
-						if (array_type != null) {
-							for (int dim = 1; dim <= array_type.rank; dim++) {
-								ccode.add_declaration ("int", new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
-							}
-						}
-
-						bool may_fail;
-						receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"), m, new CCodeIdentifier ("error"), out may_fail);
-
-						if (array_type != null) {
-							for (int dim = 1; dim <= array_type.rank; dim++) {
-								// TODO check that parameter is not NULL (out parameters are optional)
-								ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)));
-							}
-						}
-
-						if (may_fail) {
-							ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error"))));
-							ccode.add_expression (unref_reply);
-							return_default_value (m.return_type);
-							ccode.close ();
-						}
-					}
-				}
-			}
-
-			ccode.add_expression (unref_reply);
-
-			if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
-				ccode.add_return (new CCodeIdentifier ("_result"));
-			}
-		}
-	}
-
-	string generate_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
-		string proxy_name = "%sproxy_%s".printf (get_ccode_lower_case_prefix (main_iface), m.name);
-
-		string dbus_iface_name = get_dbus_name (iface);
-
-		bool no_reply = is_dbus_no_reply (m);
-
-		var function = new CCodeFunction (proxy_name);
-		function.modifiers = CCodeModifiers.STATIC;
-
-		var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
-
-		generate_cparameters (m, cfile, cparam_map, function);
-
-		push_function (function);
-
-		generate_marshalling (m, no_reply ? CallType.NO_REPLY : CallType.SYNC, dbus_iface_name, get_dbus_name_for_member (m));
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (function);
-
-		return proxy_name;
-	}
-
-	string generate_async_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
-		string proxy_name = "%sproxy_%s_async".printf (get_ccode_lower_case_prefix (main_iface), m.name);
-
-		string dbus_iface_name = get_dbus_name (iface);
-
-		var function = new CCodeFunction (proxy_name, "void");
-		function.modifiers = CCodeModifiers.STATIC;
-
-		var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
-
-		cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
-		cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
-
-		generate_cparameters (m, cfile, cparam_map, function, null, null, null, 1);
-
-		push_function (function);
-
-		generate_marshalling (m, CallType.ASYNC, dbus_iface_name, get_dbus_name_for_member (m));
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (function);
-
-		return proxy_name;
-	}
-
-	string generate_finish_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
-		string proxy_name = "%sproxy_%s_finish".printf (get_ccode_lower_case_prefix (main_iface), m.name);
-
-		var function = new CCodeFunction (proxy_name);
-		function.modifiers = CCodeModifiers.STATIC;
-
-		var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
-
-		cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
-
-		generate_cparameters (m, cfile, cparam_map, function, null, null, null, 2);
-
-		push_function (function);
-
-		generate_marshalling (m, CallType.FINISH, null, null);
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (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 (get_ccode_lower_case_prefix (main_iface), 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;
-
-		var function = new CCodeFunction (proxy_name);
-		function.modifiers = CCodeModifiers.STATIC;
-
-		function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface))));
-
-		if (prop.property_type.is_real_non_null_struct_type ()) {
-			function.add_parameter (new CCodeParameter ("result", "%s*".printf (get_ccode_name (prop.get_accessor.value_type))));
-		} else {
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					function.add_parameter (new CCodeParameter ("result_length%d".printf (dim), "int*"));
-				}
-			}
-
-			function.return_type = get_ccode_name (prop.get_accessor.value_type);
-		}
-
-		push_function (function);
-
-		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_inner_reply"));
-
-		// first try cached value
-		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_cached_property"));
-		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
-		ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
-		ccode.add_assignment (new CCodeIdentifier ("_inner_reply"), ccall);
-
-		// if not successful, retrieve value via D-Bus
-		ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_inner_reply")));
-
-		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
-		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
-		ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
-
-		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"));
-		ccode.add_expression (builder_init);
-
-		// interface name
-		write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
-		// property name
-		write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
-
-		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
-		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
-		ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
-
-		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"));
-
-		ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
-
-		// return on error
-		ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")));
-		return_default_value (prop.property_type);
-		ccode.close ();
-
-		var get_variant = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get"));
-		get_variant.add_argument (new CCodeIdentifier ("_reply"));
-		get_variant.add_argument (new CCodeConstant ("\"(v)\""));
-		get_variant.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_inner_reply")));
-		ccode.add_expression (get_variant);
-
-		var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
-		unref_reply.add_argument (new CCodeIdentifier ("_reply"));
-		ccode.add_expression (unref_reply);
-
-		ccode.close ();
-
-		if (prop.property_type.is_real_non_null_struct_type ()) {
-			var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
-			var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), target);
-			ccode.add_assignment (target, result);
-		} else {
-			ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator ("_result"));
-
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					ccode.add_declaration ("int", new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
-				}
-			}
-
-			var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), new CCodeIdentifier ("_result"));
-			ccode.add_assignment (new CCodeIdentifier ("_result"), 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)
-					ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)));
-				}
-			}
-		}
-
-		unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
-		unref_reply.add_argument (new CCodeIdentifier ("_inner_reply"));
-		ccode.add_expression (unref_reply);
-
-		if (prop.property_type.is_real_non_null_struct_type ()) {
-			ccode.add_return ();
-		} else {
-			ccode.add_return (new CCodeIdentifier ("_result"));
-		}
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (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 (get_ccode_lower_case_prefix (main_iface), prop.name);
-
-		string dbus_iface_name = get_dbus_name (iface);
-
-		var array_type = prop.set_accessor.value_type as ArrayType;
-
-		var function = new CCodeFunction (proxy_name);
-		function.modifiers = CCodeModifiers.STATIC;
-
-		function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface))));
-
-		if (prop.property_type.is_real_non_null_struct_type ()) {
-			function.add_parameter (new CCodeParameter ("value", "%s*".printf (get_ccode_name (prop.set_accessor.value_type))));
-		} else {
-			function.add_parameter (new CCodeParameter ("value", get_ccode_name (prop.set_accessor.value_type)));
-
-			if (array_type != null) {
-				for (int dim = 1; dim <= array_type.rank; dim++) {
-					function.add_parameter (new CCodeParameter ("value_length%d".printf (dim), "int"));
-				}
-			}
-		}
-
-		push_function (function);
-
-		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
-		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
-
-		ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
-
-		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"));
-		ccode.add_expression (builder_init);
-
-		// interface name
-		write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
-		// property name
-		write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
-
-		// 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"));
-		ccode.add_expression (builder_open);
-
-		if (prop.property_type.is_real_non_null_struct_type ()) {
-			write_expression (prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value")), prop);
-		} else {
-			write_expression (prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeIdentifier ("value"), prop);
-		}
-
-		var builder_close = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_close"));
-		builder_close.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
-		ccode.add_expression (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")));
-		ccode.add_assignment (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"));
-
-		ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
-
-		// return on error
-		ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")));
-		ccode.add_return ();
-		ccode.close ();
-
-		var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
-		unref_reply.add_argument (new CCodeIdentifier ("_reply"));
-		ccode.add_expression (unref_reply);
-
-		pop_function ();
-
-		cfile.add_function_declaration (function);
-		cfile.add_function (function);
-
-		return proxy_name;
-	}
-
 	public override void register_dbus_info (CCodeBlock block, ObjectTypeSymbol sym) {
 		if (!(sym is Interface)) {
 			return;
diff --git a/codegen/valagdbusclienttransformer.vala b/codegen/valagdbusclienttransformer.vala
new file mode 100644
index 0000000..13974bb
--- /dev/null
+++ b/codegen/valagdbusclienttransformer.vala
@@ -0,0 +1,346 @@
+/* valagdbusclienttransformer.vala
+ *
+ * Copyright (C) 2011  Luca Bruno
+ *
+ * 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:
+ * 	Luca Bruno <lucabru src gnome org>
+ */
+
+/**
+ * Code visitor for transforming the code tree related to DBus clients.
+ */
+public class Vala.GDBusClientTransformer : GVariantTransformer {
+	public static bool is_dbus_no_reply (Method m) {
+		return m.get_attribute_bool ("DBus", "no_reply");
+	}
+
+	public static string? get_dbus_name (TypeSymbol symbol) {
+		return symbol.get_attribute_string ("DBus", "name");
+	}
+
+	public static string get_dbus_name_for_member (Symbol symbol) {
+		var dbus_name = symbol.get_attribute_string ("DBus", "name");
+		if (dbus_name != null) {
+			return dbus_name;
+		}
+
+		return Symbol.lower_case_to_camel_case (symbol.name);
+	}
+
+	Expression read_dbus_value (DataType type, string iter, string message, ref string? fd_list, ref string? fd_index) {
+		string? type_name = null;
+		if (type.data_type != null) {
+			type_name = type.data_type.get_full_name ();
+		}
+		if (type_name == "GLib.UnixInputStream" || type_name == "GLib.UnixOutputStream" || type_name == "GLib.Socket") {
+			if (fd_list == null) {
+				fd_list = b.add_temp_declaration (data_type ("GLib.UnixFDList"), null);
+				fd_index = b.add_temp_declaration (null, expression ("0"));
+				b.add_expression (expression (@"$fd_list = $message.get_unix_fd_list ()"));
+			}
+			b.add_expression (expression (@"$iter.next (\"h\", out $fd_index)"));
+			if (type_name == "GLib.UnixInputStream") {
+				return expression (@"new GLib.UnixInputStream ($fd_list.get ($fd_index), true)");
+			} else if (type_name == "GLib.UnixInputStream") {
+				return expression (@"new GLib.UnixOutputStream ($fd_list.get ($fd_index), true)");
+			} else {
+				// socket
+				return expression (@"new GLib.Socket.from_fd ($fd_list.get ($fd_index))");
+			}
+		} else {
+			return expression (@"($(type)) ($iter.next_value ())");
+		}
+	}
+
+	void generate_marshalling (Method m, string? iface_name, string? method_name) {
+		var interface_name = iface_name != null ? @"\"$iface_name\"" : "this.get_interface_name ()";
+
+		// create the message
+		var reply = b.add_temp_declaration (data_type ("GLib.DBusMessage"));
+		var message = b.add_temp_declaration (null, expression (@"new GLib.DBusMessage.method_call (this.get_name(), this.get_object_path (), $interface_name, \"$method_name\")"));
+		var builder = b.add_temp_declaration (null, expression (@"new GLib.VariantBuilder (GLib.VariantType.TUPLE)"));
+
+		// fill the message
+		bool has_result = m.has_result;
+		string cancellable = "null";
+		string fd_list = null;
+		foreach (var param in m.get_parameters ()) {
+			if (param.direction == ParameterDirection.IN) {
+				string? type_name = null;
+				if (param.variable_type.data_type != null) {
+					type_name = param.variable_type.data_type.get_full_name ();
+				}
+				if (type_name == "GLib.Cancellable") {
+					cancellable = param.name;
+				} else if (type_name == "GLib.BusName") {
+					// ignore BusName sender
+				} else if (type_name == "GLib.UnixInputStream" || type_name == "GLib.UnixOutputStream" || type_name == "GLib.Socket") {
+					if (fd_list == null) {
+						fd_list = b.add_temp_declaration (null, expression ("new GLib.UnixFDList ()"));
+					}
+					b.add_expression (expression (@"$builder.add (\"h\", $fd_list.append ($(param.name).get_fd ()))"));
+				} else {
+					b.add_expression (expression (@"$builder.add_value ($(param.name))"));
+				}
+			} else if (param.direction == ParameterDirection.OUT) {
+				has_result = true;
+			}
+		}
+		b.add_expression (expression (@"$message.set_body ($builder.end ())"));
+		if (fd_list != null) {
+			b.add_expression (expression (@"$message.set_unix_fd_list ($fd_list)"));
+		}
+
+		// send the message
+		if (is_dbus_no_reply (m)) {
+			b.add_expression (expression (@"this.get_connection().send_message ($message, GLib.DBusSendMessageFlags.NO_REPLY_EXPECTED, null)"));
+		} else {
+			var yield_str = m.coroutine ? "yield " : "";
+			var method_str = m.coroutine ? "send_message_with_reply" : "send_message_with_reply_sync";
+			b.add_expression (expression (@"$reply = $yield_str this.get_connection().$method_str ($message, GLib.DBusSendMessageFlags.NONE, this.get_default_timeout (), null, $cancellable)"));
+
+			b.add_expression (expression (@"$reply.to_gerror ()"));
+		}
+
+		// deserialize the result
+		fd_list = null;
+		string fd_index = null;
+		if (has_result) {
+			var iter = b.add_temp_declaration (data_type ("GLib.VariantIter"));
+			b.add_expression (expression (@"$iter = $reply.get_body().iterator ()"));
+			foreach (var param in m.get_parameters ()) {
+				if (param.direction == ParameterDirection.OUT) {
+					b.add_assignment (expression (param.name), read_dbus_value (param.variable_type, iter, reply, ref fd_list, ref fd_index));
+				}
+			}
+			if (m.has_result) {
+				b.add_return (read_dbus_value (m.return_type, iter, reply, ref fd_list, ref fd_index));
+			}
+		}
+	}
+
+	void generate_dbus_proxy_method (Class proxy_class, Interface iface, Method m) {
+		var proxy = new Method (m.name, m.return_type, m.source_reference);
+		foreach (var param in m.get_parameters ()) {
+			proxy.add_parameter (param.copy ());
+		}
+		proxy.access = m.access;
+		proxy.binding = m.binding;
+		proxy.coroutine = m.coroutine;
+		var error_types = new ArrayList<DataType> ();
+		m.get_error_types (error_types);
+		foreach (var error_type in error_types) {
+			proxy.add_error_type (error_type);
+		}
+		proxy_class.add_method (proxy);
+
+		b = new CodeBuilder.for_subroutine (proxy);
+		string dbus_iface_name = get_dbus_name (iface);
+		generate_marshalling (m, dbus_iface_name, get_dbus_name_for_member (m));
+	}
+
+	void generate_dbus_proxy_methods (Class proxy_class, Interface iface) {
+		// also generate proxy for prerequisites
+		foreach (var prereq in iface.get_prerequisites ()) {
+			if (prereq.data_type is Interface) {
+				generate_dbus_proxy_methods (proxy_class, (Interface) prereq.data_type);
+			}
+		}
+
+		foreach (var m in iface.get_methods ()) {
+			if (!m.is_abstract) {
+				continue;
+			}
+
+			generate_dbus_proxy_method (proxy_class, iface, m);
+		}
+	}
+
+	string generate_dbus_proxy_signal (Class proxy_class, Signal sig, ObjectTypeSymbol sym) {
+		var m = new Method (temp_func_cname (), new VoidType (), sig.source_reference);
+		m.access = SymbolAccessibility.PRIVATE;
+		m.add_parameter (new Parameter ("parameters", data_type ("GLib.Variant", false), sig.source_reference));
+		proxy_class.add_method (m);
+		b.push_method (m);
+
+		var iter = b.add_temp_declaration (null, expression ("parameters.iterator ()"));
+		var call = new MethodCall (expression (sig.name), sig.source_reference);
+		foreach (var param in sig.get_parameters ()) {
+			var temp = b.add_temp_declaration (copy_type (param.variable_type, true));
+			if (param.variable_type.data_type == context.analyzer.gvariant_type.data_type) {
+				b.add_expression (expression (@"$temp = $iter.next_value().get_variant ()"));
+			} else {
+				b.add_expression (expression (@"$temp = ($(param.variable_type)) ($iter.next_value ())"));
+			}
+			call.add_argument (expression (temp));
+		}
+		b.add_expression (call);
+
+		b.pop_method ();
+		return m.name;
+	}
+
+	void generate_dbus_proxy_signals (Class proxy_class, ObjectTypeSymbol sym) {
+		var g_signal = (Signal) symbol_from_string ("GLib.DBusProxy.g_signal");
+		var m = new Method ("g_signal", g_signal.return_type, sym.source_reference);
+		m.overrides = true;
+		m.access = SymbolAccessibility.PUBLIC;
+		foreach (var param in g_signal.get_parameters ()) {
+			m.add_parameter (param.copy ());
+		}
+		proxy_class.add_method (m);
+
+		b = new CodeBuilder.for_subroutine (m);
+
+		b.open_switch (expression ("signal_name"), null);
+		b.add_expression (expression ("assert_not_reached ()"));
+		b.add_break ();
+		foreach (var sig in sym.get_signals ()) {
+			if (sig.access != SymbolAccessibility.PUBLIC) {
+				continue;
+			}
+
+			b.add_section (expression (@"\"$(get_dbus_name_for_member (sig))\""));
+			var handler_name = generate_dbus_proxy_signal (proxy_class, sig, sym);
+			b.add_expression (expression (@"$handler_name (parameters)"));
+			b.add_break ();
+		}
+		b.close ();
+	}
+
+	public int 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 timeout;
+	}
+
+	void generate_dbus_proxy_property (Class proxy_class, Interface iface, Property prop) {
+		int timeout = get_dbus_timeout (prop);
+		var dbus_name = get_dbus_name_for_member (prop);
+		var dbus_iface_name = get_dbus_name (iface);
+
+		PropertyAccessor proxy_get = null;
+		if (prop.get_accessor != null) {
+			var owned_type = copy_type (prop.get_accessor.value_type, 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");
+				return;
+			}
+
+			proxy_get = new PropertyAccessor (true, false, false, owned_type, null, prop.get_accessor.source_reference);
+
+			b = new CodeBuilder.for_subroutine (proxy_get);
+			// first try cached value
+			var result = b.add_temp_declaration (null, expression (@"get_cached_property (\"$dbus_name\")"));
+			b.open_if (expression (@"$result == null"));
+			b.add_expression (expression (@"$result = call_sync (\"org.freedesktop.DBus.Properties.Get\", new Variant (\"(ss)\", \"$dbus_iface_name\", \"$dbus_name\"), GLib.DBusCallFlags.NONE, $timeout, null)"));
+			b.add_expression (expression (@"$result.get (\"(v)\", out $result)"));
+			b.close ();
+
+			b.add_return (expression (@"($(prop.property_type)) ($result)"));
+		}
+
+		PropertyAccessor proxy_set = null;
+		if (prop.set_accessor != null) {
+			proxy_set = new PropertyAccessor (false, true, false, prop.set_accessor.value_type, null, prop.set_accessor.source_reference);
+			b = new CodeBuilder.for_subroutine (proxy_set);
+			var variant = b.add_temp_declaration (data_type ("GLib.Variant"), expression ("value"));
+			b.add_expression (expression (@"call_sync (\"org.freedesktop.DBus.Properties.Set\", new Variant (\"(ssv)\", \"$dbus_iface_name\", \"$dbus_name\", $variant), GLib.DBusCallFlags.NONE, $timeout, null)"));
+		}	
+
+		Property proxy = new Property (prop.name, prop.property_type, proxy_get, proxy_set, prop.source_reference);
+		proxy_class.add_property (proxy);
+	}
+
+	void generate_dbus_proxy_properties (Class proxy_class, Interface iface) {
+		// also generate proxy for prerequisites
+		foreach (var prereq in iface.get_prerequisites ()) {
+			if (prereq.data_type is Interface) {
+				generate_dbus_proxy_properties (proxy_class, (Interface) prereq.data_type);
+			}
+		}
+
+		foreach (var prop in iface.get_properties ()) {
+			if (!prop.is_abstract) {
+				continue;
+			}
+
+			generate_dbus_proxy_property (proxy_class, iface, prop);
+		}
+	}
+
+	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;
+		}
+
+		if (iface.parent_symbol.scope.lookup (iface.name+"Proxy") != null) {
+			return;
+		}
+
+		// create proxy class
+		var proxy = new Class (iface.name+"Proxy", iface.source_reference, null);
+		proxy.add_base_type (data_type ("GLib.DBusProxy"));
+		proxy.add_base_type (context.analyzer.get_data_type_for_symbol (iface));
+		proxy.access = iface.access;
+		iface.parent_symbol.add_class (proxy);
+
+		generate_dbus_proxy_methods (proxy, iface);
+		generate_dbus_proxy_signals (proxy, iface);
+		generate_dbus_proxy_properties (proxy, iface);
+
+		check (proxy);
+	}
+
+	public override void visit_method_call (MethodCall expr) {
+		var m = expr.call.symbol_reference as DynamicMethod;
+		if (m == null || m.dynamic_type.data_type != symbol_from_string ("GLib.DBusProxy")) {
+			// not a dynamic dbus call
+			base.visit_method_call (expr);
+			return;
+		}
+
+		b = new CodeBuilder (context, expr.parent_statement, expr.source_reference);
+
+		Method wrapper;
+		var cache_key = "gdbus_client_dynamic_method_call "+m.return_type.to_string ();
+		foreach (var param in m.get_parameters ()) {
+			cache_key = "%s %s".printf (cache_key, param.variable_type.to_string ());
+		}
+		if (!wrapper_method (m.return_type, cache_key, out wrapper, symbol_from_string ("GLib.DBusProxy"))) {
+			foreach (var param in m.get_parameters ()) {
+				wrapper.add_parameter (param.copy ());
+			}
+			b = new CodeBuilder.for_subroutine (wrapper);
+			generate_marshalling (m, null, m.name);
+			check (wrapper);
+		}
+
+		expr.call.symbol_reference = wrapper;
+		base.visit_method_call (expr);
+	}
+}
diff --git a/codegen/valagvariantmodule.vala b/codegen/valagvariantmodule.vala
index 3684fa9..6333325 100644
--- a/codegen/valagvariantmodule.vala
+++ b/codegen/valagvariantmodule.vala
@@ -49,14 +49,6 @@ public class Vala.GVariantModule : GAsyncModule {
 		return false;
 	}
 
-	string get_dbus_value (EnumValue value, string default_value) {
-		var dbus_value = value.get_attribute_string ("DBus", "value");
-		if (dbus_value != null) {
-			return dbus_value;;
-		}
-		return default_value;
-	}
-
 	public static string? get_dbus_signature (Symbol symbol) {
 		return symbol.get_attribute_string ("DBus", "signature");
 	}
diff --git a/codegen/valagvarianttransformer.vala b/codegen/valagvarianttransformer.vala
index 686c8f8..491240c 100644
--- a/codegen/valagvarianttransformer.vala
+++ b/codegen/valagvarianttransformer.vala
@@ -414,7 +414,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		en.add_method (m);
 		m.binding = MemberBinding.STATIC;
 		m.access = SymbolAccessibility.PUBLIC;
-		b = new CodeBuilder.for_method (m);
+		b = new CodeBuilder.for_subroutine (m);
 
 		b.open_switch (expression ("str"), null);
 		b.add_throw (expression ("new GLib.DBusError.INVALID_ARGS (\"Invalid value for enum `%s'\")".printf (CCodeBaseModule.get_ccode_name (en))));
@@ -435,7 +435,7 @@ public class Vala.GVariantTransformer : CodeTransformer {
 		var m = new Method ("to_string", data_type ("string", false, true), en.source_reference);
 		en.add_method (m);
 		m.access = SymbolAccessibility.PUBLIC;
-		b = new CodeBuilder.for_method (m);
+		b = new CodeBuilder.for_subroutine (m);
 
 		b.open_switch (expression ("this"), null);
 		b.add_return (expression ("null"));
diff --git a/compiler/valacompiler.vala b/compiler/valacompiler.vala
index b3531a3..0f337c6 100644
--- a/compiler/valacompiler.vala
+++ b/compiler/valacompiler.vala
@@ -322,7 +322,7 @@ class Vala.Compiler {
 			}
 		}
 
-		var transformer = new GVariantTransformer ();
+		var transformer = new GDBusClientTransformer ();
 		transformer.transform (context);
 
 		if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) {
diff --git a/vala/valacodebuilder.vala b/vala/valacodebuilder.vala
index ec7d370..825fd12 100644
--- a/vala/valacodebuilder.vala
+++ b/vala/valacodebuilder.vala
@@ -48,7 +48,7 @@ public class Vala.CodeBuilder {
 		build_context.check_nodes.add (build_context.current_block);
 	}
 
-	public CodeBuilder.for_method (Method m) {
+	public CodeBuilder.for_subroutine (Subroutine m) {
 		source_reference = m.source_reference;
 		build_context = new BuildContext ();
 		build_context.insert_block = m.body = new Block (source_reference);
diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala
index f79edca..8df4099 100644
--- a/vala/valacodetransformer.vala
+++ b/vala/valacodetransformer.vala
@@ -62,16 +62,18 @@ public class Vala.CodeTransformer : CodeVisitor {
 		wrapper_cache.set (key, node);
 	}
 
-	public bool wrapper_method (DataType return_type, string cache_key, out Method m) {
-		CodeNode n;
-		if (get_cached_wrapper (cache_key, out n)) {
+	public string temp_func_cname () {
+		return "_vala_func_"+CodeNode.get_temp_name ().substring (1);
+	}
+
+	public bool wrapper_method (DataType return_type, string? cache_key, out Method m, Symbol? parent = null) {
+		CodeNode n = null;
+		if (cache_key != null && get_cached_wrapper (cache_key, out n)) {
 			m = (Method) n;
 			return true;
 		}
-		var name = CodeNode.get_temp_name ().replace (".", "");
-		name = "_vala_func_"+name;
-		m = new Method (name, return_type, b.source_reference);
-		context.root.add_method (m);
+		m = new Method (temp_func_cname (), return_type, b.source_reference);
+		(parent == null ? context.root : parent).add_method (m);
 		m.access = SymbolAccessibility.PRIVATE;
 		add_cached_wrapper (cache_key, m);
 		return false;
diff --git a/vapi/gio-2.0.vapi b/vapi/gio-2.0.vapi
index 32692a9..1f62f0f 100644
--- a/vapi/gio-2.0.vapi
+++ b/vapi/gio-2.0.vapi
@@ -634,7 +634,7 @@ namespace GLib {
 		public DBusMessage  signal (string path, string interface_, string @signal);
 		[CCode (array_length_pos = 0.5, array_length_type = "gsize")]
 		public uint8[] to_blob (GLib.DBusCapabilityFlags capabilities) throws GLib.Error;
-		public bool to_gerror () throws GLib.Error;
+		public bool to_gerror () throws GLib.IOError;
 		public bool locked { get; }
 	}
 	[CCode (cheader_filename = "gio/gio.h", ref_function = "g_dbus_method_info_ref", type_id = "g_dbus_method_info_get_type ()", unref_function = "g_dbus_method_info_unref")]



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