codegen: Infer error parameter from abstract/virtual method implementations
[vala-gnome.git] / codegen / valagdbusclientmodule.vala
blob4d9caa1d317b3cc889e4190f34955fd1f06e5445
1 /* valagdbusclientmodule.vala
3 * Copyright (C) 2010-2011 Jürg Billeter
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.
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.
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Philip Van Hoof <pvanhoof@gnome.org>
24 public class Vala.GDBusClientModule : GDBusModule {
25 enum CallType {
26 SYNC,
27 ASYNC,
28 FINISH,
29 NO_REPLY
32 public CCodeConstant get_dbus_timeout (Symbol symbol) {
33 int timeout = -1;
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);
42 return new CCodeConstant (timeout.to_string ());
45 public override void generate_dynamic_method_wrapper (DynamicMethod method) {
46 var dynamic_method = (DynamicMethod) method;
48 var func = new CCodeFunction (get_ccode_name (method));
49 func.modifiers = CCodeModifiers.STATIC;
51 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
53 generate_cparameters (method, cfile, cparam_map, func);
55 push_function (func);
57 if (dynamic_method.dynamic_type.data_type == dbus_proxy_type) {
58 generate_marshalling (method, CallType.SYNC, null, method.name, -1);
59 } else {
60 Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ()));
63 pop_function ();
65 cfile.add_function_declaration (func);
66 cfile.add_function (func);
69 void generate_proxy_interface_init (Interface main_iface, Interface iface) {
70 // also generate proxy for prerequisites
71 foreach (var prereq in iface.get_prerequisites ()) {
72 if (prereq.data_type is Interface) {
73 generate_proxy_interface_init (main_iface, (Interface) prereq.data_type);
77 string lower_cname = get_ccode_lower_case_prefix (main_iface) + "proxy";
79 var proxy_iface_init = new CCodeFunction (lower_cname + "_" + get_ccode_lower_case_prefix (iface) + "interface_init", "void");
80 proxy_iface_init.add_parameter (new CCodeParameter ("iface", get_ccode_name (iface) + "Iface*"));
82 push_function (proxy_iface_init);
84 foreach (Method m in iface.get_methods ()) {
85 if (!m.is_abstract) {
86 continue;
89 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), get_ccode_vfunc_name (m));
90 if (!m.coroutine) {
91 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (main_iface, iface, m)));
92 } else {
93 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_async_dbus_proxy_method (main_iface, iface, m)));
94 vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), get_ccode_finish_vfunc_name (m));
95 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_finish_dbus_proxy_method (main_iface, iface, m)));
99 foreach (Property prop in iface.get_properties ()) {
100 if (!prop.is_abstract) {
101 continue;
104 if (prop.get_accessor != null) {
105 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "get_" + prop.name);
106 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_get (main_iface, iface, prop)));
108 if (prop.set_accessor != null) {
109 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "set_" + prop.name);
110 ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_set (main_iface, iface, prop)));
114 proxy_iface_init.modifiers = CCodeModifiers.STATIC;
115 pop_function ();
116 cfile.add_function_declaration (proxy_iface_init);
117 cfile.add_function (proxy_iface_init);
120 string implement_interface (CCodeFunctionCall define_type, Interface main_iface, Interface iface) {
121 string result = "";
123 // also implement prerequisites
124 foreach (var prereq in iface.get_prerequisites ()) {
125 if (prereq.data_type is Interface) {
126 result += implement_interface (define_type, main_iface, (Interface) prereq.data_type);
130 string interface_macro;
132 if (in_plugin) {
133 interface_macro = "G_IMPLEMENT_INTERFACE_DYNAMIC";
134 } else {
135 interface_macro = "G_IMPLEMENT_INTERFACE";
138 result += "%s (%s, %sproxy_%sinterface_init) ".printf (
139 interface_macro,
140 get_ccode_upper_case_name (iface, "TYPE_"),
141 get_ccode_lower_case_prefix (main_iface),
142 get_ccode_lower_case_prefix (iface));
143 return result;
146 public override void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
147 base.generate_interface_declaration (iface, decl_space);
149 string dbus_iface_name = get_dbus_name (iface);
150 if (dbus_iface_name == null) {
151 return;
154 string get_type_name = "%sproxy_get_type".printf (get_ccode_lower_case_prefix (iface));
156 if (add_symbol_declaration (decl_space, iface, get_type_name)) {
157 return;
160 decl_space.add_type_declaration (new CCodeNewline ());
161 var macro = "(%s ())".printf (get_type_name);
162 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s_PROXY".printf (get_ccode_type_id (iface)), macro));
164 // declare proxy_get_type function
165 var proxy_get_type = new CCodeFunction (get_type_name, "GType");
166 proxy_get_type.modifiers = CCodeModifiers.CONST;
167 decl_space.add_function_declaration (proxy_get_type);
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 decl_space.add_function_declaration (proxy_register_type);
176 public override void visit_interface (Interface iface) {
177 base.visit_interface (iface);
179 string dbus_iface_name = get_dbus_name (iface);
180 if (dbus_iface_name == null) {
181 return;
184 cfile.add_include ("gio/gio.h");
186 // create proxy class
187 string cname = get_ccode_name (iface) + "Proxy";
188 string lower_cname = get_ccode_lower_case_prefix (iface) + "proxy";
190 cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxy", new CCodeVariableDeclarator (cname)));
191 cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxyClass", new CCodeVariableDeclarator (cname + "Class")));
193 string type_macro;
195 if (in_plugin) {
196 type_macro = "G_DEFINE_DYNAMIC_TYPE_EXTENDED";
197 } else {
198 type_macro = "G_DEFINE_TYPE_EXTENDED";
201 var define_type = new CCodeFunctionCall (new CCodeIdentifier (type_macro));
202 define_type.add_argument (new CCodeIdentifier (cname));
203 define_type.add_argument (new CCodeIdentifier (lower_cname));
204 define_type.add_argument (new CCodeIdentifier ("G_TYPE_DBUS_PROXY"));
205 define_type.add_argument (new CCodeConstant ("0"));
206 define_type.add_argument (new CCodeIdentifier (implement_interface (define_type, iface, iface)));
208 cfile.add_type_member_definition (define_type);
210 var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void");
211 proxy_class_init.add_parameter (new CCodeParameter ("klass", cname + "Class*"));
212 proxy_class_init.modifiers = CCodeModifiers.STATIC;
213 push_function (proxy_class_init);
214 var proxy_class = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY_CLASS"));
215 proxy_class.add_argument (new CCodeIdentifier ("klass"));
216 ccode.add_assignment (new CCodeMemberAccess.pointer (proxy_class, "g_signal"), new CCodeIdentifier (lower_cname + "_g_signal"));
217 pop_function ();
218 cfile.add_function (proxy_class_init);
220 generate_signal_handler_function (iface);
222 if (in_plugin) {
223 var proxy_class_finalize = new CCodeFunction (lower_cname + "_class_finalize", "void");
224 proxy_class_finalize.add_parameter (new CCodeParameter ("klass", cname + "Class*"));
225 proxy_class_finalize.modifiers = CCodeModifiers.STATIC;
226 cfile.add_function (proxy_class_finalize);
228 var proxy_type_init = new CCodeFunction (lower_cname + "_register_dynamic_type", "void");
229 proxy_type_init.add_parameter (new CCodeParameter ("module", "GTypeModule*"));
230 push_function (proxy_type_init);
231 var call_register_type = new CCodeFunctionCall (new CCodeIdentifier (lower_cname + "_register_type"));
232 call_register_type.add_argument (new CCodeIdentifier ("module"));
233 ccode.add_expression (call_register_type);
234 pop_function ();
235 cfile.add_function(proxy_type_init);
238 var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void");
239 proxy_instance_init.add_parameter (new CCodeParameter ("self", cname + "*"));
240 proxy_instance_init.modifiers = CCodeModifiers.STATIC;
241 cfile.add_function (proxy_instance_init);
243 generate_proxy_interface_init (iface, iface);
246 public override void visit_method_call (MethodCall expr) {
247 var mtype = expr.call.value_type as MethodType;
248 bool bus_get_proxy_async = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_bus_get_proxy");
249 bool bus_get_proxy_sync = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_bus_get_proxy_sync");
250 bool conn_get_proxy_async = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_dbus_connection_get_proxy");
251 bool conn_get_proxy_sync = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_dbus_connection_get_proxy_sync");
252 if (!bus_get_proxy_async && !bus_get_proxy_sync && !conn_get_proxy_async && !conn_get_proxy_sync) {
253 base.visit_method_call (expr);
254 return;
257 var ma = (MemberAccess) expr.call;
258 var type_arg = ma.get_type_arguments ().get (0);
260 CCodeExpression proxy_type;
261 CCodeExpression dbus_iface_name;
262 CCodeExpression dbus_iface_info;
264 var object_type = type_arg as ObjectType;
265 if (object_type != null) {
266 var iface = (Interface) object_type.type_symbol;
268 if (get_dbus_name (iface) == null) {
269 Report.error (expr.source_reference, "`%s' is not a D-Bus interface".printf (iface.get_full_name ()));
270 return;
273 proxy_type = new CCodeIdentifier ("%s_PROXY".printf (get_ccode_type_id (iface)));
274 dbus_iface_name = new CCodeConstant ("\"%s\"".printf (get_dbus_name (iface)));
275 } else {
276 // use runtime type information for generic methods
278 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
279 quark.add_argument (new CCodeConstant ("\"vala-dbus-proxy-type\""));
281 var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
282 get_qdata.add_argument (get_type_id_expression (type_arg));
283 get_qdata.add_argument (quark);
285 proxy_type = new CCodeFunctionCall (new CCodeCastExpression (get_qdata, "GType (*) (void)"));
287 quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
288 quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-name\""));
290 get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
291 get_qdata.add_argument (get_type_id_expression (type_arg));
292 get_qdata.add_argument (quark);
294 dbus_iface_name = get_qdata;
297 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
298 quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-info\""));
300 var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
301 get_qdata.add_argument (get_type_id_expression (type_arg));
302 get_qdata.add_argument (quark);
304 dbus_iface_info = get_qdata;
306 if (bus_get_proxy_async || conn_get_proxy_async) {
307 if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
308 // method can fail
309 current_method_inner_error = true;
311 var args = expr.get_argument_list ();
312 Expression res = args.get (0);
314 var source_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
315 var source_ref = get_variable_cexpression (source_var.name);
316 emit_temp_var (source_var);
317 var source = new CCodeFunctionCall (new CCodeIdentifier ("g_async_result_get_source_object"));
318 source.add_argument (get_cvalue (res));
319 ccode.add_assignment (source_ref, source);
321 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_finish"));
322 ccall.add_argument (source_ref);
323 ccall.add_argument (get_cvalue (res));
324 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
326 var temp_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
327 var temp_ref = get_variable_cexpression (temp_var.name);
328 emit_temp_var (temp_var);
329 ccode.add_assignment (temp_ref, ccall);
331 // g_async_result_get_source_object transfers ownership, unref after use
332 var unref_proxy = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
333 unref_proxy.add_argument (source_ref);
334 ccode.add_expression (unref_proxy);
336 set_cvalue (expr, temp_ref);
338 return;
342 var base_arg_index = 0;
343 if (bus_get_proxy_async || bus_get_proxy_sync)
344 base_arg_index = 1;
346 var args = expr.get_argument_list ();
347 Expression name = args.get (base_arg_index + 0);
348 Expression object_path = args.get (base_arg_index + 1);
349 Expression flags = args.get (base_arg_index + 2);
350 Expression cancellable = args.get (base_arg_index + 3);
352 // method can fail
353 current_method_inner_error = true;
355 CCodeFunctionCall ccall;
356 if (bus_get_proxy_async || conn_get_proxy_async) {
357 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_async"));
358 } else {
359 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_initable_new"));
361 ccall.add_argument (proxy_type);
362 if (bus_get_proxy_async || conn_get_proxy_async) {
363 // I/O priority
364 ccall.add_argument (new CCodeConstant ("0"));
366 ccall.add_argument (get_cvalue (cancellable));
367 if (bus_get_proxy_async || conn_get_proxy_async) {
368 if (expr.is_yield_expression) {
369 // asynchronous call
370 ccall.add_argument (new CCodeIdentifier (generate_ready_function (current_method)));
371 ccall.add_argument (new CCodeIdentifier ("_data_"));
372 } else {
373 // begin
374 Expression callback = args.get (base_arg_index + 4);
375 ccall.add_argument (get_cvalue (callback));
376 ccall.add_argument (get_delegate_target (callback));
378 } else {
379 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
381 ccall.add_argument (new CCodeConstant ("\"g-flags\""));
382 ccall.add_argument (get_cvalue (flags));
383 ccall.add_argument (new CCodeConstant ("\"g-name\""));
384 ccall.add_argument (get_cvalue (name));
385 if (bus_get_proxy_async || bus_get_proxy_sync) {
386 Expression bus_type = args.get (0);
387 ccall.add_argument (new CCodeConstant ("\"g-bus-type\""));
388 ccall.add_argument (get_cvalue (bus_type));
389 } else {
390 Expression connection = ma.inner;
391 if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
392 var inner_ma = (MemberAccess) ma.inner;
393 connection = inner_ma.inner;
395 ccall.add_argument (new CCodeConstant ("\"g-connection\""));
396 ccall.add_argument (get_cvalue (connection));
398 ccall.add_argument (new CCodeConstant ("\"g-object-path\""));
399 ccall.add_argument (get_cvalue (object_path));
400 ccall.add_argument (new CCodeConstant ("\"g-interface-name\""));
401 ccall.add_argument (dbus_iface_name);
402 if (dbus_iface_info != null) {
403 ccall.add_argument (new CCodeConstant ("\"g-interface-info\""));
404 ccall.add_argument (dbus_iface_info);
406 ccall.add_argument (new CCodeConstant ("NULL"));
408 if (bus_get_proxy_async || conn_get_proxy_async) {
409 if (expr.is_yield_expression) {
410 int state = emit_context.next_coroutine_state++;
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));
417 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_finish"));
418 ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_source_object_"));
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_variable_cexpression ("_inner_error_")));
422 } else {
423 // begin
424 ccode.add_expression (ccall);
425 return;
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);
432 emit_temp_var (temp_var);
434 ccode.add_assignment (temp_ref, ccall);
435 set_cvalue (expr, temp_ref);
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));
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*"));
446 push_function (function);
448 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_arguments_iter"));
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);
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));
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;
464 ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero (param_name, default_value_for_type (param.variable_type, true)));
466 var st = param.variable_type.data_type 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));
473 if (param.variable_type is ArrayType) {
474 var array_type = (ArrayType) param.variable_type;
476 for (int dim = 1; dim <= array_type.rank; dim++) {
477 string length_cname = get_parameter_array_length_cname (param, dim);
479 ccode.add_declaration ("int", new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
480 ccall.add_argument (new CCodeIdentifier (length_cname));
484 read_expression (param.variable_type, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param_name), param);
487 ccode.add_expression (ccall);
489 foreach (Parameter param in sig.get_parameters ()) {
490 var owned_type = param.variable_type.copy ();
491 owned_type.value_owned = true;
493 if (requires_destroy (owned_type)) {
494 // keep local alive (symbol_reference is weak)
495 var local = new LocalVariable (owned_type, param.name);
496 ccode.add_expression (destroy_local (local));
500 pop_function ();
502 cfile.add_function_declaration (function);
503 cfile.add_function (function);
505 return wrapper_name;
508 void generate_signal_handler_function (ObjectTypeSymbol sym) {
509 var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "proxy_g_signal", "void");
510 cfunc.add_parameter (new CCodeParameter ("proxy", "GDBusProxy*"));
511 cfunc.add_parameter (new CCodeParameter ("sender_name", "const gchar*"));
512 cfunc.add_parameter (new CCodeParameter ("signal_name", "const gchar*"));
513 cfunc.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
515 cfunc.modifiers |= CCodeModifiers.STATIC;
517 cfile.add_function_declaration (cfunc);
519 push_function (cfunc);
521 bool firstif = true;
523 foreach (Signal sig in sym.get_signals ()) {
524 if (sig.access != SymbolAccessibility.PUBLIC) {
525 continue;
528 cfile.add_include ("string.h");
530 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
531 ccheck.add_argument (new CCodeIdentifier ("signal_name"));
532 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
534 var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0"));
535 if (firstif) {
536 ccode.open_if (cond);
537 firstif = false;
538 } else {
539 ccode.else_if (cond);
542 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_signal_handler (sig, sym)));
543 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("proxy"), get_ccode_name (sym) + "*"));
544 ccall.add_argument (new CCodeIdentifier ("parameters"));
546 ccode.add_expression (ccall);
548 if (!firstif) {
549 ccode.close ();
552 pop_function ();
554 cfile.add_function (cfunc);
557 void generate_marshalling (Method m, CallType call_type, string? iface_name, string? method_name, int method_timeout) {
558 var gdbusproxy = new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *");
560 var connection = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_connection"));
561 connection.add_argument (gdbusproxy);
563 bool uses_fd = dbus_method_uses_file_descriptor (m);
564 if (uses_fd) {
565 cfile.add_include ("gio/gunixfdlist.h");
568 bool has_error_argument = (m.get_error_types ().size > 0);
569 CCodeExpression error_argument;
570 if (has_error_argument) {
571 error_argument = new CCodeIdentifier ("error");
572 } else {
573 error_argument = new CCodeConstant ("NULL");
576 if (call_type != CallType.FINISH) {
577 var destination = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_name"));
578 destination.add_argument (gdbusproxy);
580 var interface_name = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_interface_name"));
581 interface_name.add_argument (gdbusproxy);
583 var object_path = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_object_path"));
584 object_path.add_argument (gdbusproxy);
586 CCodeExpression timeout;
587 if (method_timeout <= 0) {
588 timeout = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_default_timeout"));
589 ((CCodeFunctionCall) timeout).add_argument (gdbusproxy);
590 } else {
591 timeout = new CCodeConstant ("%d".printf (method_timeout));
594 // register errors
595 foreach (var error_type in m.get_error_types ()) {
596 var errtype = (ErrorType) error_type;
597 if (errtype.error_domain != null) {
598 ccode.add_expression (new CCodeIdentifier (get_ccode_upper_case_name (errtype.error_domain)));
602 // build D-Bus message
604 ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_message"));
606 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_new_method_call"));
607 ccall.add_argument (destination);
608 ccall.add_argument (object_path);
609 if (iface_name != null) {
610 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (iface_name)));
611 } else {
612 ccall.add_argument (interface_name);
614 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (method_name)));
615 ccode.add_assignment (new CCodeIdentifier ("_message"), ccall);
617 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
618 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
620 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
621 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
622 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
623 ccode.add_expression (builder_init);
625 if (uses_fd) {
626 ccode.add_assignment (new CCodeIdentifier ("_fd_list"), new CCodeFunctionCall (new CCodeIdentifier ("g_unix_fd_list_new")));
629 CCodeExpression cancellable = new CCodeConstant ("NULL");
631 foreach (Parameter param in m.get_parameters ()) {
632 if (param.direction == ParameterDirection.IN) {
633 CCodeExpression expr = new CCodeIdentifier (get_variable_cname (param.name));
634 if (param.variable_type.is_real_struct_type ()) {
635 expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
638 if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
639 cancellable = expr;
640 continue;
643 if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.BusName") {
644 // ignore BusName sender parameters
645 continue;
648 send_dbus_value (param.variable_type, new CCodeIdentifier ("_arguments_builder"), expr, param);
652 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
653 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
654 ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
656 var set_body = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_body"));
657 set_body.add_argument (new CCodeIdentifier ("_message"));
658 set_body.add_argument (new CCodeIdentifier ("_arguments"));
659 ccode.add_expression (set_body);
661 if (uses_fd) {
662 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_unix_fd_list"));
663 ccall.add_argument (new CCodeIdentifier ("_message"));
664 ccall.add_argument (new CCodeIdentifier ("_fd_list"));
665 ccode.add_expression (ccall);
667 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
668 ccall.add_argument (new CCodeIdentifier ("_fd_list"));
669 ccode.add_expression (ccall);
672 // send D-Bus message
674 if (call_type == CallType.SYNC) {
675 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_sync"));
676 ccall.add_argument (connection);
677 ccall.add_argument (new CCodeIdentifier ("_message"));
678 ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
679 ccall.add_argument (timeout);
680 ccall.add_argument (new CCodeConstant ("NULL"));
681 ccall.add_argument (cancellable);
682 ccall.add_argument (error_argument);
683 ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
684 } else if (call_type == CallType.NO_REPLY) {
685 var set_flags = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_flags"));
686 set_flags.add_argument (new CCodeIdentifier ("_message"));
687 set_flags.add_argument (new CCodeConstant ("G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED"));
688 ccode.add_expression (set_flags);
690 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message"));
691 ccall.add_argument (connection);
692 ccall.add_argument (new CCodeIdentifier ("_message"));
693 ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
694 ccall.add_argument (new CCodeConstant ("NULL"));
695 ccall.add_argument (error_argument);
696 ccode.add_expression (ccall);
697 } else if (call_type == CallType.ASYNC) {
698 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply"));
699 ccall.add_argument (connection);
700 ccall.add_argument (new CCodeIdentifier ("_message"));
701 ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
702 ccall.add_argument (timeout);
703 ccall.add_argument (new CCodeConstant ("NULL"));
704 ccall.add_argument (cancellable);
706 CCodeFunctionCall res_wrapper = null;
708 // use wrapper as source_object wouldn't be correct otherwise
709 ccall.add_argument (new CCodeIdentifier (generate_async_callback_wrapper ()));
710 res_wrapper = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new"));
711 res_wrapper.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
712 res_wrapper.add_argument (new CCodeConstant ("NULL"));
713 res_wrapper.add_argument (new CCodeIdentifier ("_callback_"));
714 res_wrapper.add_argument (new CCodeIdentifier ("_user_data_"));
715 ccall.add_argument (res_wrapper);
717 ccode.add_expression (ccall);
720 // free D-Bus message
722 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
723 ccall.add_argument (new CCodeIdentifier ("_message"));
724 ccode.add_expression (ccall);
725 } else {
726 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_finish"));
727 ccall.add_argument (connection);
729 // unwrap async result
730 ccode.add_declaration ("GAsyncResult", new CCodeVariableDeclarator ("*_inner_res"));
732 var inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer"));
733 inner_res.add_argument (new CCodeCastExpression (new CCodeIdentifier ("_res_"), "GTask *"));
734 inner_res.add_argument (new CCodeConstant ("NULL"));
735 ccode.add_assignment (new CCodeIdentifier ("_inner_res"), inner_res);
737 ccall.add_argument (new CCodeIdentifier ("_inner_res"));
738 ccall.add_argument (error_argument);
739 ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
741 // _inner_res is guaranteed to be non-NULL, so just unref it
742 var unref_inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
743 unref_inner_res.add_argument (new CCodeIdentifier ("_inner_res"));
744 ccode.add_expression (unref_inner_res);
747 if (call_type == CallType.SYNC || call_type == CallType.FINISH) {
748 ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_reply_message"));
750 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
751 unref_reply.add_argument (new CCodeIdentifier ("_reply_message"));
753 // return on io error
754 var reply_is_null = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply_message"));
755 ccode.open_if (reply_is_null);
756 return_default_value (m.return_type);
757 ccode.close ();
759 // return on remote error
760 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_to_gerror"));
761 ccall.add_argument (new CCodeIdentifier ("_reply_message"));
762 ccall.add_argument (error_argument);
763 ccode.open_if (ccall);
764 ccode.add_expression (unref_reply);
765 return_default_value (m.return_type);
766 ccode.close ();
768 bool has_result = !(m.return_type is VoidType);
770 if (uses_fd) {
771 ccode.add_declaration ("gint", new CCodeVariableDeclarator.zero ("_fd_index", new CCodeConstant ("0")));
772 ccode.add_declaration ("GUnixFDList*", new CCodeVariableDeclarator ("_fd_list"));
773 ccode.add_declaration ("gint", new CCodeVariableDeclarator ("_fd"));
776 foreach (Parameter param in m.get_parameters ()) {
777 if (param.direction == ParameterDirection.OUT) {
778 has_result = true;
782 if (has_result) {
783 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
784 ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_reply_iter"));
786 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_get_body"));
787 ccall.add_argument (new CCodeIdentifier ("_reply_message"));
788 ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
790 var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
791 iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_iter")));
792 iter_init.add_argument (new CCodeIdentifier ("_reply"));
793 ccode.add_expression (iter_init);
795 foreach (Parameter param in m.get_parameters ()) {
796 if (param.direction == ParameterDirection.OUT) {
797 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)));
799 var array_type = param.variable_type as ArrayType;
801 if (array_type != null) {
802 for (int dim = 1; dim <= array_type.rank; dim++) {
803 ccode.add_declaration ("int", new CCodeVariableDeclarator ("_vala_%s_length%d".printf (param.name, dim), new CCodeConstant ("0")));
807 var target = new CCodeIdentifier ("_vala_%s".printf (param.name));
808 bool may_fail;
810 receive_dbus_value (param.variable_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, param, error_argument, out may_fail);
812 // TODO check that parameter is not NULL (out parameters are optional)
813 // free value if parameter is NULL
814 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_variable_cname (param.name))), target);
816 if (array_type != null) {
817 for (int dim = 1; dim <= array_type.rank; dim++) {
818 // TODO check that parameter is not NULL (out parameters are optional)
819 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)));
823 if (may_fail && has_error_argument) {
824 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error"))));
825 ccode.add_expression (unref_reply);
826 return_default_value (m.return_type);
827 ccode.close ();
832 if (!(m.return_type is VoidType)) {
833 if (m.return_type.is_real_non_null_struct_type ()) {
834 var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
835 receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, m);
836 } else {
837 ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator.zero ("_result", default_value_for_type (m.return_type, true)));
839 var array_type = m.return_type as ArrayType;
841 if (array_type != null) {
842 for (int dim = 1; dim <= array_type.rank; dim++) {
843 ccode.add_declaration ("int", new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
847 bool may_fail;
848 receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"), m, new CCodeIdentifier ("error"), out may_fail);
850 if (array_type != null) {
851 for (int dim = 1; dim <= array_type.rank; dim++) {
852 // TODO check that parameter is not NULL (out parameters are optional)
853 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)));
857 if (may_fail) {
858 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error"))));
859 ccode.add_expression (unref_reply);
860 return_default_value (m.return_type);
861 ccode.close ();
867 ccode.add_expression (unref_reply);
869 if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
870 ccode.add_return (new CCodeIdentifier ("_result"));
875 string generate_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
876 string proxy_name = "%sproxy_%s".printf (get_ccode_lower_case_prefix (main_iface), m.name);
878 string dbus_iface_name = get_dbus_name (iface);
880 bool no_reply = is_dbus_no_reply (m);
882 var function = new CCodeFunction (proxy_name);
883 function.modifiers = CCodeModifiers.STATIC;
885 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
887 generate_cparameters (m, cfile, cparam_map, function);
889 push_function (function);
891 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));
893 pop_function ();
895 cfile.add_function_declaration (function);
896 cfile.add_function (function);
898 return proxy_name;
901 string generate_async_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
902 string proxy_name = "%sproxy_%s_async".printf (get_ccode_lower_case_prefix (main_iface), m.name);
904 string dbus_iface_name = get_dbus_name (iface);
906 var function = new CCodeFunction (proxy_name, "void");
907 function.modifiers = CCodeModifiers.STATIC;
909 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
911 cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
912 cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
914 generate_cparameters (m, cfile, cparam_map, function, null, null, null, 1);
916 push_function (function);
918 generate_marshalling (m, CallType.ASYNC, dbus_iface_name, get_dbus_name_for_member (m), get_dbus_timeout_for_member (m));
920 pop_function ();
922 cfile.add_function_declaration (function);
923 cfile.add_function (function);
925 return proxy_name;
928 string generate_finish_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
929 string proxy_name = "%sproxy_%s_finish".printf (get_ccode_lower_case_prefix (main_iface), m.name);
931 var function = new CCodeFunction (proxy_name);
932 function.modifiers = CCodeModifiers.STATIC;
934 var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
936 cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
938 generate_cparameters (m, cfile, cparam_map, function, null, null, null, 2);
940 push_function (function);
942 generate_marshalling (m, CallType.FINISH, null, null, -1);
944 pop_function ();
946 cfile.add_function_declaration (function);
947 cfile.add_function (function);
949 return proxy_name;
952 string generate_dbus_proxy_property_get (Interface main_iface, Interface iface, Property prop) {
953 string proxy_name = "%sdbus_proxy_get_%s".printf (get_ccode_lower_case_prefix (main_iface), prop.name);
955 string dbus_iface_name = get_dbus_name (iface);
957 var owned_type = prop.get_accessor.value_type.copy ();
958 owned_type.value_owned = true;
959 if (owned_type.is_disposable () && !prop.get_accessor.value_type.value_owned) {
960 Report.error (prop.get_accessor.value_type.source_reference, "Properties used in D-Bus clients require owned get accessor");
963 var array_type = prop.get_accessor.value_type as ArrayType;
965 var function = new CCodeFunction (proxy_name);
966 function.modifiers = CCodeModifiers.STATIC;
968 function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface))));
970 if (prop.property_type.is_real_non_null_struct_type ()) {
971 function.add_parameter (new CCodeParameter ("result", "%s*".printf (get_ccode_name (prop.get_accessor.value_type))));
972 } else {
973 if (array_type != null) {
974 for (int dim = 1; dim <= array_type.rank; dim++) {
975 function.add_parameter (new CCodeParameter ("result_length%d".printf (dim), "int*"));
979 function.return_type = get_ccode_name (prop.get_accessor.value_type);
982 push_function (function);
984 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_inner_reply"));
986 // first try cached value
987 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_cached_property"));
988 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
989 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
990 ccode.add_assignment (new CCodeIdentifier ("_inner_reply"), ccall);
992 // if not successful, retrieve value via D-Bus
993 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_inner_reply")));
995 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
996 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
997 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
999 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
1000 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1001 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
1002 ccode.add_expression (builder_init);
1004 // interface name
1005 write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
1006 // property name
1007 write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
1009 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
1010 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1011 ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
1013 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
1014 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
1015 ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Get\""));
1016 ccall.add_argument (new CCodeIdentifier ("_arguments"));
1017 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
1018 ccall.add_argument (get_dbus_timeout (prop));
1019 ccall.add_argument (new CCodeConstant ("NULL"));
1020 ccall.add_argument (new CCodeConstant ("NULL"));
1022 ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
1024 // return on error
1025 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")));
1026 return_default_value (prop.property_type);
1027 ccode.close ();
1029 var get_variant = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get"));
1030 get_variant.add_argument (new CCodeIdentifier ("_reply"));
1031 get_variant.add_argument (new CCodeConstant ("\"(v)\""));
1032 get_variant.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_inner_reply")));
1033 ccode.add_expression (get_variant);
1035 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
1036 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
1037 ccode.add_expression (unref_reply);
1039 ccode.close ();
1041 if (prop.property_type.is_real_non_null_struct_type ()) {
1042 var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
1043 var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), target);
1044 ccode.add_assignment (target, result);
1045 } else {
1046 ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator ("_result"));
1048 if (get_dbus_signature (prop) != null) {
1049 // raw GVariant
1050 ccode.add_assignment (new CCodeIdentifier ("_result"), new CCodeIdentifier("_inner_reply"));
1051 } else {
1052 if (array_type != null) {
1053 for (int dim = 1; dim <= array_type.rank; dim++) {
1054 ccode.add_declaration ("int", new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
1058 var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), new CCodeIdentifier ("_result"));
1059 ccode.add_assignment (new CCodeIdentifier ("_result"), result);
1061 if (array_type != null) {
1062 for (int dim = 1; dim <= array_type.rank; dim++) {
1063 // TODO check that parameter is not NULL (out parameters are optional)
1064 ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)));
1070 if (prop.property_type.is_real_non_null_struct_type () || get_dbus_signature (prop) == null) {
1071 unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
1072 unref_reply.add_argument (new CCodeIdentifier ("_inner_reply"));
1073 ccode.add_expression (unref_reply);
1076 if (prop.property_type.is_real_non_null_struct_type ()) {
1077 ccode.add_return ();
1078 } else {
1079 ccode.add_return (new CCodeIdentifier ("_result"));
1082 pop_function ();
1084 cfile.add_function_declaration (function);
1085 cfile.add_function (function);
1087 return proxy_name;
1090 string generate_dbus_proxy_property_set (Interface main_iface, Interface iface, Property prop) {
1091 string proxy_name = "%sdbus_proxy_set_%s".printf (get_ccode_lower_case_prefix (main_iface), prop.name);
1093 string dbus_iface_name = get_dbus_name (iface);
1095 var array_type = prop.set_accessor.value_type as ArrayType;
1097 var function = new CCodeFunction (proxy_name);
1098 function.modifiers = CCodeModifiers.STATIC;
1100 function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface))));
1102 if (prop.property_type.is_real_non_null_struct_type ()) {
1103 function.add_parameter (new CCodeParameter ("value", "%s*".printf (get_ccode_name (prop.set_accessor.value_type))));
1104 } else {
1105 function.add_parameter (new CCodeParameter ("value", get_ccode_name (prop.set_accessor.value_type)));
1107 if (array_type != null) {
1108 for (int dim = 1; dim <= array_type.rank; dim++) {
1109 function.add_parameter (new CCodeParameter ("value_length%d".printf (dim), "int"));
1114 push_function (function);
1116 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
1117 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
1119 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
1121 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
1122 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1123 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
1124 ccode.add_expression (builder_init);
1126 // interface name
1127 write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
1128 // property name
1129 write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
1131 // property value (as variant)
1132 var builder_open = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_open"));
1133 builder_open.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1134 builder_open.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_VARIANT"));
1135 ccode.add_expression (builder_open);
1137 if (prop.property_type.is_real_non_null_struct_type ()) {
1138 write_expression (prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value")), prop);
1139 } else {
1140 write_expression (prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeIdentifier ("value"), prop);
1143 var builder_close = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_close"));
1144 builder_close.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1145 ccode.add_expression (builder_close);
1147 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
1148 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1149 ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
1151 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
1152 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
1153 ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Set\""));
1154 ccall.add_argument (new CCodeIdentifier ("_arguments"));
1155 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
1156 ccall.add_argument (get_dbus_timeout (prop));
1157 ccall.add_argument (new CCodeConstant ("NULL"));
1158 ccall.add_argument (new CCodeConstant ("NULL"));
1160 ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
1162 // return on error
1163 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")));
1164 ccode.add_return ();
1165 ccode.close ();
1167 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
1168 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
1169 ccode.add_expression (unref_reply);
1171 pop_function ();
1173 cfile.add_function_declaration (function);
1174 cfile.add_function (function);
1176 return proxy_name;
1179 public override void register_dbus_info (CCodeBlock block, ObjectTypeSymbol sym) {
1180 if (!(sym is Interface)) {
1181 return;
1184 string dbus_iface_name = get_dbus_name (sym);
1185 if (dbus_iface_name == null) {
1186 return;
1189 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1190 quark.add_argument (new CCodeConstant ("\"vala-dbus-proxy-type\""));
1192 var proxy_type = new CCodeIdentifier (get_ccode_lower_case_prefix (sym) + "proxy_get_type");
1194 var set_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_set_qdata"));
1195 set_qdata.add_argument (new CCodeIdentifier ("%s_type_id".printf (get_ccode_lower_case_name (sym, null))));
1196 set_qdata.add_argument (quark);
1197 set_qdata.add_argument (new CCodeCastExpression (proxy_type, "void*"));
1199 block.add_statement (new CCodeExpressionStatement (set_qdata));
1201 quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1202 quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-name\""));
1204 set_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_set_qdata"));
1205 set_qdata.add_argument (new CCodeIdentifier ("%s_type_id".printf (get_ccode_lower_case_name (sym, null))));
1206 set_qdata.add_argument (quark);
1207 set_qdata.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
1209 block.add_statement (new CCodeExpressionStatement (set_qdata));
1211 quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1212 quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-info\""));
1214 set_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_set_qdata"));
1215 set_qdata.add_argument (new CCodeIdentifier ("%s_type_id".printf (get_ccode_lower_case_name (sym, null))));
1216 set_qdata.add_argument (quark);
1217 set_qdata.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_interface_info (sym)), "void*"));
1219 block.add_statement (new CCodeExpressionStatement (set_qdata));