]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Support GVariant casts and GDBus clients and servers
authorJürg Billeter <j@bitron.ch>
Sat, 19 Jun 2010 19:43:44 +0000 (21:43 +0200)
committerJürg Billeter <j@bitron.ch>
Sun, 20 Jun 2010 09:32:21 +0000 (11:32 +0200)
12 files changed:
codegen/Makefile.am
codegen/valaccodebasemodule.vala
codegen/valaccodegenerator.vala
codegen/valagdbusclientmodule.vala [new file with mode: 0644]
codegen/valagdbusmodule.vala [new file with mode: 0644]
codegen/valagdbusservermodule.vala [new file with mode: 0644]
codegen/valagvariantmodule.vala [new file with mode: 0644]
vala/valaarraytype.vala
vala/valadatatype.vala
vapi/gio-2.0.vapi
vapi/packages/gio-2.0/gio-2.0-custom.vala
vapi/packages/gio-2.0/gio-2.0.metadata

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