697b0875875f298bbc251b9af5c643a43c4a7d3e
[roobuilder] / src / codegen / valagdbusclientmodule.vala
1 /* valagdbusclientmodule.vala
2  *
3  * Copyright (C) 2010-2011  Jürg Billeter
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
18  *
19  * Author:
20  *      Jürg Billeter <j@bitron.ch>
21  *      Philip Van Hoof <pvanhoof@gnome.org>
22  */
23
24 public class Vala.GDBusClientModule : GDBusModule {
25         enum CallType {
26                 SYNC,
27                 ASYNC,
28                 FINISH,
29                 NO_REPLY
30         }
31
32         public CCodeConstant get_dbus_timeout (Symbol symbol) {
33                 int timeout = -1;
34
35                 var dbus = symbol.get_attribute ("DBus");
36                 if (dbus != null && dbus.has_argument ("timeout")) {
37                         timeout = dbus.get_integer ("timeout");
38                 } else if (symbol.parent_symbol != null) {
39                         return get_dbus_timeout (symbol.parent_symbol);
40                 }
41
42                 return new CCodeConstant (timeout.to_string ());
43         }
44
45         public override void generate_dynamic_method_wrapper (DynamicMethod method) {
46                 var func = new CCodeFunction (get_ccode_name (method));
47                 func.modifiers = CCodeModifiers.STATIC;
48
49                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
50
51                 generate_cparameters (method, cfile, cparam_map, func);
52
53                 push_function (func);
54
55                 if (method.dynamic_type.type_symbol == dbus_proxy_type) {
56                         generate_marshalling (method, CallType.SYNC, null, method.name, -1);
57                 } else {
58                         Report.error (method.source_reference, "dynamic methods are not supported for `%s'", method.dynamic_type.to_string ());
59                 }
60
61                 pop_function ();
62
63                 cfile.add_function_declaration (func);
64                 cfile.add_function (func);
65         }
66
67         void generate_proxy_interface_init (Interface main_iface, Interface iface) {
68                 // also generate proxy for prerequisites
69                 foreach (var prereq in iface.get_prerequisites ()) {
70                         if (prereq.type_symbol is Interface) {
71                                 generate_proxy_interface_init (main_iface, (Interface) prereq.type_symbol);
72                         }
73                 }
74
75                 string lower_cname = get_ccode_lower_case_prefix (main_iface) + "proxy";
76
77                 var proxy_iface_init = new CCodeFunction (lower_cname + "_" + get_ccode_lower_case_prefix (iface) + "interface_init", "void");
78                 proxy_iface_init.add_parameter (new CCodeParameter ("iface", get_ccode_name (iface) + "Iface*"));
79
80                 push_function (proxy_iface_init);
81
82                 foreach (Method m in iface.get_methods ()) {
83                         if (!m.is_abstract) {
84                                 continue;
85                         }
86
87                         var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), get_ccode_vfunc_name (m));
88                         if (!m.coroutine) {
89                                 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (main_iface, iface, m)));
90                         } else {
91                                 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_async_dbus_proxy_method (main_iface, iface, m)));
92                                 vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), get_ccode_finish_vfunc_name (m));
93                                 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_finish_dbus_proxy_method (main_iface, iface, m)));
94                         }
95                 }
96
97                 foreach (Property prop in iface.get_properties ()) {
98                         if (!prop.is_abstract) {
99                                 continue;
100                         }
101
102                         if (prop.get_accessor != null) {
103                                 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "get_" + prop.name);
104                                 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_get (main_iface, iface, prop)));
105                         }
106                         if (prop.set_accessor != null) {
107                                 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "set_" + prop.name);
108                                 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_set (main_iface, iface, prop)));
109                         }
110                 }
111
112                 proxy_iface_init.modifiers = CCodeModifiers.STATIC;
113                 pop_function ();
114                 cfile.add_function_declaration (proxy_iface_init);
115                 cfile.add_function (proxy_iface_init);
116         }
117
118         string implement_interface (CCodeFunctionCall define_type, Interface main_iface, Interface iface) {
119                 string result = "";
120
121                 // also implement prerequisites
122                 foreach (var prereq in iface.get_prerequisites ()) {
123                         if (prereq.type_symbol is Interface) {
124                                 result += implement_interface (define_type, main_iface, (Interface) prereq.type_symbol);
125                         }
126                 }
127
128                 string interface_macro;
129
130                 if (in_plugin) {
131                         interface_macro = "G_IMPLEMENT_INTERFACE_DYNAMIC";
132                 } else {
133                         interface_macro = "G_IMPLEMENT_INTERFACE";
134                 }
135
136                 result += "%s (%s, %sproxy_%sinterface_init) ".printf (
137                         interface_macro,
138                         get_ccode_upper_case_name (iface, "TYPE_"),
139                         get_ccode_lower_case_prefix (main_iface),
140                         get_ccode_lower_case_prefix (iface));
141                 return result;
142         }
143
144         public override void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
145                 base.generate_interface_declaration (iface, decl_space);
146
147                 string dbus_iface_name = get_dbus_name (iface);
148                 if (dbus_iface_name == null) {
149                         return;
150                 }
151
152                 string get_type_name = "%sproxy_get_type".printf (get_ccode_lower_case_prefix (iface));
153
154                 if (add_symbol_declaration (decl_space, iface, get_type_name)) {
155                         return;
156                 }
157
158                 decl_space.add_type_declaration (new CCodeNewline ());
159                 var macro = "(%s ())".printf (get_type_name);
160                 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s_PROXY".printf (get_ccode_type_id (iface)), macro));
161
162                 // declare proxy_get_type function
163                 var proxy_get_type = new CCodeFunction (get_type_name, "GType");
164                 proxy_get_type.modifiers = CCodeModifiers.CONST | CCodeModifiers.EXTERN;
165                 requires_vala_extern = true;
166
167                 decl_space.add_function_declaration (proxy_get_type);
168
169                 if (in_plugin) {
170                         var proxy_register_type = new CCodeFunction ("%sproxy_register_dynamic_type".printf (get_ccode_lower_case_prefix (iface)));
171                         proxy_register_type.add_parameter (new CCodeParameter ("module", "GTypeModule*"));
172                         proxy_register_type.modifiers |= CCodeModifiers.EXTERN;
173                         requires_vala_extern = true;
174
175                         decl_space.add_function_declaration (proxy_register_type);
176                 }
177         }
178
179         public override void visit_interface (Interface iface) {
180                 base.visit_interface (iface);
181
182                 string dbus_iface_name = get_dbus_name (iface);
183                 if (dbus_iface_name == null) {
184                         return;
185                 }
186
187                 cfile.add_include ("gio/gio.h");
188
189                 // create proxy class
190                 string cname = get_ccode_name (iface) + "Proxy";
191                 string lower_cname = get_ccode_lower_case_prefix (iface) + "proxy";
192
193                 cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxy", new CCodeVariableDeclarator (cname)));
194                 cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxyClass", new CCodeVariableDeclarator (cname + "Class")));
195
196                 string type_macro;
197
198                 if (in_plugin) {
199                         type_macro = "G_DEFINE_DYNAMIC_TYPE_EXTENDED";
200                 } else {
201                         type_macro = "G_DEFINE_TYPE_EXTENDED";
202                 }
203
204                 var define_type = new CCodeFunctionCall (new CCodeIdentifier (type_macro));
205                 define_type.add_argument (new CCodeIdentifier (cname));
206                 define_type.add_argument (new CCodeIdentifier (lower_cname));
207                 define_type.add_argument (new CCodeIdentifier ("G_TYPE_DBUS_PROXY"));
208                 define_type.add_argument (new CCodeConstant ("0"));
209                 define_type.add_argument (new CCodeIdentifier (implement_interface (define_type, iface, iface)));
210
211                 cfile.add_type_member_definition (define_type);
212
213                 var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void");
214                 proxy_class_init.add_parameter (new CCodeParameter ("klass", cname + "Class*"));
215                 proxy_class_init.modifiers = CCodeModifiers.STATIC;
216                 push_function (proxy_class_init);
217                 var proxy_class = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY_CLASS"));
218                 proxy_class.add_argument (new CCodeIdentifier ("klass"));
219                 ccode.add_assignment (new CCodeMemberAccess.pointer (proxy_class, "g_signal"), new CCodeIdentifier (lower_cname + "_g_signal"));
220                 pop_function ();
221                 cfile.add_function (proxy_class_init);
222
223                 generate_signal_handler_function (iface);
224
225                 if (in_plugin) {
226                         var proxy_class_finalize = new CCodeFunction (lower_cname + "_class_finalize", "void");
227                         proxy_class_finalize.add_parameter (new CCodeParameter ("klass", cname + "Class*"));
228                         proxy_class_finalize.modifiers = CCodeModifiers.STATIC;
229                         cfile.add_function (proxy_class_finalize);
230
231                         var proxy_type_init = new CCodeFunction (lower_cname + "_register_dynamic_type", "void");
232                         proxy_type_init.add_parameter (new CCodeParameter ("module", "GTypeModule*"));
233                         push_function (proxy_type_init);
234                         var call_register_type = new CCodeFunctionCall (new CCodeIdentifier (lower_cname + "_register_type"));
235                         call_register_type.add_argument (new CCodeIdentifier ("module"));
236                         ccode.add_expression (call_register_type);
237                         pop_function ();
238                         cfile.add_function(proxy_type_init);
239                 }
240
241                 var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void");
242                 proxy_instance_init.add_parameter (new CCodeParameter ("self", cname + "*"));
243                 proxy_instance_init.modifiers = CCodeModifiers.STATIC;
244                 push_function (proxy_instance_init);
245
246                 // TODO Replaces setting of "vala-dbus-interface-info"
247                 var dbus_proxy_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY"));
248                 dbus_proxy_cast.add_argument (new CCodeIdentifier ("self"));
249                 var set_interface_info = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_set_interface_info"));
250                 set_interface_info.add_argument (dbus_proxy_cast);
251                 set_interface_info.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_interface_info (iface)), "GDBusInterfaceInfo *"));
252                 ccode.add_expression (set_interface_info);
253
254                 pop_function ();
255                 cfile.add_function (proxy_instance_init);
256
257                 generate_proxy_interface_init (iface, iface);
258         }
259
260         public override void visit_method_call (MethodCall expr) {
261                 var mtype = expr.call.value_type as MethodType;
262                 bool bus_get_proxy_async = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_bus_get_proxy");
263                 bool bus_get_proxy_sync = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_bus_get_proxy_sync");
264                 bool conn_get_proxy_async = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_dbus_connection_get_proxy");
265                 bool conn_get_proxy_sync = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_dbus_connection_get_proxy_sync");
266                 if (!bus_get_proxy_async && !bus_get_proxy_sync && !conn_get_proxy_async && !conn_get_proxy_sync) {
267                         base.visit_method_call (expr);
268                         return;
269                 }
270
271                 var ma = (MemberAccess) expr.call;
272                 var type_arg = ma.get_type_arguments ().get (0);
273
274                 CCodeExpression proxy_type;
275                 CCodeExpression dbus_iface_name;
276
277                 var object_type = type_arg as ObjectType;
278                 if (object_type != null) {
279                         var iface = (Interface) object_type.type_symbol;
280
281                         if (get_dbus_name (iface) == null) {
282                                 Report.error (expr.source_reference, "`%s' is not a D-Bus interface", iface.get_full_name ());
283                                 return;
284                         }
285
286                         proxy_type = new CCodeIdentifier ("%s_PROXY".printf (get_ccode_type_id (iface)));
287                         dbus_iface_name = new CCodeConstant ("\"%s\"".printf (get_dbus_name (iface)));
288                 } else {
289                         // use runtime type information for generic methods
290
291                         var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
292                         quark.add_argument (new CCodeConstant ("\"vala-dbus-proxy-type\""));
293
294                         var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
295                         get_qdata.add_argument (get_type_id_expression (type_arg));
296                         get_qdata.add_argument (quark);
297
298                         proxy_type = new CCodeFunctionCall (new CCodeCastExpression (get_qdata, "GType (*) (void)"));
299
300                         quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
301                         quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-name\""));
302
303                         get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
304                         get_qdata.add_argument (get_type_id_expression (type_arg));
305                         get_qdata.add_argument (quark);
306
307                         dbus_iface_name = get_qdata;
308                 }
309
310                 if (bus_get_proxy_async || conn_get_proxy_async) {
311                         if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
312                                 // method can fail
313                                 current_method_inner_error = true;
314
315                                 var args = expr.get_argument_list ();
316                                 Expression res = args.get (0);
317
318                                 var source_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
319                                 var source_ref = get_variable_cexpression (source_var.name);
320                                 emit_temp_var (source_var);
321                                 var source = new CCodeFunctionCall (new CCodeIdentifier ("g_async_result_get_source_object"));
322                                 source.add_argument (get_cvalue (res));
323                                 ccode.add_assignment (source_ref, source);
324
325                                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_finish"));
326                                 ccall.add_argument (new CCodeCastExpression (source_ref, "GAsyncInitable *"));
327                                 ccall.add_argument (get_cvalue (res));
328                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
329
330                                 var temp_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
331                                 var temp_ref = get_variable_cexpression (temp_var.name);
332                                 emit_temp_var (temp_var);
333                                 ccode.add_assignment (temp_ref, new CCodeCastExpression (ccall, get_ccode_name (expr.value_type)));
334
335                                 // g_async_result_get_source_object transfers ownership, unref after use
336                                 var unref_proxy = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
337                                 unref_proxy.add_argument (source_ref);
338                                 ccode.add_expression (unref_proxy);
339
340                                 set_cvalue (expr, temp_ref);
341
342                                 return;
343                         }
344                 }
345
346                 var base_arg_index = 0;
347                 if (bus_get_proxy_async || bus_get_proxy_sync)
348                         base_arg_index = 1;
349
350                 var args = expr.get_argument_list ();
351                 Expression name = args.get (base_arg_index + 0);
352                 Expression object_path = args.get (base_arg_index + 1);
353                 Expression flags = args.get (base_arg_index + 2);
354                 Expression cancellable = args.get (base_arg_index + 3);
355
356                 // method can fail
357                 current_method_inner_error = true;
358
359                 CCodeFunctionCall ccall;
360                 if (bus_get_proxy_async || conn_get_proxy_async) {
361                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_async"));
362                 } else {
363                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_initable_new"));
364                 }
365                 ccall.add_argument (proxy_type);
366                 if (bus_get_proxy_async || conn_get_proxy_async) {
367                         // I/O priority
368                         ccall.add_argument (new CCodeConstant ("0"));
369                 }
370                 ccall.add_argument (get_cvalue (cancellable));
371                 if (bus_get_proxy_async || conn_get_proxy_async) {
372                         if (expr.is_yield_expression) {
373                                 // asynchronous call
374                                 ccall.add_argument (new CCodeIdentifier (generate_ready_function (current_method)));
375                                 ccall.add_argument (new CCodeIdentifier ("_data_"));
376                         } else {
377                                 // begin
378                                 Expression callback = args.get (base_arg_index + 4);
379                                 ccall.add_argument (get_cvalue (callback));
380                                 ccall.add_argument (get_delegate_target (callback));
381                         }
382                 } else {
383                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
384                 }
385                 ccall.add_argument (new CCodeConstant ("\"g-flags\""));
386                 ccall.add_argument (get_cvalue (flags));
387                 ccall.add_argument (new CCodeConstant ("\"g-name\""));
388                 ccall.add_argument (get_cvalue (name));
389                 if (bus_get_proxy_async || bus_get_proxy_sync) {
390                         Expression bus_type = args.get (0);
391                         ccall.add_argument (new CCodeConstant ("\"g-bus-type\""));
392                         ccall.add_argument (get_cvalue (bus_type));
393                 } else {
394                         Expression connection = ma.inner;
395                         if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
396                                 var inner_ma = (MemberAccess) ma.inner;
397                                 connection = inner_ma.inner;
398                         }
399                         ccall.add_argument (new CCodeConstant ("\"g-connection\""));
400                         ccall.add_argument (get_cvalue (connection));
401                 }
402                 ccall.add_argument (new CCodeConstant ("\"g-object-path\""));
403                 ccall.add_argument (get_cvalue (object_path));
404                 ccall.add_argument (new CCodeConstant ("\"g-interface-name\""));
405                 ccall.add_argument (dbus_iface_name);
406                 ccall.add_argument (new CCodeConstant ("NULL"));
407
408                 if (bus_get_proxy_async || conn_get_proxy_async) {
409                         if (expr.is_yield_expression) {
410                                 int state = emit_context.next_coroutine_state++;
411
412                                 ccode.add_assignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_state_"), new CCodeConstant (state.to_string ()));
413                                 ccode.add_expression (ccall);
414                                 ccode.add_return (new CCodeConstant ("FALSE"));
415                                 ccode.add_label ("_state_%d".printf (state));
416
417                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_finish"));
418                                 ccall.add_argument (new CCodeCastExpression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_"), "GAsyncInitable *"));
419                                 // pass GAsyncResult stored in closure to finish function
420                                 ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
421                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
422                         } else {
423                                 // begin
424                                 ccode.add_expression (ccall);
425                                 return;
426                         }
427                 }
428
429                 var temp_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
430                 var temp_ref = get_variable_cexpression (temp_var.name);
431
432                 emit_temp_var (temp_var);
433
434                 ccode.add_assignment (temp_ref, new CCodeCastExpression (ccall, get_ccode_name (expr.value_type)));
435                 set_cvalue (expr, temp_ref);
436         }
437
438         string generate_dbus_signal_handler (Signal sig, ObjectTypeSymbol sym) {
439                 string wrapper_name = "_dbus_handle_%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_lower_case_name (sig));
440
441                 var function = new CCodeFunction (wrapper_name);
442                 function.modifiers = CCodeModifiers.STATIC;
443                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*"));
444                 function.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
445
446                 push_function (function);
447
448                 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_arguments_iter"));
449
450                 var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
451                 iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_iter")));
452                 iter_init.add_argument (new CCodeIdentifier ("parameters"));
453                 ccode.add_expression (iter_init);
454
455                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
456                 ccall.add_argument (new CCodeIdentifier ("self"));
457                 ccall.add_argument (get_signal_canonical_constant (sig));
458
459                 foreach (Parameter param in sig.get_parameters ()) {
460                         var param_name = get_variable_cname (param.name);
461                         var owned_type = param.variable_type.copy ();
462                         owned_type.value_owned = true;
463
464                         ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero (param_name, default_value_for_type (param.variable_type, true)));
465
466                         unowned Struct? st = param.variable_type.type_symbol as Struct;
467                         if (st != null && !st.is_simple_type ()) {
468                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param_name)));
469                         } else {
470                                 ccall.add_argument (new CCodeIdentifier (param_name));
471                         }
472
473                         if (param.variable_type is ArrayType) {
474                                 var array_type = (ArrayType) param.variable_type;
475                                 var length_ctype = get_ccode_array_length_type (array_type);
476
477                                 for (int dim = 1; dim <= array_type.rank; dim++) {
478                                         string length_cname = get_variable_array_length_cname (param, dim);
479
480                                         ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
481                                         ccall.add_argument (new CCodeIdentifier (length_cname));
482                                 }
483                         }
484
485                         read_expression (param.variable_type, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param_name), param);
486                 }
487
488                 ccode.add_expression (ccall);
489
490                 foreach (Parameter param in sig.get_parameters ()) {
491                         var owned_type = param.variable_type.copy ();
492                         owned_type.value_owned = true;
493
494                         if (requires_destroy (owned_type)) {
495                                 // keep local alive (symbol_reference is weak)
496                                 var local = new LocalVariable (owned_type, param.name);
497                                 ccode.add_expression (destroy_local (local));
498                         }
499                 }
500
501                 pop_function ();
502
503                 cfile.add_function_declaration (function);
504                 cfile.add_function (function);
505
506                 return wrapper_name;
507         }
508
509         void generate_signal_handler_function (ObjectTypeSymbol sym) {
510                 var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "proxy_g_signal", "void");
511                 cfunc.add_parameter (new CCodeParameter ("proxy", "GDBusProxy*"));
512                 cfunc.add_parameter (new CCodeParameter ("sender_name", "const gchar*"));
513                 cfunc.add_parameter (new CCodeParameter ("signal_name", "const gchar*"));
514                 cfunc.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
515
516                 cfunc.modifiers |= CCodeModifiers.STATIC;
517
518                 cfile.add_function_declaration (cfunc);
519
520                 push_function (cfunc);
521
522                 bool firstif = true;
523
524                 foreach (Signal sig in sym.get_signals ()) {
525                         if (sig.access != SymbolAccessibility.PUBLIC) {
526                                 continue;
527                         }
528
529                         cfile.add_include ("string.h");
530
531                         var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
532                         ccheck.add_argument (new CCodeIdentifier ("signal_name"));
533                         ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
534
535                         var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0"));
536                         if (firstif) {
537                                 ccode.open_if (cond);
538                                 firstif = false;
539                         } else {
540                                 ccode.else_if (cond);
541                         }
542
543                         var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_signal_handler (sig, sym)));
544                         ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("proxy"), get_ccode_name (sym) + "*"));
545                         ccall.add_argument (new CCodeIdentifier ("parameters"));
546
547                         ccode.add_expression (ccall);
548                 }
549                 if (!firstif) {
550                         ccode.close ();
551                 }
552
553                 pop_function ();
554
555                 cfile.add_function (cfunc);
556         }
557
558         void generate_marshalling (Method m, CallType call_type, string? iface_name, string? method_name, int method_timeout) {
559                 var gdbusproxy = new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *");
560
561                 var connection = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_connection"));
562                 connection.add_argument (gdbusproxy);
563
564                 bool uses_fd = dbus_method_uses_file_descriptor (m);
565                 if (uses_fd) {
566                         cfile.add_include ("gio/gunixfdlist.h");
567                         ccode.add_declaration ("GUnixFDList*", new CCodeVariableDeclarator ("_fd_list"));
568                 }
569
570                 bool has_error_argument = m.tree_can_fail;
571                 CCodeExpression error_argument;
572                 if (has_error_argument) {
573                         error_argument = new CCodeIdentifier ("error");
574                 } else {
575                         error_argument = new CCodeConstant ("NULL");
576                 }
577
578                 if (call_type != CallType.FINISH) {
579                         var destination = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_name"));
580                         destination.add_argument (gdbusproxy);
581
582                         var interface_name = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_interface_name"));
583                         interface_name.add_argument (gdbusproxy);
584
585                         var object_path = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_object_path"));
586                         object_path.add_argument (gdbusproxy);
587
588                         CCodeExpression timeout;
589                         if (method_timeout <= 0) {
590                                 timeout = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_default_timeout"));
591                                 ((CCodeFunctionCall) timeout).add_argument (gdbusproxy);
592                         } else {
593                                 timeout = new CCodeConstant ("%d".printf (method_timeout));
594                         }
595
596                         // register errors
597                         var error_types = new ArrayList<DataType> ();
598                         m.get_error_types (error_types);
599                         foreach (var error_type in error_types) {
600                                 var errtype = (ErrorType) error_type;
601                                 if (errtype.error_domain != null) {
602                                         ccode.add_expression (new CCodeIdentifier (get_ccode_upper_case_name (errtype.error_domain)));
603                                 }
604                         }
605
606                         // build D-Bus message
607
608                         ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_message"));
609
610                         var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_new_method_call"));
611                         ccall.add_argument (destination);
612                         ccall.add_argument (object_path);
613                         if (iface_name != null) {
614                                 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (iface_name)));
615                         } else {
616                                 ccall.add_argument (interface_name);
617                         }
618                         ccall.add_argument (new CCodeConstant ("\"%s\"".printf (method_name)));
619                         ccode.add_assignment (new CCodeIdentifier ("_message"), ccall);
620
621                         ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
622                         ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
623
624                         var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
625                         builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
626                         builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
627                         ccode.add_expression (builder_init);
628
629                         if (uses_fd) {
630                                 ccode.add_assignment (new CCodeIdentifier ("_fd_list"), new CCodeFunctionCall (new CCodeIdentifier ("g_unix_fd_list_new")));
631                         }
632
633                         CCodeExpression cancellable = new CCodeConstant ("NULL");
634
635                         foreach (Parameter param in m.get_parameters ()) {
636                                 if (param.direction == ParameterDirection.IN) {
637                                         CCodeExpression expr = new CCodeIdentifier (get_variable_cname (param.name));
638                                         if (param.variable_type.is_real_struct_type ()) {
639                                                 expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
640                                         }
641
642                                         if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
643                                                 cancellable = expr;
644                                                 continue;
645                                         }
646
647                                         if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.BusName") {
648                                                 // ignore BusName sender parameters
649                                                 continue;
650                                         }
651
652                                         send_dbus_value (param.variable_type, new CCodeIdentifier ("_arguments_builder"), expr, param);
653                                 }
654                         }
655
656                         var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
657                         builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
658                         ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
659
660                         var set_body = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_body"));
661                         set_body.add_argument (new CCodeIdentifier ("_message"));
662                         set_body.add_argument (new CCodeIdentifier ("_arguments"));
663                         ccode.add_expression (set_body);
664
665                         if (uses_fd) {
666                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_unix_fd_list"));
667                                 ccall.add_argument (new CCodeIdentifier ("_message"));
668                                 ccall.add_argument (new CCodeIdentifier ("_fd_list"));
669                                 ccode.add_expression (ccall);
670
671                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
672                                 ccall.add_argument (new CCodeIdentifier ("_fd_list"));
673                                 ccode.add_expression (ccall);
674                         }
675
676                         // send D-Bus message
677
678                         if (call_type == CallType.SYNC) {
679                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_sync"));
680                                 ccall.add_argument (connection);
681                                 ccall.add_argument (new CCodeIdentifier ("_message"));
682                                 ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
683                                 ccall.add_argument (timeout);
684                                 ccall.add_argument (new CCodeConstant ("NULL"));
685                                 ccall.add_argument (cancellable);
686                                 ccall.add_argument (error_argument);
687                                 ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
688                         } else if (call_type == CallType.NO_REPLY) {
689                                 var set_flags = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_flags"));
690                                 set_flags.add_argument (new CCodeIdentifier ("_message"));
691                                 set_flags.add_argument (new CCodeConstant ("G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED"));
692                                 ccode.add_expression (set_flags);
693
694                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message"));
695                                 ccall.add_argument (connection);
696                                 ccall.add_argument (new CCodeIdentifier ("_message"));
697                                 ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
698                                 ccall.add_argument (new CCodeConstant ("NULL"));
699                                 ccall.add_argument (error_argument);
700                                 ccode.add_expression (ccall);
701                         } else if (call_type == CallType.ASYNC) {
702                                 var callback_specified = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("_callback_"), new CCodeConstant ("NULL"));
703                                 ccode.open_if (callback_specified);
704
705                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply"));
706                                 ccall.add_argument (connection);
707                                 ccall.add_argument (new CCodeIdentifier ("_message"));
708                                 ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
709                                 ccall.add_argument (timeout);
710                                 ccall.add_argument (new CCodeConstant ("NULL"));
711                                 ccall.add_argument (cancellable);
712
713                                 CCodeFunctionCall res_wrapper = null;
714
715                                 // use wrapper as source_object wouldn't be correct otherwise
716                                 ccall.add_argument (new CCodeIdentifier (generate_async_callback_wrapper ()));
717                                 res_wrapper = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new"));
718                                 res_wrapper.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
719                                 res_wrapper.add_argument (new CCodeConstant ("NULL"));
720                                 res_wrapper.add_argument (new CCodeIdentifier ("_callback_"));
721                                 res_wrapper.add_argument (new CCodeIdentifier ("_user_data_"));
722                                 ccall.add_argument (res_wrapper);
723
724                                 ccode.add_expression (ccall);
725
726                                 ccode.add_else ();
727
728                                 var set_flags = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_flags"));
729                                 set_flags.add_argument (new CCodeIdentifier ("_message"));
730                                 set_flags.add_argument (new CCodeConstant ("G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED"));
731                                 ccode.add_expression (set_flags);
732
733                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message"));
734                                 ccall.add_argument (connection);
735                                 ccall.add_argument (new CCodeIdentifier ("_message"));
736                                 ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
737                                 ccall.add_argument (new CCodeConstant ("NULL"));
738                                 ccall.add_argument (new CCodeConstant ("NULL"));
739                                 ccode.add_expression (ccall);
740
741                                 ccode.close ();
742                         }
743
744                         // free D-Bus message
745
746                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
747                         ccall.add_argument (new CCodeIdentifier ("_message"));
748                         ccode.add_expression (ccall);
749                 } else {
750                         var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_finish"));
751                         ccall.add_argument (connection);
752
753                         // unwrap async result
754                         ccode.add_declaration ("GAsyncResult", new CCodeVariableDeclarator ("*_inner_res"));
755
756                         var inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer"));
757                         inner_res.add_argument (new CCodeCastExpression (new CCodeIdentifier ("_res_"), "GTask *"));
758                         inner_res.add_argument (new CCodeConstant ("NULL"));
759                         ccode.add_assignment (new CCodeIdentifier ("_inner_res"), inner_res);
760
761                         ccall.add_argument (new CCodeIdentifier ("_inner_res"));
762                         ccall.add_argument (error_argument);
763                         ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
764
765                         // _inner_res is guaranteed to be non-NULL, so just unref it
766                         var unref_inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
767                         unref_inner_res.add_argument (new CCodeIdentifier ("_inner_res"));
768                         ccode.add_expression (unref_inner_res);
769                 }
770
771                 if (call_type == CallType.SYNC || call_type == CallType.FINISH) {
772                         ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_reply_message"));
773
774                         var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
775                         unref_reply.add_argument (new CCodeIdentifier ("_reply_message"));
776
777                         // return on io error
778                         var reply_is_null = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply_message"));
779                         ccode.open_if (reply_is_null);
780                         return_default_value (m.return_type);
781                         ccode.close ();
782
783                         // return on remote error
784                         var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_to_gerror"));
785                         ccall.add_argument (new CCodeIdentifier ("_reply_message"));
786                         ccall.add_argument (error_argument);
787                         ccode.open_if (ccall);
788                         ccode.add_expression (unref_reply);
789                         return_default_value (m.return_type);
790                         ccode.close ();
791
792                         bool has_result = !(m.return_type is VoidType);
793
794                         if (uses_fd) {
795                                 ccode.add_declaration ("gint", new CCodeVariableDeclarator.zero ("_fd_index", new CCodeConstant ("0")));
796                                 ccode.add_declaration ("gint", new CCodeVariableDeclarator ("_fd"));
797                         }
798
799                         foreach (Parameter param in m.get_parameters ()) {
800                                 if (param.direction == ParameterDirection.OUT) {
801                                         has_result = true;
802                                 }
803                         }
804
805                         if (has_result) {
806                                 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
807                                 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_reply_iter"));
808
809                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_get_body"));
810                                 ccall.add_argument (new CCodeIdentifier ("_reply_message"));
811                                 ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
812
813                                 var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
814                                 iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_iter")));
815                                 iter_init.add_argument (new CCodeIdentifier ("_reply"));
816                                 ccode.add_expression (iter_init);
817
818                                 foreach (Parameter param in m.get_parameters ()) {
819                                         if (param.direction == ParameterDirection.OUT) {
820                                                 ccode.add_declaration (get_ccode_name (param.variable_type), new CCodeVariableDeclarator.zero ("_vala_%s".printf (param.name), default_value_for_type (param.variable_type, true)));
821
822                                                 var array_type = param.variable_type as ArrayType;
823                                                 if (array_type != null) {
824                                                         var length_ctype = get_ccode_array_length_type (array_type);
825                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
826                                                                 ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_vala_%s_length%d".printf (param.name, dim), new CCodeConstant ("0")));
827                                                         }
828                                                 }
829
830                                                 var target = new CCodeIdentifier ("_vala_%s".printf (param.name));
831                                                 bool may_fail;
832
833                                                 receive_dbus_value (param.variable_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, param, error_argument, out may_fail);
834
835                                                 // TODO check that parameter is not NULL (out parameters are optional)
836                                                 // free value if parameter is NULL
837                                                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_variable_cname (param.name))), target);
838
839                                                 if (array_type != null) {
840                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
841                                                                 // TODO check that parameter is not NULL (out parameters are optional)
842                                                                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("%s_length%d".printf (param.name, dim))), new CCodeIdentifier ("_vala_%s_length%d".printf (param.name, dim)));
843                                                         }
844                                                 }
845
846                                                 if (may_fail && has_error_argument) {
847                                                         ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error"))));
848                                                         ccode.add_expression (unref_reply);
849                                                         return_default_value (m.return_type);
850                                                         ccode.close ();
851                                                 }
852                                         }
853                                 }
854
855                                 if (!(m.return_type is VoidType)) {
856                                         if (m.return_type.is_real_non_null_struct_type ()) {
857                                                 var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
858                                                 receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, m);
859                                         } else {
860                                                 ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator.zero ("_result", default_value_for_type (m.return_type, true)));
861
862                                                 var array_type = m.return_type as ArrayType;
863                                                 if (array_type != null) {
864                                                         var length_ctype = get_ccode_array_length_type (array_type);
865                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
866                                                                 ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
867                                                         }
868                                                 }
869
870                                                 bool may_fail;
871                                                 receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"), m, new CCodeIdentifier ("error"), out may_fail);
872
873                                                 if (array_type != null) {
874                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
875                                                                 // TODO check that parameter is not NULL (out parameters are optional)
876                                                                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)));
877                                                         }
878                                                 }
879
880                                                 if (may_fail) {
881                                                         ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error"))));
882                                                         ccode.add_expression (unref_reply);
883                                                         return_default_value (m.return_type);
884                                                         ccode.close ();
885                                                 }
886                                         }
887                                 }
888                         }
889
890                         ccode.add_expression (unref_reply);
891
892                         if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
893                                 ccode.add_return (new CCodeIdentifier ("_result"));
894                         }
895                 }
896         }
897
898         string generate_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
899                 string proxy_name = "%sproxy_%s".printf (get_ccode_lower_case_prefix (main_iface), m.name);
900
901                 string dbus_iface_name = get_dbus_name (iface);
902
903                 bool no_reply = is_dbus_no_reply (m);
904
905                 var function = new CCodeFunction (proxy_name);
906                 function.modifiers = CCodeModifiers.STATIC;
907
908                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
909
910                 generate_cparameters (m, cfile, cparam_map, function);
911
912                 push_function (function);
913
914                 generate_marshalling (m, no_reply ? CallType.NO_REPLY : CallType.SYNC, dbus_iface_name, get_dbus_name_for_member (m), get_dbus_timeout_for_member (m));
915
916                 pop_function ();
917
918                 cfile.add_function_declaration (function);
919                 cfile.add_function (function);
920
921                 return proxy_name;
922         }
923
924         string generate_async_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
925                 string proxy_name = "%sproxy_%s_async".printf (get_ccode_lower_case_prefix (main_iface), m.name);
926
927                 string dbus_iface_name = get_dbus_name (iface);
928
929                 var function = new CCodeFunction (proxy_name, "void");
930                 function.modifiers = CCodeModifiers.STATIC;
931
932                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
933
934                 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
935                 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
936
937                 generate_cparameters (m, cfile, cparam_map, function, null, null, null, 1);
938
939                 push_function (function);
940
941                 generate_marshalling (m, CallType.ASYNC, dbus_iface_name, get_dbus_name_for_member (m), get_dbus_timeout_for_member (m));
942
943                 pop_function ();
944
945                 cfile.add_function_declaration (function);
946                 cfile.add_function (function);
947
948                 return proxy_name;
949         }
950
951         string generate_finish_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
952                 string proxy_name = "%sproxy_%s_finish".printf (get_ccode_lower_case_prefix (main_iface), m.name);
953
954                 var function = new CCodeFunction (proxy_name);
955                 function.modifiers = CCodeModifiers.STATIC;
956
957                 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
958
959                 cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
960
961                 generate_cparameters (m, cfile, cparam_map, function, null, null, null, 2);
962
963                 push_function (function);
964
965                 generate_marshalling (m, CallType.FINISH, null, null, -1);
966
967                 pop_function ();
968
969                 cfile.add_function_declaration (function);
970                 cfile.add_function (function);
971
972                 return proxy_name;
973         }
974
975         string generate_dbus_proxy_property_get (Interface main_iface, Interface iface, Property prop) {
976                 string proxy_name = "%sdbus_proxy_get_%s".printf (get_ccode_lower_case_prefix (main_iface), prop.name);
977
978                 string dbus_iface_name = get_dbus_name (iface);
979
980                 var owned_type = prop.get_accessor.value_type.copy ();
981                 owned_type.value_owned = true;
982                 if (owned_type.is_disposable () && !prop.get_accessor.value_type.value_owned) {
983                         Report.error (prop.get_accessor.value_type.source_reference, "Properties used in D-Bus clients require owned get accessor");
984                 }
985
986                 var array_type = prop.get_accessor.value_type as ArrayType;
987
988                 var function = new CCodeFunction (proxy_name);
989                 function.modifiers = CCodeModifiers.STATIC;
990
991                 function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface))));
992
993                 if (prop.property_type.is_real_non_null_struct_type ()) {
994                         function.add_parameter (new CCodeParameter ("result", "%s*".printf (get_ccode_name (prop.get_accessor.value_type))));
995                 } else {
996                         if (array_type != null) {
997                                 var length_ctype = get_ccode_array_length_type (array_type) + "*";
998                                 for (int dim = 1; dim <= array_type.rank; dim++) {
999                                         function.add_parameter (new CCodeParameter ("result_length%d".printf (dim), length_ctype));
1000                                 }
1001                         }
1002
1003                         function.return_type = get_ccode_name (prop.get_accessor.value_type);
1004                 }
1005
1006                 push_function (function);
1007
1008                 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_inner_reply"));
1009
1010                 // first try cached value
1011                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_cached_property"));
1012                 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
1013                 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
1014                 ccode.add_assignment (new CCodeIdentifier ("_inner_reply"), ccall);
1015
1016                 // if not successful, retrieve value via D-Bus
1017                 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_inner_reply")));
1018
1019                 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
1020                 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
1021                 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
1022
1023                 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
1024                 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1025                 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
1026                 ccode.add_expression (builder_init);
1027
1028                 // interface name
1029                 write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
1030                 // property name
1031                 write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
1032
1033                 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
1034                 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1035                 ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
1036
1037                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
1038                 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
1039                 ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Get\""));
1040                 ccall.add_argument (new CCodeIdentifier ("_arguments"));
1041                 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
1042                 ccall.add_argument (get_dbus_timeout (prop));
1043                 ccall.add_argument (new CCodeConstant ("NULL"));
1044                 ccall.add_argument (new CCodeConstant ("NULL"));
1045
1046                 ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
1047
1048                 // return on error
1049                 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")));
1050                 return_default_value (prop.property_type);
1051                 ccode.close ();
1052
1053                 var get_variant = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get"));
1054                 get_variant.add_argument (new CCodeIdentifier ("_reply"));
1055                 get_variant.add_argument (new CCodeConstant ("\"(v)\""));
1056                 get_variant.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_inner_reply")));
1057                 ccode.add_expression (get_variant);
1058
1059                 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
1060                 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
1061                 ccode.add_expression (unref_reply);
1062
1063                 ccode.close ();
1064
1065                 if (prop.property_type.is_real_non_null_struct_type ()) {
1066                         var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
1067                         var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), target);
1068                         ccode.add_assignment (target, result);
1069                 } else {
1070                         ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator ("_result"));
1071
1072                         if (get_dbus_signature (prop) != null) {
1073                                 // raw GVariant
1074                                 ccode.add_assignment (new CCodeIdentifier ("_result"), new CCodeIdentifier("_inner_reply"));
1075                         } else {
1076                                 if (array_type != null) {
1077                                         var length_ctype = get_ccode_array_length_type (array_type);
1078                                         for (int dim = 1; dim <= array_type.rank; dim++) {
1079                                                 ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
1080                                         }
1081                                 }
1082
1083                                 var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), new CCodeIdentifier ("_result"));
1084                                 ccode.add_assignment (new CCodeIdentifier ("_result"), result);
1085
1086                                 if (array_type != null) {
1087                                         for (int dim = 1; dim <= array_type.rank; dim++) {
1088                                                 // TODO check that parameter is not NULL (out parameters are optional)
1089                                                 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)));
1090                                         }
1091                                 }
1092                         }
1093                 }
1094
1095                 if (prop.property_type.is_real_non_null_struct_type () || get_dbus_signature (prop) == null) {
1096                         unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
1097                         unref_reply.add_argument (new CCodeIdentifier ("_inner_reply"));
1098                         ccode.add_expression (unref_reply);
1099                 }
1100
1101                 if (prop.property_type.is_real_non_null_struct_type ()) {
1102                         ccode.add_return ();
1103                 } else {
1104                         ccode.add_return (new CCodeIdentifier ("_result"));
1105                 }
1106
1107                 pop_function ();
1108
1109                 cfile.add_function_declaration (function);
1110                 cfile.add_function (function);
1111
1112                 return proxy_name;
1113         }
1114
1115         string generate_dbus_proxy_property_set (Interface main_iface, Interface iface, Property prop) {
1116                 string proxy_name = "%sdbus_proxy_set_%s".printf (get_ccode_lower_case_prefix (main_iface), prop.name);
1117
1118                 string dbus_iface_name = get_dbus_name (iface);
1119
1120                 var array_type = prop.set_accessor.value_type as ArrayType;
1121
1122                 var function = new CCodeFunction (proxy_name);
1123                 function.modifiers = CCodeModifiers.STATIC;
1124
1125                 function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface))));
1126
1127                 if (prop.property_type.is_real_non_null_struct_type ()) {
1128                         function.add_parameter (new CCodeParameter ("value", "%s*".printf (get_ccode_name (prop.set_accessor.value_type))));
1129                 } else {
1130                         function.add_parameter (new CCodeParameter ("value", get_ccode_name (prop.set_accessor.value_type)));
1131
1132                         if (array_type != null) {
1133                                 var length_ctype = get_ccode_array_length_type (array_type);
1134                                 for (int dim = 1; dim <= array_type.rank; dim++) {
1135                                         function.add_parameter (new CCodeParameter ("value_length%d".printf (dim), length_ctype));
1136                                 }
1137                         }
1138                 }
1139
1140                 push_function (function);
1141
1142                 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
1143                 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
1144
1145                 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
1146
1147                 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
1148                 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1149                 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
1150                 ccode.add_expression (builder_init);
1151
1152                 // interface name
1153                 write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
1154                 // property name
1155                 write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
1156
1157                 // property value (as variant)
1158                 var builder_open = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_open"));
1159                 builder_open.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1160                 builder_open.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_VARIANT"));
1161                 ccode.add_expression (builder_open);
1162
1163                 if (prop.property_type.is_real_non_null_struct_type ()) {
1164                         write_expression (prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value")), prop);
1165                 } else {
1166                         write_expression (prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeIdentifier ("value"), prop);
1167                 }
1168
1169                 var builder_close = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_close"));
1170                 builder_close.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1171                 ccode.add_expression (builder_close);
1172
1173                 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
1174                 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1175                 ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
1176
1177                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
1178                 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
1179                 ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Set\""));
1180                 ccall.add_argument (new CCodeIdentifier ("_arguments"));
1181                 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
1182                 ccall.add_argument (get_dbus_timeout (prop));
1183                 ccall.add_argument (new CCodeConstant ("NULL"));
1184                 ccall.add_argument (new CCodeConstant ("NULL"));
1185
1186                 ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
1187
1188                 // return on error
1189                 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")));
1190                 ccode.add_return ();
1191                 ccode.close ();
1192
1193                 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
1194                 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
1195                 ccode.add_expression (unref_reply);
1196
1197                 pop_function ();
1198
1199                 cfile.add_function_declaration (function);
1200                 cfile.add_function (function);
1201
1202                 return proxy_name;
1203         }
1204
1205         public override void register_dbus_info (CCodeBlock block, ObjectTypeSymbol sym) {
1206                 if (!(sym is Interface)) {
1207                         return;
1208                 }
1209
1210                 string dbus_iface_name = get_dbus_name (sym);
1211                 if (dbus_iface_name == null) {
1212                         return;
1213                 }
1214
1215                 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1216                 quark.add_argument (new CCodeConstant ("\"vala-dbus-proxy-type\""));
1217
1218                 var proxy_type = new CCodeIdentifier (get_ccode_lower_case_prefix (sym) + "proxy_get_type");
1219
1220                 var set_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_set_qdata"));
1221                 set_qdata.add_argument (new CCodeIdentifier ("%s_type_id".printf (get_ccode_lower_case_name (sym, null))));
1222                 set_qdata.add_argument (quark);
1223                 set_qdata.add_argument (new CCodeCastExpression (proxy_type, "void*"));
1224
1225                 block.add_statement (new CCodeExpressionStatement (set_qdata));
1226
1227                 quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1228                 quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-name\""));
1229
1230                 set_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_set_qdata"));
1231                 set_qdata.add_argument (new CCodeIdentifier ("%s_type_id".printf (get_ccode_lower_case_name (sym, null))));
1232                 set_qdata.add_argument (quark);
1233                 set_qdata.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
1234
1235                 block.add_statement (new CCodeExpressionStatement (set_qdata));
1236
1237                 // TODO Replaced by g_dbus_proxy_set_interface_info() call in *_init
1238                 quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1239                 quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-info\""));
1240
1241                 set_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_set_qdata"));
1242                 set_qdata.add_argument (new CCodeIdentifier ("%s_type_id".printf (get_ccode_lower_case_name (sym, null))));
1243                 set_qdata.add_argument (quark);
1244                 set_qdata.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_interface_info (sym)), "void*"));
1245
1246                 block.add_statement (new CCodeExpressionStatement (set_qdata));
1247         }
1248 }