Move source file adding logic to CodeContext
[vala-lang.git] / codegen / valagdbusclientmodule.vala
blob4ce19b490195e4ad9d01de689bcc77ffedd83270
1 /* valagdbusclientmodule.vala
3 * Copyright (C) 2010 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 public CCodeConstant get_dbus_timeout (Symbol symbol) {
26 int timeout = -1;
28 var dbus = symbol.get_attribute ("DBus");
29 if (dbus != null && dbus.has_argument ("timeout")) {
30 timeout = dbus.get_integer ("timeout");
31 } else if (symbol.parent_symbol != null) {
32 return get_dbus_timeout (symbol.parent_symbol);
35 return new CCodeConstant (timeout.to_string ());
38 public override void generate_dynamic_method_wrapper (DynamicMethod method) {
39 var dynamic_method = (DynamicMethod) method;
41 var func = new CCodeFunction (method.get_cname ());
42 func.modifiers = CCodeModifiers.STATIC;
44 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
46 generate_cparameters (method, cfile, cparam_map, func);
48 var block = new CCodeBlock ();
49 if (dynamic_method.dynamic_type.data_type == dbus_proxy_type) {
50 generate_dbus_method_wrapper (method, block);
51 } else {
52 Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ()));
55 // append to C source file
56 cfile.add_function_declaration (func);
58 func.block = block;
59 cfile.add_function (func);
62 void generate_dbus_method_wrapper (Method m, CCodeBlock block) {
63 var prefragment = new CCodeFragment ();
64 var postfragment = new CCodeFragment ();
66 var cdecl = new CCodeDeclaration ("GVariant");
67 cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
68 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
69 block.add_statement (cdecl);
71 generate_marshalling (m, prefragment, postfragment);
73 block.add_statement (prefragment);
75 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
76 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
77 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (m.name)));
78 ccall.add_argument (new CCodeIdentifier ("_arguments"));
79 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
80 ccall.add_argument (get_dbus_timeout (m));
81 ccall.add_argument (new CCodeConstant ("NULL"));
82 ccall.add_argument (new CCodeConstant ("error"));
83 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
85 // return on error
86 var error_block = new CCodeBlock ();
87 if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
88 error_block.add_statement (new CCodeReturnStatement ());
89 } else {
90 error_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
92 block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
94 block.add_statement (postfragment);
96 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
97 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
98 block.add_statement (new CCodeExpressionStatement (unref_reply));
100 if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
101 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
105 void generate_proxy_interface_init (Interface main_iface, Interface iface) {
106 // also generate proxy for prerequisites
107 foreach (var prereq in iface.get_prerequisites ()) {
108 if (prereq.data_type is Interface) {
109 generate_proxy_interface_init (main_iface, (Interface) prereq.data_type);
113 string lower_cname = main_iface.get_lower_case_cprefix () + "proxy";
115 var proxy_iface_init = new CCodeFunction (lower_cname + "_" + iface.get_lower_case_cprefix () + "interface_init", "void");
116 proxy_iface_init.add_parameter (new CCodeFormalParameter ("iface", iface.get_cname () + "Iface*"));
118 var iface_block = new CCodeBlock ();
120 foreach (Method m in iface.get_methods ()) {
121 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.vfunc_name);
122 if (!m.coroutine) {
123 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (main_iface, iface, m)))));
124 } else {
125 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_async_dbus_proxy_method (main_iface, iface, m)))));
126 vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.get_finish_vfunc_name ());
127 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_finish_dbus_proxy_method (main_iface, iface, m)))));
131 foreach (Property prop in iface.get_properties ()) {
132 if (prop.get_accessor != null) {
133 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "get_" + prop.name);
134 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_get (main_iface, iface, prop)))));
136 if (prop.set_accessor != null) {
137 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "set_" + prop.name);
138 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_set (main_iface, iface, prop)))));
142 proxy_iface_init.modifiers = CCodeModifiers.STATIC;
143 cfile.add_function_declaration (proxy_iface_init);
144 proxy_iface_init.block = iface_block;
145 cfile.add_function (proxy_iface_init);
148 string implement_interface (CCodeFunctionCall define_type, Interface main_iface, Interface iface) {
149 string result = "";
151 // also implement prerequisites
152 foreach (var prereq in iface.get_prerequisites ()) {
153 if (prereq.data_type is Interface) {
154 result += implement_interface (define_type, main_iface, (Interface) prereq.data_type);
158 result += "G_IMPLEMENT_INTERFACE (%s, %sproxy_%sinterface_init) ".printf (
159 iface.get_upper_case_cname ("TYPE_"),
160 main_iface.get_lower_case_cprefix (),
161 iface.get_lower_case_cprefix ());
162 return result;
165 public override void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
166 base.generate_interface_declaration (iface, decl_space);
168 string dbus_iface_name = get_dbus_name (iface);
169 if (dbus_iface_name == null) {
170 return;
173 string get_type_name = "%sproxy_get_type".printf (iface.get_lower_case_cprefix ());
175 if (add_symbol_declaration (decl_space, iface, get_type_name)) {
176 return;
179 decl_space.add_type_declaration (new CCodeNewline ());
180 var macro = "(%s ())".printf (get_type_name);
181 decl_space.add_type_declaration (new CCodeMacroReplacement ("%s_PROXY".printf (iface.get_type_id ()), macro));
183 // declare proxy_get_type function
184 var proxy_get_type = new CCodeFunction (get_type_name, "GType");
185 proxy_get_type.attributes = "G_GNUC_CONST";
186 decl_space.add_function_declaration (proxy_get_type);
189 public override void visit_interface (Interface iface) {
190 base.visit_interface (iface);
192 string dbus_iface_name = get_dbus_name (iface);
193 if (dbus_iface_name == null) {
194 return;
197 cfile.add_include ("gio/gio.h");
199 // create proxy class
200 string cname = iface.get_cname () + "Proxy";
201 string lower_cname = iface.get_lower_case_cprefix () + "proxy";
203 cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxy", new CCodeVariableDeclarator (cname)));
204 cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxyClass", new CCodeVariableDeclarator (cname + "Class")));
206 var define_type = new CCodeFunctionCall (new CCodeIdentifier ("G_DEFINE_TYPE_EXTENDED"));
207 define_type.add_argument (new CCodeIdentifier (cname));
208 define_type.add_argument (new CCodeIdentifier (lower_cname));
209 define_type.add_argument (new CCodeIdentifier ("G_TYPE_DBUS_PROXY"));
210 define_type.add_argument (new CCodeConstant ("0"));
211 define_type.add_argument (new CCodeIdentifier (implement_interface (define_type, iface, iface)));
213 cfile.add_type_member_definition (new CCodeExpressionStatement (define_type));
215 var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void");
216 proxy_class_init.add_parameter (new CCodeFormalParameter ("klass", cname + "Class*"));
217 proxy_class_init.modifiers = CCodeModifiers.STATIC;
218 proxy_class_init.block = new CCodeBlock ();
219 var proxy_class = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY_CLASS"));
220 proxy_class.add_argument (new CCodeIdentifier ("klass"));
221 proxy_class_init.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (proxy_class, "g_signal"), new CCodeIdentifier (lower_cname + "_g_signal"))));
222 cfile.add_function (proxy_class_init);
224 generate_signal_handler_function (iface);
226 var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void");
227 proxy_instance_init.add_parameter (new CCodeFormalParameter ("self", cname + "*"));
228 proxy_instance_init.modifiers = CCodeModifiers.STATIC;
229 proxy_instance_init.block = new CCodeBlock ();
230 cfile.add_function (proxy_instance_init);
232 generate_proxy_interface_init (iface, iface);
235 public override void visit_method_call (MethodCall expr) {
236 var mtype = expr.call.value_type as MethodType;
237 bool bus_get_proxy_sync = (mtype != null && mtype.method_symbol.get_cname () == "g_bus_get_proxy_sync");
238 bool conn_get_proxy_sync = (mtype != null && mtype.method_symbol.get_cname () == "g_dbus_connection_get_proxy_sync");
239 if (!bus_get_proxy_sync && !conn_get_proxy_sync) {
240 base.visit_method_call (expr);
241 return;
244 var ma = (MemberAccess) expr.call;
245 var type_arg = (ObjectType) ma.get_type_arguments ().get (0);
246 var iface = (Interface) type_arg.type_symbol;
248 string dbus_iface_name = get_dbus_name (iface);
249 if (dbus_iface_name == null) {
250 Report.error (expr.source_reference, "`%s' is not a D-Bus interface".printf (iface.get_full_name ()));
251 return;
254 var base_arg_index = 0;
255 if (bus_get_proxy_sync)
256 base_arg_index = 1;
258 var args = expr.get_argument_list ();
259 Expression name = args.get (base_arg_index + 0);
260 Expression object_path = args.get (base_arg_index + 1);
261 Expression cancellable = args.get (base_arg_index + 2);
263 // method can fail
264 current_method_inner_error = true;
266 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_initable_new"));
267 ccall.add_argument (new CCodeIdentifier ("%s_PROXY".printf (iface.get_type_id ())));
268 cancellable.emit (this);
269 ccall.add_argument ((CCodeExpression) cancellable.ccodenode);
270 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
271 ccall.add_argument (new CCodeConstant ("\"g-flags\""));
272 ccall.add_argument (new CCodeConstant ("G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES"));
273 ccall.add_argument (new CCodeConstant ("\"g-name\""));
274 name.emit (this);
275 ccall.add_argument ((CCodeExpression) name.ccodenode);
276 if (bus_get_proxy_sync) {
277 Expression bus_type = args.get (0);
278 ccall.add_argument (new CCodeConstant ("\"g-bus-type\""));
279 bus_type.emit (this);
280 ccall.add_argument ((CCodeExpression) bus_type.ccodenode);
281 } else {
282 Expression connection = ((MemberAccess) expr.call).inner;
283 ccall.add_argument (new CCodeConstant ("\"g-connection\""));
284 connection.emit (this);
285 ccall.add_argument ((CCodeExpression) connection.ccodenode);
287 ccall.add_argument (new CCodeConstant ("\"g-object-path\""));
288 object_path.emit (this);
289 ccall.add_argument ((CCodeExpression) object_path.ccodenode);
290 ccall.add_argument (new CCodeConstant ("\"g-interface-name\""));
291 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name (iface))));
292 ccall.add_argument (new CCodeConstant ("NULL"));
293 expr.ccodenode = ccall;
296 string generate_dbus_signal_handler (Signal sig, ObjectTypeSymbol sym) {
297 string wrapper_name = "_dbus_handle_%s_%s".printf (sym.get_lower_case_cname (), sig.get_cname ());
299 // declaration
301 CCodeDeclaration cdecl;
303 var function = new CCodeFunction (wrapper_name);
304 function.modifiers = CCodeModifiers.STATIC;
305 function.add_parameter (new CCodeFormalParameter ("self", sym.get_cname () + "*"));
306 function.add_parameter (new CCodeFormalParameter ("parameters", "GVariant*"));
307 var block = new CCodeBlock ();
309 var prefragment = new CCodeFragment ();
310 var postfragment = new CCodeFragment ();
312 block.add_statement (prefragment);
314 cdecl = new CCodeDeclaration ("GVariantIter");
315 cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_iter"));
316 block.add_statement (cdecl);
318 var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
319 iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_iter")));
320 iter_init.add_argument (new CCodeIdentifier ("parameters"));
321 prefragment.append (new CCodeExpressionStatement (iter_init));
323 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
324 ccall.add_argument (new CCodeIdentifier ("self"));
325 ccall.add_argument (sig.get_canonical_cconstant ());
327 foreach (FormalParameter param in sig.get_parameters ()) {
328 var owned_type = param.variable_type.copy ();
329 owned_type.value_owned = true;
331 cdecl = new CCodeDeclaration (owned_type.get_cname ());
332 cdecl.add_declarator (new CCodeVariableDeclarator.zero (param.name, default_value_for_type (param.variable_type, true)));
333 prefragment.append (cdecl);
335 var st = param.variable_type.data_type as Struct;
336 if (st != null && !st.is_simple_type ()) {
337 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
338 } else {
339 ccall.add_argument (new CCodeIdentifier (param.name));
342 if (param.variable_type is ArrayType) {
343 var array_type = (ArrayType) param.variable_type;
345 for (int dim = 1; dim <= array_type.rank; dim++) {
346 string length_cname = get_parameter_array_length_cname (param, dim);
348 cdecl = new CCodeDeclaration ("int");
349 cdecl.add_declarator (new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
350 prefragment.append (cdecl);
351 ccall.add_argument (new CCodeIdentifier (length_cname));
355 read_expression (prefragment, param.variable_type, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param.name), param);
357 if (requires_destroy (owned_type)) {
358 // keep local alive (symbol_reference is weak)
359 var local = new LocalVariable (owned_type, param.name);
360 var ma = new MemberAccess.simple (param.name);
361 ma.symbol_reference = local;
362 var stmt = new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (param.name), owned_type, ma));
363 postfragment.append (stmt);
367 block.add_statement (new CCodeExpressionStatement (ccall));
369 block.add_statement (postfragment);
371 cfile.add_function_declaration (function);
373 function.block = block;
374 cfile.add_function (function);
376 return wrapper_name;
379 void generate_signal_handler_function (ObjectTypeSymbol sym) {
380 var cfunc = new CCodeFunction (sym.get_lower_case_cprefix () + "proxy_g_signal", "void");
381 cfunc.add_parameter (new CCodeFormalParameter ("proxy", "GDBusProxy*"));
382 cfunc.add_parameter (new CCodeFormalParameter ("sender_name", "const gchar*"));
383 cfunc.add_parameter (new CCodeFormalParameter ("signal_name", "const gchar*"));
384 cfunc.add_parameter (new CCodeFormalParameter ("parameters", "GVariant*"));
386 cfunc.modifiers |= CCodeModifiers.STATIC;
388 cfile.add_function_declaration (cfunc);
390 var block = new CCodeBlock ();
391 cfunc.block = block;
393 CCodeIfStatement clastif = null;
395 foreach (Signal sig in sym.get_signals ()) {
396 if (sig.access != SymbolAccessibility.PUBLIC) {
397 continue;
400 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
401 ccheck.add_argument (new CCodeIdentifier ("signal_name"));
402 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
404 var callblock = new CCodeBlock ();
406 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_signal_handler (sig, sym)));
407 ccall.add_argument (new CCodeIdentifier ("proxy"));
408 ccall.add_argument (new CCodeIdentifier ("parameters"));
410 callblock.add_statement (new CCodeExpressionStatement (ccall));
412 var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")), callblock);
413 if (clastif == null) {
414 block.add_statement (cif);
415 } else {
416 clastif.false_statement = cif;
419 clastif = cif;
422 cfile.add_function (cfunc);
425 void generate_marshalling (Method m, CCodeFragment prefragment, CCodeFragment postfragment) {
426 CCodeDeclaration cdecl;
428 cdecl = new CCodeDeclaration ("GVariantBuilder");
429 cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_builder"));
430 prefragment.append (cdecl);
432 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
433 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
434 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
435 prefragment.append (new CCodeExpressionStatement (builder_init));
437 cdecl = new CCodeDeclaration ("GVariantIter");
438 cdecl.add_declarator (new CCodeVariableDeclarator ("_reply_iter"));
439 postfragment.append (cdecl);
441 var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
442 iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_iter")));
443 iter_init.add_argument (new CCodeIdentifier ("_reply"));
444 postfragment.append (new CCodeExpressionStatement (iter_init));
446 foreach (FormalParameter param in m.get_parameters ()) {
447 if (param.direction == ParameterDirection.IN) {
448 CCodeExpression expr = new CCodeIdentifier (param.name);
449 if (param.variable_type.is_real_struct_type ()) {
450 expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
452 write_expression (prefragment, param.variable_type, new CCodeIdentifier ("_arguments_builder"), expr, param);
453 } else {
454 cdecl = new CCodeDeclaration (param.variable_type.get_cname ());
455 cdecl.add_declarator (new CCodeVariableDeclarator ("_" + param.name));
456 postfragment.append (cdecl);
458 var array_type = param.variable_type as ArrayType;
460 if (array_type != null) {
461 for (int dim = 1; dim <= array_type.rank; dim++) {
462 cdecl = new CCodeDeclaration ("int");
463 cdecl.add_declarator (new CCodeVariableDeclarator ("_%s_length%d".printf (param.name, dim), new CCodeConstant ("0")));
464 postfragment.append (cdecl);
468 var target = new CCodeIdentifier ("_" + param.name);
469 read_expression (postfragment, param.variable_type, new CCodeIdentifier ("_reply_iter"), target, param);
471 // TODO check that parameter is not NULL (out parameters are optional)
472 // free value if parameter is NULL
473 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), target)));
475 if (array_type != null) {
476 for (int dim = 1; dim <= array_type.rank; dim++) {
477 // TODO check that parameter is not NULL (out parameters are optional)
478 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("%s_length%d".printf (param.name, dim))), new CCodeIdentifier ("_%s_length%d".printf (param.name, dim)))));
484 if (!(m.return_type is VoidType)) {
485 if (m.return_type.is_real_non_null_struct_type ()) {
486 var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
487 read_expression (postfragment, m.return_type, new CCodeIdentifier ("_reply_iter"), target, m);
488 } else {
489 cdecl = new CCodeDeclaration (m.return_type.get_cname ());
490 cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
491 postfragment.append (cdecl);
493 var array_type = m.return_type as ArrayType;
495 if (array_type != null) {
496 for (int dim = 1; dim <= array_type.rank; dim++) {
497 cdecl = new CCodeDeclaration ("int");
498 cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
499 postfragment.append (cdecl);
503 read_expression (postfragment, m.return_type, new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"), m);
505 if (array_type != null) {
506 for (int dim = 1; dim <= array_type.rank; dim++) {
507 // TODO check that parameter is not NULL (out parameters are optional)
508 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)))));
514 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
515 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
516 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_arguments"), builder_end)));
519 string generate_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
520 string proxy_name = "%sproxy_%s".printf (main_iface.get_lower_case_cprefix (), m.name);
522 string dbus_iface_name = get_dbus_name (iface);
524 CCodeDeclaration cdecl;
526 var function = new CCodeFunction (proxy_name);
527 function.modifiers = CCodeModifiers.STATIC;
529 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
531 generate_cparameters (m, cfile, cparam_map, function);
533 var block = new CCodeBlock ();
534 var prefragment = new CCodeFragment ();
535 var postfragment = new CCodeFragment ();
537 cdecl = new CCodeDeclaration ("GVariant");
538 cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
539 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
540 block.add_statement (cdecl);
542 generate_marshalling (m, prefragment, postfragment);
544 block.add_statement (prefragment);
546 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
547 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
548 ccall.add_argument (new CCodeConstant ("\"%s.%s\"".printf (dbus_iface_name, get_dbus_name_for_member (m))));
549 ccall.add_argument (new CCodeIdentifier ("_arguments"));
550 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
551 ccall.add_argument (get_dbus_timeout (m));
552 ccall.add_argument (new CCodeConstant ("NULL"));
553 ccall.add_argument (new CCodeConstant ("error"));
554 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
556 // return on error
557 var error_block = new CCodeBlock ();
558 if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
559 error_block.add_statement (new CCodeReturnStatement ());
560 } else {
561 error_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
563 block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
565 block.add_statement (postfragment);
567 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
568 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
569 block.add_statement (new CCodeExpressionStatement (unref_reply));
571 if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
572 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
575 cfile.add_function_declaration (function);
576 function.block = block;
577 cfile.add_function (function);
579 return proxy_name;
582 string generate_async_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
583 string proxy_name = "%sproxy_%s_async".printf (main_iface.get_lower_case_cprefix (), m.name);
585 string dbus_iface_name = get_dbus_name (iface);
587 CCodeDeclaration cdecl;
589 var function = new CCodeFunction (proxy_name, "void");
590 function.modifiers = CCodeModifiers.STATIC;
592 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
594 cparam_map.set (get_param_pos (-1), new CCodeFormalParameter ("_callback_", "GAsyncReadyCallback"));
595 cparam_map.set (get_param_pos (-0.9), new CCodeFormalParameter ("_user_data_", "gpointer"));
597 generate_cparameters (m, cfile, cparam_map, function, null, null, null, 1);
599 var block = new CCodeBlock ();
600 var prefragment = new CCodeFragment ();
601 var postfragment = new CCodeFragment ();
603 cdecl = new CCodeDeclaration ("GVariant");
604 cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
605 block.add_statement (cdecl);
607 generate_marshalling (m, prefragment, postfragment);
609 block.add_statement (prefragment);
611 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call"));
612 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
613 ccall.add_argument (new CCodeConstant ("\"%s.%s\"".printf (dbus_iface_name, get_dbus_name_for_member (m))));
614 ccall.add_argument (new CCodeIdentifier ("_arguments"));
615 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
616 ccall.add_argument (get_dbus_timeout (m));
617 ccall.add_argument (new CCodeConstant ("NULL"));
618 ccall.add_argument (new CCodeIdentifier ("_callback_"));
619 ccall.add_argument (new CCodeIdentifier ("_user_data_"));
620 block.add_statement (new CCodeExpressionStatement (ccall));
622 cfile.add_function_declaration (function);
623 function.block = block;
624 cfile.add_function (function);
626 return proxy_name;
629 string generate_finish_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
630 string proxy_name = "%sproxy_%s_finish".printf (main_iface.get_lower_case_cprefix (), m.name);
632 CCodeDeclaration cdecl;
634 var function = new CCodeFunction (proxy_name);
635 function.modifiers = CCodeModifiers.STATIC;
637 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
639 cparam_map.set (get_param_pos (0.1), new CCodeFormalParameter ("_res_", "GAsyncResult*"));
641 generate_cparameters (m, cfile, cparam_map, function, null, null, null, 2);
643 var block = new CCodeBlock ();
644 var prefragment = new CCodeFragment ();
645 var postfragment = new CCodeFragment ();
647 cdecl = new CCodeDeclaration ("GVariant");
648 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
649 block.add_statement (cdecl);
651 generate_marshalling (m, prefragment, postfragment);
653 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_finish"));
654 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
655 ccall.add_argument (new CCodeIdentifier ("_res_"));
656 ccall.add_argument (new CCodeConstant ("error"));
657 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
659 // return on error
660 var error_block = new CCodeBlock ();
661 if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
662 error_block.add_statement (new CCodeReturnStatement ());
663 } else {
664 error_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
666 block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
668 block.add_statement (postfragment);
670 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
671 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
672 block.add_statement (new CCodeExpressionStatement (unref_reply));
674 if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
675 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
678 cfile.add_function_declaration (function);
679 function.block = block;
680 cfile.add_function (function);
682 return proxy_name;
685 string generate_dbus_proxy_property_get (Interface main_iface, Interface iface, Property prop) {
686 string proxy_name = "%sdbus_proxy_get_%s".printf (main_iface.get_lower_case_cprefix (), prop.name);
688 string dbus_iface_name = get_dbus_name (iface);
690 var owned_type = prop.get_accessor.value_type.copy ();
691 owned_type.value_owned = true;
692 if (owned_type.is_disposable () && !prop.get_accessor.value_type.value_owned) {
693 Report.error (prop.get_accessor.value_type.source_reference, "Properties used in D-Bus clients require owned get accessor");
696 var array_type = prop.get_accessor.value_type as ArrayType;
698 CCodeDeclaration cdecl;
700 var function = new CCodeFunction (proxy_name);
701 function.modifiers = CCodeModifiers.STATIC;
703 function.add_parameter (new CCodeFormalParameter ("self", "%s*".printf (iface.get_cname ())));
705 if (prop.property_type.is_real_non_null_struct_type ()) {
706 function.add_parameter (new CCodeFormalParameter ("result", "%s*".printf (prop.get_accessor.value_type.get_cname ())));
707 } else {
708 if (array_type != null) {
709 for (int dim = 1; dim <= array_type.rank; dim++) {
710 function.add_parameter (new CCodeFormalParameter ("result_length%d".printf (dim), "int*"));
714 function.return_type = prop.get_accessor.value_type.get_cname ();
717 var block = new CCodeBlock ();
718 var prefragment = new CCodeFragment ();
719 var postfragment = new CCodeFragment ();
721 cdecl = new CCodeDeclaration ("GVariant");
722 cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
723 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
724 cdecl.add_declarator (new CCodeVariableDeclarator ("*_inner_reply"));
725 block.add_statement (cdecl);
727 block.add_statement (prefragment);
729 cdecl = new CCodeDeclaration ("GVariantBuilder");
730 cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_builder"));
731 prefragment.append (cdecl);
733 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
734 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
735 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
736 prefragment.append (new CCodeExpressionStatement (builder_init));
738 // interface name
739 write_expression (prefragment, string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
740 // property name
741 write_expression (prefragment, string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
743 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
744 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
745 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_arguments"), builder_end)));
747 cdecl = new CCodeDeclaration ("GVariantIter");
748 cdecl.add_declarator (new CCodeVariableDeclarator ("_reply_iter"));
749 postfragment.append (cdecl);
751 var get_variant = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get_child_value"));
752 get_variant.add_argument (new CCodeIdentifier ("_reply"));
753 get_variant.add_argument (new CCodeConstant ("0"));
754 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_inner_reply"), get_variant)));
756 var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
757 iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_iter")));
758 iter_init.add_argument (new CCodeIdentifier ("_inner_reply"));
759 postfragment.append (new CCodeExpressionStatement (iter_init));
761 if (prop.property_type.is_real_non_null_struct_type ()) {
762 var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
763 read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_reply_iter"), target, prop);
764 } else {
765 cdecl = new CCodeDeclaration (prop.get_accessor.value_type.get_cname ());
766 cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
767 postfragment.append (cdecl);
769 if (array_type != null) {
770 for (int dim = 1; dim <= array_type.rank; dim++) {
771 cdecl = new CCodeDeclaration ("int");
772 cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
773 postfragment.append (cdecl);
777 read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"), prop);
779 if (array_type != null) {
780 for (int dim = 1; dim <= array_type.rank; dim++) {
781 // TODO check that parameter is not NULL (out parameters are optional)
782 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim)))));
787 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
788 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
789 ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Get\""));
790 ccall.add_argument (new CCodeIdentifier ("_arguments"));
791 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
792 ccall.add_argument (get_dbus_timeout (prop));
793 ccall.add_argument (new CCodeConstant ("NULL"));
794 ccall.add_argument (new CCodeConstant ("NULL"));
796 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
798 // return on error
799 var error_block = new CCodeBlock ();
800 if (prop.property_type.is_real_non_null_struct_type ()) {
801 error_block.add_statement (new CCodeReturnStatement ());
802 } else {
803 error_block.add_statement (new CCodeReturnStatement (default_value_for_type (prop.property_type, false)));
805 block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
807 block.add_statement (postfragment);
809 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
810 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
811 block.add_statement (new CCodeExpressionStatement (unref_reply));
813 if (prop.property_type.is_real_non_null_struct_type ()) {
814 block.add_statement (new CCodeReturnStatement ());
815 } else {
816 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
819 cfile.add_function_declaration (function);
820 function.block = block;
821 cfile.add_function (function);
823 return proxy_name;
826 string generate_dbus_proxy_property_set (Interface main_iface, Interface iface, Property prop) {
827 string proxy_name = "%sdbus_proxy_set_%s".printf (main_iface.get_lower_case_cprefix (), prop.name);
829 string dbus_iface_name = get_dbus_name (iface);
831 var array_type = prop.set_accessor.value_type as ArrayType;
833 CCodeDeclaration cdecl;
835 var function = new CCodeFunction (proxy_name);
836 function.modifiers = CCodeModifiers.STATIC;
838 function.add_parameter (new CCodeFormalParameter ("self", "%s*".printf (iface.get_cname ())));
840 if (prop.property_type.is_real_non_null_struct_type ()) {
841 function.add_parameter (new CCodeFormalParameter ("value", "%s*".printf (prop.set_accessor.value_type.get_cname ())));
842 } else {
843 function.add_parameter (new CCodeFormalParameter ("value", prop.set_accessor.value_type.get_cname ()));
845 if (array_type != null) {
846 for (int dim = 1; dim <= array_type.rank; dim++) {
847 function.add_parameter (new CCodeFormalParameter ("value_length%d".printf (dim), "int"));
852 var block = new CCodeBlock ();
853 var prefragment = new CCodeFragment ();
854 var postfragment = new CCodeFragment ();
856 cdecl = new CCodeDeclaration ("GVariant");
857 cdecl.add_declarator (new CCodeVariableDeclarator ("*_arguments"));
858 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
859 block.add_statement (cdecl);
861 block.add_statement (prefragment);
863 cdecl = new CCodeDeclaration ("GVariantBuilder");
864 cdecl.add_declarator (new CCodeVariableDeclarator ("_arguments_builder"));
865 prefragment.append (cdecl);
867 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
868 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
869 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
870 prefragment.append (new CCodeExpressionStatement (builder_init));
872 // interface name
873 write_expression (prefragment, string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)), null);
874 // property name
875 write_expression (prefragment, string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
877 // property value (as variant)
878 var builder_open = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_open"));
879 builder_open.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
880 builder_open.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_VARIANT"));
881 prefragment.append (new CCodeExpressionStatement (builder_open));
883 if (prop.property_type.is_real_non_null_struct_type ()) {
884 write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value")), prop);
885 } else {
886 write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_arguments_builder"), new CCodeIdentifier ("value"), prop);
889 var builder_close = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_close"));
890 builder_close.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
891 prefragment.append (new CCodeExpressionStatement (builder_close));
893 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
894 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
895 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_arguments"), builder_end)));
897 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
898 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
899 ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Set\""));
900 ccall.add_argument (new CCodeIdentifier ("_arguments"));
901 ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
902 ccall.add_argument (get_dbus_timeout (prop));
903 ccall.add_argument (new CCodeConstant ("NULL"));
904 ccall.add_argument (new CCodeConstant ("NULL"));
906 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
908 // return on error
909 var error_block = new CCodeBlock ();
910 error_block.add_statement (new CCodeReturnStatement ());
911 block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply")), error_block));
913 block.add_statement (postfragment);
915 var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
916 unref_reply.add_argument (new CCodeIdentifier ("_reply"));
917 block.add_statement (new CCodeExpressionStatement (unref_reply));
919 cfile.add_function_declaration (function);
920 function.block = block;
921 cfile.add_function (function);
923 return proxy_name;