[vala/wip/transform: 31/72] GDBus client transformer



commit 27da56a3a83bf96c67fa99425af84c71716d5a14
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 b04245f..4309085 100644
--- a/compiler/valacompiler.vala
+++ b/compiler/valacompiler.vala
@@ -324,7 +324,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 6e90166..86bc7de 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]