valagdbusclientmodule.vala 51.2 KB
Newer Older
1 2
/* valagdbusclientmodule.vala
 *
3
 * Copyright (C) 2010-2011  Jürg Billeter
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
 * 	Philip Van Hoof <pvanhoof@gnome.org>
 */

public class Vala.GDBusClientModule : GDBusModule {
25 26 27 28 29 30 31
	enum CallType {
		SYNC,
		ASYNC,
		FINISH,
		NO_REPLY
	}

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
	public CCodeConstant get_dbus_timeout (Symbol symbol) {
		int timeout = -1;

		var dbus = symbol.get_attribute ("DBus");
		if (dbus != null && dbus.has_argument ("timeout")) {
			timeout = dbus.get_integer ("timeout");
		} else if (symbol.parent_symbol != null) {
			return get_dbus_timeout (symbol.parent_symbol);
		}

		return new CCodeConstant (timeout.to_string ());
	}

	public override void generate_dynamic_method_wrapper (DynamicMethod method) {
		var dynamic_method = (DynamicMethod) method;

48
		var func = new CCodeFunction (get_ccode_name (method));
49 50
		func.modifiers = CCodeModifiers.STATIC;

51
		var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
52

53
		generate_cparameters (method, cfile, cparam_map, func);
54

55 56
		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 60 61 62
		} else {
			Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ()));
		}

63
		pop_function ();
64

65
		cfile.add_function_declaration (func);
66
		cfile.add_function (func);
67 68 69 70 71 72 73 74 75 76
	}

	void generate_proxy_interface_init (Interface main_iface, Interface iface) {
		// also generate proxy for prerequisites
		foreach (var prereq in iface.get_prerequisites ()) {
			if (prereq.data_type is Interface) {
				generate_proxy_interface_init (main_iface, (Interface) prereq.data_type);
			}
		}

77
		string lower_cname = get_ccode_lower_case_prefix (main_iface) + "proxy";
78

79 80
		var proxy_iface_init = new CCodeFunction (lower_cname + "_" + get_ccode_lower_case_prefix (iface) + "interface_init", "void");
		proxy_iface_init.add_parameter (new CCodeParameter ("iface", get_ccode_name (iface) + "Iface*"));
81

82
		push_function (proxy_iface_init);
83 84

		foreach (Method m in iface.get_methods ()) {
85 86 87 88
			if (!m.is_abstract) {
				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)));
96 97 98 99
			}
		}

		foreach (Property prop in iface.get_properties ()) {
100 101 102 103
			if (!prop.is_abstract) {
				continue;
			}

104 105
			if (prop.get_accessor != null) {
				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)));
107 108 109
			}
			if (prop.set_accessor != null) {
				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)));
111 112 113 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);
118 119 120 121 122 123 124 125 126 127 128 129
	}

	string implement_interface (CCodeFunctionCall define_type, Interface main_iface, Interface iface) {
		string result = "";

		// also implement prerequisites
		foreach (var prereq in iface.get_prerequisites ()) {
			if (prereq.data_type is Interface) {
				result += implement_interface (define_type, main_iface, (Interface) prereq.data_type);
			}
		}

130 131 132 133 134 135 136 137 138 139
		string interface_macro;

		if (in_plugin) {
			interface_macro = "G_IMPLEMENT_INTERFACE_DYNAMIC";
		} else {
			interface_macro = "G_IMPLEMENT_INTERFACE";
		}

		result += "%s (%s, %sproxy_%sinterface_init) ".printf (
			interface_macro,
140 141 142
			get_ccode_upper_case_name (iface, "TYPE_"),
			get_ccode_lower_case_prefix (main_iface),
			get_ccode_lower_case_prefix (iface));
143 144 145
		return result;
	}

146
	public override void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
147 148 149 150 151 152 153
		base.generate_interface_declaration (iface, decl_space);

		string dbus_iface_name = get_dbus_name (iface);
		if (dbus_iface_name == null) {
			return;
		}

154
		string get_type_name = "%sproxy_get_type".printf (get_ccode_lower_case_prefix (iface));
155

156
		if (add_symbol_declaration (decl_space, iface, get_type_name)) {
157 158 159 160 161
			return;
		}

		decl_space.add_type_declaration (new CCodeNewline ());
		var macro = "(%s ())".printf (get_type_name);
162
		decl_space.add_type_declaration (new CCodeMacroReplacement ("%s_PROXY".printf (get_ccode_type_id (iface)), macro));
163 164 165

		// declare proxy_get_type function
		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);
168 169 170 171 172 173

		if (in_plugin) {
			var proxy_register_type = new CCodeFunction ("%sproxy_register_dynamic_type".printf (get_ccode_lower_case_prefix (iface)));
			proxy_register_type.add_parameter (new CCodeParameter ("module", "GTypeModule*"));
			decl_space.add_function_declaration (proxy_register_type);
		}
174 175 176 177 178 179 180 181 182 183
	}

	public override void visit_interface (Interface iface) {
		base.visit_interface (iface);

		string dbus_iface_name = get_dbus_name (iface);
		if (dbus_iface_name == null) {
			return;
		}

184
		cfile.add_include ("gio/gio.h");
185

186
		// create proxy class
187 188
		string cname = get_ccode_name (iface) + "Proxy";
		string lower_cname = get_ccode_lower_case_prefix (iface) + "proxy";
189

190 191
		cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxy", new CCodeVariableDeclarator (cname)));
		cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxyClass", new CCodeVariableDeclarator (cname + "Class")));
192

193 194 195 196 197 198 199 200 201
		string type_macro;

		if (in_plugin) {
			type_macro = "G_DEFINE_DYNAMIC_TYPE_EXTENDED";
		} else {
			type_macro = "G_DEFINE_TYPE_EXTENDED";
		}

		var define_type = new CCodeFunctionCall (new CCodeIdentifier (type_macro));
202 203 204 205 206 207
		define_type.add_argument (new CCodeIdentifier (cname));
		define_type.add_argument (new CCodeIdentifier (lower_cname));
		define_type.add_argument (new CCodeIdentifier ("G_TYPE_DBUS_PROXY"));
		define_type.add_argument (new CCodeConstant ("0"));
		define_type.add_argument (new CCodeIdentifier (implement_interface (define_type, iface, iface)));

208
		cfile.add_type_member_definition (define_type);
209 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 215
		var proxy_class = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY_CLASS"));
		proxy_class.add_argument (new CCodeIdentifier ("klass"));
216 217
		ccode.add_assignment (new CCodeMemberAccess.pointer (proxy_class, "g_signal"), new CCodeIdentifier (lower_cname + "_g_signal"));
		pop_function ();
218
		cfile.add_function (proxy_class_init);
219 220 221

		generate_signal_handler_function (iface);

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
		if (in_plugin) {
			var proxy_class_finalize = new CCodeFunction (lower_cname + "_class_finalize", "void");
			proxy_class_finalize.add_parameter (new CCodeParameter ("klass", cname + "Class*"));
			proxy_class_finalize.modifiers = CCodeModifiers.STATIC;
			cfile.add_function (proxy_class_finalize);

			var proxy_type_init = new CCodeFunction (lower_cname + "_register_dynamic_type", "void");
			proxy_type_init.add_parameter (new CCodeParameter ("module", "GTypeModule*"));
			push_function (proxy_type_init);
			var call_register_type = new CCodeFunctionCall (new CCodeIdentifier (lower_cname + "_register_type"));
			call_register_type.add_argument (new CCodeIdentifier ("module"));
			ccode.add_expression (call_register_type);
			pop_function ();
			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);
242 243 244 245 246 247

		generate_proxy_interface_init (iface, iface);
	}

	public override void visit_method_call (MethodCall expr) {
		var mtype = expr.call.value_type as MethodType;
248 249 250 251
		bool bus_get_proxy_async = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_bus_get_proxy");
		bool bus_get_proxy_sync = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_bus_get_proxy_sync");
		bool conn_get_proxy_async = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_dbus_connection_get_proxy");
		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 254 255 256 257
			base.visit_method_call (expr);
			return;
		}

		var ma = (MemberAccess) expr.call;
258
		var type_arg = ma.get_type_arguments ().get (0);
259

260 261
		CCodeExpression proxy_type;
		CCodeExpression dbus_iface_name;
262
		CCodeExpression dbus_iface_info;
263 264 265 266 267 268 269 270 271 272

		var object_type = type_arg as ObjectType;
		if (object_type != null) {
			var iface = (Interface) object_type.type_symbol;

			if (get_dbus_name (iface) == null) {
				Report.error (expr.source_reference, "`%s' is not a D-Bus interface".printf (iface.get_full_name ()));
				return;
			}

273
			proxy_type = new CCodeIdentifier ("%s_PROXY".printf (get_ccode_type_id (iface)));
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
			dbus_iface_name = new CCodeConstant ("\"%s\"".printf (get_dbus_name (iface)));
		} else {
			// use runtime type information for generic methods

			var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
			quark.add_argument (new CCodeConstant ("\"vala-dbus-proxy-type\""));

			var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
			get_qdata.add_argument (get_type_id_expression (type_arg));
			get_qdata.add_argument (quark);

			proxy_type = new CCodeFunctionCall (new CCodeCastExpression (get_qdata, "GType (*) (void)"));

			quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
			quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-name\""));

			get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
			get_qdata.add_argument (get_type_id_expression (type_arg));
			get_qdata.add_argument (quark);

			dbus_iface_name = get_qdata;
295 296
		}

297 298 299 300 301 302 303 304 305
		var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
		quark.add_argument (new CCodeConstant ("\"vala-dbus-interface-info\""));

		var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
		get_qdata.add_argument (get_type_id_expression (type_arg));
		get_qdata.add_argument (quark);

		dbus_iface_info = get_qdata;

306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
		if (bus_get_proxy_async || conn_get_proxy_async) {
			if (ma.member_name == "end" && ma.inner.symbol_reference == ma.symbol_reference) {
				// method can fail
				current_method_inner_error = true;

				var args = expr.get_argument_list ();
				Expression res = args.get (0);

				var source_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
				var source_ref = get_variable_cexpression (source_var.name);
				emit_temp_var (source_var);
				var source = new CCodeFunctionCall (new CCodeIdentifier ("g_async_result_get_source_object"));
				source.add_argument (get_cvalue (res));
				ccode.add_assignment (source_ref, source);

				var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_finish"));
322
				ccall.add_argument (new CCodeCastExpression (source_ref, "GAsyncInitable *"));
323
				ccall.add_argument (get_cvalue (res));
324
				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
325 326 327 328

				var temp_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
				var temp_ref = get_variable_cexpression (temp_var.name);
				emit_temp_var (temp_var);
329
				ccode.add_assignment (temp_ref, new CCodeCastExpression (ccall, get_ccode_name (expr.value_type)));
330 331 332 333 334 335 336 337 338 339 340 341

				// g_async_result_get_source_object transfers ownership, unref after use
				var unref_proxy = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
				unref_proxy.add_argument (source_ref);
				ccode.add_expression (unref_proxy);

				set_cvalue (expr, temp_ref);

				return;
			}
		}

342
		var base_arg_index = 0;
343
		if (bus_get_proxy_async || bus_get_proxy_sync)
344 345
			base_arg_index = 1;

346
		var args = expr.get_argument_list ();
347 348
		Expression name = args.get (base_arg_index + 0);
		Expression object_path = args.get (base_arg_index + 1);
349 350
		Expression flags = args.get (base_arg_index + 2);
		Expression cancellable = args.get (base_arg_index + 3);
351 352 353 354

		// method can fail
		current_method_inner_error = true;

355 356 357 358 359 360
		CCodeFunctionCall ccall;
		if (bus_get_proxy_async || conn_get_proxy_async) {
			ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_async_initable_new_async"));
		} else {
			ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_initable_new"));
		}
361
		ccall.add_argument (proxy_type);
362 363 364 365
		if (bus_get_proxy_async || conn_get_proxy_async) {
			// I/O priority
			ccall.add_argument (new CCodeConstant ("0"));
		}
366
		ccall.add_argument (get_cvalue (cancellable));
367 368 369
		if (bus_get_proxy_async || conn_get_proxy_async) {
			if (expr.is_yield_expression) {
				// asynchronous call
370
				ccall.add_argument (new CCodeIdentifier (generate_ready_function (current_method)));
371
				ccall.add_argument (new CCodeIdentifier ("_data_"));
372 373 374 375 376
			} else {
				// begin
				Expression callback = args.get (base_arg_index + 4);
				ccall.add_argument (get_cvalue (callback));
				ccall.add_argument (get_delegate_target (callback));
377 378
			}
		} else {
379
			ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
380
		}
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 387
			Expression bus_type = args.get (0);
			ccall.add_argument (new CCodeConstant ("\"g-bus-type\""));
388
			ccall.add_argument (get_cvalue (bus_type));
389
		} else {
390 391 392 393 394
			Expression connection = ma.inner;
			if (ma.member_name == "begin" && ma.inner.symbol_reference == ma.symbol_reference) {
				var inner_ma = (MemberAccess) ma.inner;
				connection = inner_ma.inner;
			}
395
			ccall.add_argument (new CCodeConstant ("\"g-connection\""));
396
			ccall.add_argument (get_cvalue (connection));
397
		}
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 403 404 405
		if (dbus_iface_info != null) {
			ccall.add_argument (new CCodeConstant ("\"g-interface-info\""));
			ccall.add_argument (dbus_iface_info);
		}
406
		ccall.add_argument (new CCodeConstant ("NULL"));
407 408 409

		if (bus_get_proxy_async || conn_get_proxy_async) {
			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 414 415 416 417
				ccode.add_expression (ccall);
				ccode.add_return (new CCodeConstant ("FALSE"));
				ccode.add_label ("_state_%d".printf (state));

				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 423 424 425
			} else {
				// begin
				ccode.add_expression (ccall);
				return;
426 427 428
			}
		}

429 430 431 432 433
		var temp_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
		var temp_ref = get_variable_cexpression (temp_var.name);

		emit_temp_var (temp_var);

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 442

		var function = new CCodeFunction (wrapper_name);
		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 451 452

		var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
		iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_iter")));
		iter_init.add_argument (new CCodeIdentifier ("parameters"));
453
		ccode.add_expression (iter_init);
454 455 456

		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
		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);
Jürg Billeter's avatar
Jürg Billeter committed
461
			var owned_type = param.variable_type.copy ();
462 463
			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)));
465

Jürg Billeter's avatar
Jürg Billeter committed
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));
471 472
			}

Jürg Billeter's avatar
Jürg Billeter committed
473 474
			if (param.variable_type is ArrayType) {
				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_parameter_array_length_cname (param, dim);
479

480
					ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
481 482 483 484
					ccall.add_argument (new CCodeIdentifier (length_cname));
				}
			}

485
			read_expression (param.variable_type, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param_name), param);
486 487 488 489
		}

		ccode.add_expression (ccall);

490
		foreach (Parameter param in sig.get_parameters ()) {
491 492
			var owned_type = param.variable_type.copy ();
			owned_type.value_owned = true;
493 494 495 496

			if (requires_destroy (owned_type)) {
				// keep local alive (symbol_reference is weak)
				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 507 508 509

		return wrapper_name;
	}

	void generate_signal_handler_function (ObjectTypeSymbol sym) {
510
		var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "proxy_g_signal", "void");
511 512 513 514
		cfunc.add_parameter (new CCodeParameter ("proxy", "GDBusProxy*"));
		cfunc.add_parameter (new CCodeParameter ("sender_name", "const gchar*"));
		cfunc.add_parameter (new CCodeParameter ("signal_name", "const gchar*"));
		cfunc.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
515 516 517

		cfunc.modifiers |= CCodeModifiers.STATIC;

518
		cfile.add_function_declaration (cfunc);
519

520
		push_function (cfunc);
521

522
		bool firstif = true;
523 524 525 526 527 528

		foreach (Signal sig in sym.get_signals ()) {
			if (sig.access != SymbolAccessibility.PUBLIC) {
				continue;
			}

529 530
			cfile.add_include ("string.h");

531 532 533 534
			var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
			ccheck.add_argument (new CCodeIdentifier ("signal_name"));
			ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));

535 536 537 538 539 540
			var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0"));
			if (firstif) {
				ccode.open_if (cond);
				firstif = false;
			} else {
				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 546
			ccall.add_argument (new CCodeIdentifier ("parameters"));

547 548 549 550
			ccode.add_expression (ccall);
		}
		if (!firstif) {
			ccode.close ();
551 552
		}

553 554
		pop_function ();

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 565 566
		bool uses_fd = dbus_method_uses_file_descriptor (m);
		if (uses_fd) {
			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 572 573 574 575 576 577
		CCodeExpression error_argument;
		if (has_error_argument) {
			error_argument = new CCodeIdentifier ("error");
		} else {
			error_argument = new CCodeConstant ("NULL");
		}

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 589 590 591 592 593 594
			CCodeExpression timeout;
			if (method_timeout <= 0) {
				timeout = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_default_timeout"));
				((CCodeFunctionCall) timeout).add_argument (gdbusproxy);
			} else {
				timeout = new CCodeConstant ("%d".printf (method_timeout));
			}
595

596
			// register errors
597 598 599
			var error_types = new ArrayList<DataType> ();
			m.get_error_types (error_types);
			foreach (var error_type in error_types) {
600 601
				var errtype = (ErrorType) error_type;
				if (errtype.error_domain != null) {
602
					ccode.add_expression (new CCodeIdentifier (get_ccode_upper_case_name (errtype.error_domain)));
603 604 605
				}
			}

606 607 608 609 610 611 612 613 614 615 616 617 618
			// build D-Bus message

			ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_message"));

			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_new_method_call"));
			ccall.add_argument (destination);
			ccall.add_argument (object_path);
			if (iface_name != null) {
				ccall.add_argument (new CCodeConstant ("\"%s\"".printf (iface_name)));
			} else {
				ccall.add_argument (interface_name);
			}
			ccall.add_argument (new CCodeConstant ("\"%s\"".printf (method_name)));
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 625 626
			var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
			builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
			builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
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 634
			CCodeExpression cancellable = new CCodeConstant ("NULL");

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 639
					if (param.variable_type.is_real_struct_type ()) {
						expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
640
					}
641

642 643 644 645 646
					if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") {
						cancellable = expr;
						continue;
					}

647 648 649 650 651
					if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.BusName") {
						// ignore BusName sender parameters
						continue;
					}

652
					send_dbus_value (param.variable_type, new CCodeIdentifier ("_arguments_builder"), expr, param);
653 654 655
				}
			}

656 657
			var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
			builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
658
			ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
659 660 661 662

			var set_body = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_body"));
			set_body.add_argument (new CCodeIdentifier ("_message"));
			set_body.add_argument (new CCodeIdentifier ("_arguments"));
663
			ccode.add_expression (set_body);
664

665 666 667 668 669
			if (uses_fd) {
				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_unix_fd_list"));
				ccall.add_argument (new CCodeIdentifier ("_message"));
				ccall.add_argument (new CCodeIdentifier ("_fd_list"));
				ccode.add_expression (ccall);
670

671 672 673 674
				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
				ccall.add_argument (new CCodeIdentifier ("_fd_list"));
				ccode.add_expression (ccall);
			}
675

676 677 678 679 680 681 682 683 684
			// send D-Bus message

			if (call_type == CallType.SYNC) {
				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_sync"));
				ccall.add_argument (connection);
				ccall.add_argument (new CCodeIdentifier ("_message"));
				ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
				ccall.add_argument (timeout);
				ccall.add_argument (new CCodeConstant ("NULL"));
685
				ccall.add_argument (cancellable);
686
				ccall.add_argument (error_argument);
687
				ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
688 689 690 691 692 693 694 695 696 697 698
			} else if (call_type == CallType.NO_REPLY) {
				var set_flags = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_flags"));
				set_flags.add_argument (new CCodeIdentifier ("_message"));
				set_flags.add_argument (new CCodeConstant ("G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED"));
				ccode.add_expression (set_flags);

				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message"));
				ccall.add_argument (connection);
				ccall.add_argument (new CCodeIdentifier ("_message"));
				ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
				ccall.add_argument (new CCodeConstant ("NULL"));
699
				ccall.add_argument (error_argument);
700 701 702 703 704 705 706 707
				ccode.add_expression (ccall);
			} else if (call_type == CallType.ASYNC) {
				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply"));
				ccall.add_argument (connection);
				ccall.add_argument (new CCodeIdentifier ("_message"));
				ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
				ccall.add_argument (timeout);
				ccall.add_argument (new CCodeConstant ("NULL"));
708
				ccall.add_argument (cancellable);
709

710 711
				CCodeFunctionCall res_wrapper = null;

712
				// use wrapper as source_object wouldn't be correct otherwise
713 714 715 716 717 718
				ccall.add_argument (new CCodeIdentifier (generate_async_callback_wrapper ()));
				res_wrapper = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new"));
				res_wrapper.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
				res_wrapper.add_argument (new CCodeConstant ("NULL"));
				res_wrapper.add_argument (new CCodeIdentifier ("_callback_"));
				res_wrapper.add_argument (new CCodeIdentifier ("_user_data_"));
719 720
				ccall.add_argument (res_wrapper);

721 722 723 724
				ccode.add_expression (ccall);
			}

			// free D-Bus message
725 726 727

			ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
			ccall.add_argument (new CCodeIdentifier ("_message"));
728
			ccode.add_expression (ccall);
729 730 731
		} else {
			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_finish"));
			ccall.add_argument (connection);
732 733

			// unwrap async result
734
			ccode.add_declaration ("GAsyncResult", new CCodeVariableDeclarator ("*_inner_res"));
735

736 737 738 739
			var inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer"));
			inner_res.add_argument (new CCodeCastExpression (new CCodeIdentifier ("_res_"), "GTask *"));
			inner_res.add_argument (new CCodeConstant ("NULL"));
			ccode.add_assignment (new CCodeIdentifier ("_inner_res"), inner_res);
740

741 742 743
			ccall.add_argument (new CCodeIdentifier ("_inner_res"));
			ccall.add_argument (error_argument);
			ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
744

745 746 747 748
			// _inner_res is guaranteed to be non-NULL, so just unref it
			var unref_inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
			unref_inner_res.add_argument (new CCodeIdentifier ("_inner_res"));
			ccode.add_expression (unref_inner_res);
749
		}
750

751
		if (call_type == CallType.SYNC || call_type == CallType.FINISH) {
752
			ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_reply_message"));
753

754 755 756 757 758 759
			var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
			unref_reply.add_argument (new CCodeIdentifier ("_reply_message"));

			// return on io error
			var reply_is_null = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply_message"));
			ccode.open_if (reply_is_null);
760
			return_default_value (m.return_type);
761
			ccode.close ();
762

763 764 765
			// return on remote error
			var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_to_gerror"));
			ccall.add_argument (new CCodeIdentifier ("_reply_message"));
766
			ccall.add_argument (error_argument);
767 768 769 770
			ccode.open_if (ccall);
			ccode.add_expression (unref_reply);
			return_default_value (m.return_type);
			ccode.close ();
771

772
			bool has_result = !(m.return_type is VoidType);
773

774 775
			if (uses_fd) {
				ccode.add_declaration ("gint", new CCodeVariableDeclarator.zero ("_fd_index", new CCodeConstant ("0")));
776
				ccode.add_declaration ("gint", new CCodeVariableDeclarator ("_fd"));
777
			}
778

779
			foreach (Parameter param in m.get_parameters ()) {
780
				if (param.direction == ParameterDirection.OUT) {
781 782 783 784 785 786 787 788 789 790
					has_result = true;
				}
			}

			if (has_result) {
				ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
				ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_reply_iter"));

				ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_get_body"));
				ccall.add_argument (new CCodeIdentifier ("_reply_message"));
791
				ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
792 793 794 795 796

				var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
				iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_iter")));
				iter_init.add_argument (new CCodeIdentifier ("_reply"));
				ccode.add_expression (iter_init);
797

798
				foreach (Parameter param in m.get_parameters ()) {
799
					if (param.direction == ParameterDirection.OUT) {
800
						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)));
801

802 803
						var array_type = param.variable_type as ArrayType;
						if (array_type != null) {
804
							var length_ctype = get_ccode_array_length_type (array_type);
805
							for (int dim = 1; dim <= array_type.rank; dim++) {
806
								ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_vala_%s_length%d".printf (param.name, dim), new CCodeConstant ("0")));
807
							}
808 809
						}

810
						var target = new CCodeIdentifier ("_vala_%s".printf (param.name));
811
						bool may_fail;
812 813

						receive_dbus_value (param.variable_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, param, error_argument, out may_fail);
814

815 816
						// TODO check that parameter is not NULL (out parameters are optional)
						// free value if parameter is NULL
817
						ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_variable_cname (param.name))), target);
818

819 820 821
						if (array_type != null) {
							for (int dim = 1; dim <= array_type.rank; dim++) {
								// TODO check that parameter is not NULL (out parameters are optional)
822
								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
							}
824
						}
825

826
						if (may_fail && has_error_argument) {
827 828 829 830 831
							ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error"))));
							ccode.add_expression (unref_reply);
							return_default_value (m.return_type);
							ccode.close ();
						}
832 833 834
					}
				}

835 836 837
				if (!(m.return_type is VoidType)) {
					if (m.return_type.is_real_non_null_struct_type ()) {
						var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
838
						receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, m);
839
					} else {
840
						ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator.zero ("_result", default_value_for_type (m.return_type, true)));
841

842 843
						var array_type = m.return_type as ArrayType;
						if (array_type != null) {
844
							var length_ctype = get_ccode_array_length_type (array_type);
845
							for (int dim = 1; dim <= array_type.rank; dim++) {
846
								ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
847
							}
848 849
						}

850 851
						bool may_fail;
						receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"), m, new CCodeIdentifier ("error"), out may_fail);
852

853 854 855
						if (array_type != null) {
							for (int dim = 1; dim <= array_type.rank; dim++) {
								// TODO check that parameter is not NULL (out parameters are optional)
856
								ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)));
857
							}
858
						}
859 860 861 862 863 864 865

						if (may_fail) {
							ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error"))));
							ccode.add_expression (unref_reply);
							return_default_value (m.return_type);
							ccode.close ();
						}
866 867 868 869
					}
				}
			}

870
			ccode.add_expression (unref_reply);
871

872
			if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
873
				ccode.add_return (new CCodeIdentifier ("_result"));
874
			}
875
		}
876 877 878
	}

	string generate_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
879
		string proxy_name = "%sproxy_%s".printf (get_ccode_lower_case_prefix (main_iface), m.name);
880 881 882 883 884 885 886 887

		string dbus_iface_name = get_dbus_name (iface);

		bool no_reply = is_dbus_no_reply (m);

		var function = new CCodeFunction (proxy_name);
		function.modifiers = CCodeModifiers.STATIC;

888
		var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
889 890 891

		generate_cparameters (m, cfile, cparam_map, function);

892
		push_function (function);
893

894
		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));
895 896

		pop_function ();
897

898
		cfile.add_function_declaration (function);
899
		cfile.add_function (function);
900 901 902 903 904

		return proxy_name;
	}

	string generate_async_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
905
		string proxy_name = "%sproxy_%s_async".printf (get_ccode_lower_case_prefix (main_iface), m.name);
906 907 908 909 910 911

		string dbus_iface_name = get_dbus_name (iface);

		var function = new CCodeFunction (proxy_name, "void");
		function.modifiers = CCodeModifiers.STATIC;

912
		var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
913

914 915
		cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback"));
		cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer"));
916

917
		generate_cparameters (m, cfile, cparam_map, function, null, null, null, 1);
918

919
		push_function (function);
920

921
		generate_marshalling (m, CallType.ASYNC, dbus_iface_name, get_dbus_name_for_member (m), get_dbus_timeout_for_member (m));
922 923

		pop_function ();
924

925
		cfile.add_function_declaration (function);
926
		cfile.add_function (function);
927 928 929 930 931

		return proxy_name;
	}

	string generate_finish_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
932
		string proxy_name = "%sproxy_%s_finish".printf (get_ccode_lower_case_prefix (main_iface), m.name);
933 934 935 936

		var function = new CCodeFunction (proxy_name);
		function.modifiers = CCodeModifiers.STATIC;

937
		var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
938

939
		cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
940

941
		generate_cparameters (m, cfile, cparam_map, function, null, null, null, 2);
942

943
		push_function (function);
944

945
		generate_marshalling (m, CallType.FINISH, null, null, -1);
946 947

		pop_function ();
948

949
		cfile.add_function_declaration (function);
950
		cfile.add_function (function);
951 952 953 954 955

		return proxy_name;
	}

	string generate_dbus_proxy_property_get (Interface main_iface, Interface iface, Property prop) {
956
		string proxy_name = "%sdbus_proxy_get_%s".printf (get_ccode_lower_case_prefix (main_iface), prop.name);
957 958 959 960 961 962 963 964 965 966 967 968 969 970

		string dbus_iface_name = get_dbus_name (iface);

		var owned_type = prop.get_accessor.value_type.copy ();
		owned_type.value_owned = true;
		if (owned_type.is_disposable () && !prop.get_accessor.value_type.value_owned) {
			Report.error (prop.get_accessor.value_type.source_reference, "Properties used in D-Bus clients require owned get accessor");
		}

		var array_type = prop.get_accessor.value_type as ArrayType;

		var function = new CCodeFunction (proxy_name);
		function.modifiers = CCodeModifiers.STATIC;

971
		function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface))));
972 973

		if (prop.property_type.is_real_non_null_struct_type ()) {
974
			function.add_parameter (new CCodeParameter ("result", "%s*".printf (get_ccode_name (prop.get_accessor.value_type))));
975 976
		} else {
			if (array_type != null) {
977
				var length_ctype = get_ccode_array_length_type (array_type) + "*";
978
				for (int dim = 1; dim <= array_type.rank; dim++) {
979
					function.add_parameter (new CCodeParameter ("result_length%d".printf (dim), length_ctype));
980 981 982
				}
			}

983
			function.return_type = get_ccode_name (prop.get_accessor.value_type);
984 985
		}

986
		push_function (function);
987

988
		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_inner_reply"));
989

990 991 992 993
		// first try cached value
		var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_cached_property"));
		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
		ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
994
		ccode.add_assignment (new CCodeIdentifier ("_inner_reply"), ccall);
995 996 997 998 999 1000

		// if not successful, retrieve value via D-Bus
		ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_inner_reply")));

		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
1001
		ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
1002 1003 1004 1005

		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
1006
		ccode.add_expression (builder_init);
1007 1008

		// interface name
1009
		write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
1010
		// property name
1011
		write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
1012 1013 1014

		var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
		builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
1015
		ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
1016

1017
		ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
1018 1019 1020 1021 1022 1023 1024 1025
		ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
		ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Get\""));
		ccall.add_argument (new CCodeIdentifier ("_arguments"));
		ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
		ccall.add_argument (get_dbus_timeout (prop));
		ccall.add_argument (new CCodeConstant ("NULL"));
		ccall.add_argument (new CCodeConstant ("NULL"));

1026
		ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
1027 1028 1029

		// return on error
		ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")));
1030
		return_default_value (prop.property_type);
1031
		ccode.close ();
1032

1033
		var get_variant = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get"));
1034
		get_variant.add_argument (new CCodeIdentifier ("_reply"));
1035 1036 1037
		get_variant.add_argument (new CCodeConstant ("\"(v)\""));
		get_variant.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_inner_reply")));
		ccode.add_expression (get_variant);
1038

1039 1040 1041 1042 1043
		var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
		unref_reply.add_argument (new CCodeIdentifier ("_reply"));
		ccode.add_expression (unref_reply);

		ccode.close ();
1044 1045 1046

		if (prop.property_type.is_real_non_null_struct_type ()) {
			var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
1047
			var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), target);
1048
			ccode.add_assignment (target, result);
1049
		} else {
1050
			ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator ("_result"));
1051

1052 1053 1054 1055 1056
			if (get_dbus_signature (prop) != null) {
				// raw GVariant
				ccode.add_assignment (new CCodeIdentifier ("_result"), new CCodeIdentifier("_inner_reply"));
			} else {
				if (array_type != null) {
1057
					var length_ctype = get_ccode_array_length_type (array_type);
1058
					for (int dim = 1; dim <= array_type.rank; dim++) {
1059
						ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
1060
					}
1061 1062
				}

1063 1064
				var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), new CCodeIdentifier ("_result"));
				ccode.add_assignment (new CCodeIdentifier ("_result"), result);
1065

1066 1067 1068 1069 1070
				if (array_type != null) {
					for (int dim = 1; dim <= array_type.rank; dim++) {
						// TODO check that parameter is not NULL (out parameters are optional)
						ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)));
					}
1071 1072 1073 1074
				}
			}
		}

1075 1076 1077 1078 1079
		if (prop.property_type.is_real_non_null_struct_type () || get_dbus_signature (prop) == null) {
			unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
			unref_reply.add_argument (new CCodeIdentifier ("_inner_reply"));
			ccode.add_expression (unref_reply);
		}
1080 1081

		if (prop.property_type.is_real_non_null_struct_type ()) {
1082
			ccode.add_return ();
1083
		} else {
1084
			ccode.add_return (new CCodeIdentifier ("_result"));
1085 1086
		}

1087 1088
		pop_function ();

1089
		cfile.add_function_declaration (function);
1090
		cfile.add_function (function);
1091 1092 1093 1094 1095

		return proxy_name;
	}

	string generate_dbus_proxy_property_set (Interface main_iface, Interface iface, Property prop) {
1096
		string proxy_name = "%sdbus_proxy_set_%s".printf (get_ccode_lower_case_prefix (main_iface), prop.name);
1097 1098 1099 1100 1101 1102 1103 1104

		string dbus_iface_name = get_dbus_name (iface);

		var array_type = prop.set_accessor.value_type as ArrayType;

		var function = new CCodeFunction (proxy_name);
		function.modifiers = CCodeModifiers.STATIC;

1105
		function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface))));
1106 1107

		if (prop.property_type.is_real_non_null_struct_type ()) {
1108
			function.add_parameter (new CCodeParameter ("value", "%s*".printf (get_ccode_name (prop.set_accessor.value_type))));
1109
		} else {
1110
			function.add_parameter (new CCodeParameter ("value", get_ccode_name (prop.set_accessor.value_type)));
1111 1112

			if (array_type != null) {
1113
				var length_ctype = get_ccode_array_length_type (array_type);
1114
				for (int dim = 1; dim <= array_type.rank; dim++) {
1115
					function.add_parameter (new CCodeParameter ("value_length%d".printf (dim), length_ctype));
1116 1117 1118 1119
				}
			}
		}

1120
		push_function (function);
1121

1122 1123
		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
		ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
1124

1125
		ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
1126 1127 1128 1129

		var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
		builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
		builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
1130
		ccode.add_expression (builder_init);
Jürg Billeter's avatar