Fix ref_sink of Gtk.Window created with GLib.Object.new
[vala-lang.git] / codegen / valadbusclientmodule.vala
blob3d8703ac6309639ee47924b4f7f0ea53c204f808
1 /* valadbusclientmodule.vala
3 * Copyright (C) 2007-2010 Jürg Billeter
4 * Copyright (C) 2008 Philip Van Hoof
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Philip Van Hoof <pvanhoof@gnome.org>
25 using GLib;
27 /**
28 * The link between a dynamic method and generated code.
30 public class Vala.DBusClientModule : DBusModule {
31 int dynamic_property_id;
33 string get_dynamic_dbus_name (string vala_name) {
34 // TODO switch default to no transformation as soon as we have static D-Bus client support
35 // keep transformation by default for static D-Bus client and server support
36 if (context.dbus_transformation) {
37 return Symbol.lower_case_to_camel_case (vala_name);
38 } else {
39 return vala_name;
43 public CCodeConstant get_dbus_timeout (Symbol symbol) {
44 int timeout = -1;
46 var dbus = symbol.get_attribute ("DBus");
47 if (dbus != null && dbus.has_argument ("timeout")) {
48 timeout = dbus.get_integer ("timeout");
49 } else if (symbol.parent_symbol != null) {
50 return get_dbus_timeout (symbol.parent_symbol);
53 return new CCodeConstant (timeout.to_string ());
56 public static bool is_dbus_no_reply (CodeNode node) {
57 var dbus_attribute = node.get_attribute ("DBus");
58 if (dbus_attribute != null
59 && dbus_attribute.has_argument ("no_reply")
60 && dbus_attribute.get_bool ("no_reply")) {
61 return true;
64 return false;
67 bool has_dbus_error (List<DataType> error_types) {
68 foreach (DataType error_type in error_types) {
69 if (((ErrorType) error_type).error_domain.get_full_name () == "DBus.Error") {
70 return true;
73 return false;
76 public override void generate_dynamic_method_wrapper (DynamicMethod method) {
77 var dynamic_method = (DynamicMethod) method;
79 var func = new CCodeFunction (method.get_cname ());
80 func.modifiers = CCodeModifiers.STATIC;
82 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
84 generate_cparameters (method, source_declarations, cparam_map, func);
86 var block = new CCodeBlock ();
87 if (dynamic_method.dynamic_type.data_type == dbus_object_type) {
88 generate_dbus_method_wrapper (method, block);
89 } else {
90 Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ()));
93 // append to C source file
94 source_declarations.add_type_member_declaration (func.copy ());
96 func.block = block;
97 source_type_member_definition.append (func);
100 void generate_dbus_method_wrapper (Method method, CCodeBlock block) {
101 var dynamic_method = (DynamicMethod) method;
103 var expr = dynamic_method.invocation;
105 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_begin_call"));
107 ccall.add_argument (new CCodeIdentifier ("self"));
109 bool found_out = false;
110 Expression callback = null;
111 int callback_index = -1;
112 int arg_index = 1;
113 foreach (Expression arg in expr.get_argument_list ()) {
114 if (arg.symbol_reference is Method) {
115 // callback
116 if (callback != null) {
117 Report.error (expr.source_reference, "only one reply callback may be specified in invocation of DBus method");
118 expr.error = true;
119 return;
120 } else if (found_out) {
121 Report.error (expr.source_reference, "out argument and reply callback conflict in invocation of DBus method");
122 expr.error = true;
123 return;
125 callback = arg;
126 callback_index = arg_index;
127 } else if (arg is UnaryExpression && ((UnaryExpression) arg).operator == UnaryOperator.OUT) {
128 // out arg
129 if (callback != null) {
130 Report.error (expr.source_reference, "out argument and reply callback conflict in invocation of DBus method");
131 expr.error = true;
132 return;
134 found_out = true;
135 } else {
136 // in arg
137 if (callback != null || found_out) {
138 Report.error (expr.source_reference, "in argument must not follow out argument or reply callback in invocation of DBus method");
139 expr.error = true;
140 return;
143 arg_index++;
146 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (method.name))));
148 if (callback != null) {
149 var reply_method = (Method) callback.symbol_reference;
151 var cb_fun = new CCodeFunction ("_%s_cb".printf (reply_method.get_cname ()), "void");
152 cb_fun.modifiers = CCodeModifiers.STATIC;
153 cb_fun.add_parameter (new CCodeFormalParameter ("proxy", "DBusGProxy*"));
154 cb_fun.add_parameter (new CCodeFormalParameter ("call", "DBusGProxyCall*"));
155 cb_fun.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
156 cb_fun.block = new CCodeBlock ();
157 var cerrdecl = new CCodeDeclaration ("GError*");
158 cerrdecl.add_declarator (new CCodeVariableDeclarator ("error", new CCodeConstant ("NULL")));
159 cb_fun.block.add_statement (cerrdecl);
160 var cend_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_end_call"));
161 cend_call.add_argument (new CCodeIdentifier ("proxy"));
162 cend_call.add_argument (new CCodeIdentifier ("call"));
163 cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
164 var creply_call = new CCodeFunctionCall ((CCodeExpression) callback.ccodenode);
165 if (reply_method.binding != MemberBinding.STATIC) {
166 creply_call.add_argument (new CCodeIdentifier ("user_data"));
168 int param_count = reply_method.get_parameters ().size;
169 int i = 0;
170 foreach (FormalParameter param in reply_method.get_parameters ()) {
171 if ((++i) == param_count) {
172 if (!(param.variable_type is ErrorType)) {
173 Report.error (null, "DBus reply callbacks must end with GLib.Error argument");
174 return;
177 break;
179 if (param.variable_type is ArrayType && ((ArrayType) param.variable_type).element_type.data_type != string_type.data_type) {
180 var array_type = (ArrayType) param.variable_type;
181 CCodeDeclaration cdecl;
182 if (dbus_use_ptr_array (array_type)) {
183 cdecl = new CCodeDeclaration ("GPtrArray*");
184 } else {
185 cdecl = new CCodeDeclaration ("GArray*");
187 cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
188 cb_fun.block.add_statement (cdecl);
189 cend_call.add_argument (get_dbus_g_type (array_type));
190 cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
191 creply_call.add_argument (new CCodeCastExpression (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), dbus_use_ptr_array (array_type) ? "pdata" : "data"), array_type.get_cname ()));
192 creply_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), "len"));
193 } else {
194 var cdecl = new CCodeDeclaration (param.variable_type.get_cname ());
195 cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
196 cb_fun.block.add_statement (cdecl);
197 cend_call.add_argument (get_dbus_g_type (param.variable_type));
198 cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
199 creply_call.add_argument (new CCodeIdentifier (param.name));
201 if (param.variable_type is ArrayType && ((ArrayType) param.variable_type).element_type.data_type == string_type.data_type) {
202 var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
203 cstrvlen.add_argument (new CCodeIdentifier (param.name));
204 creply_call.add_argument (cstrvlen);
209 cend_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
210 cb_fun.block.add_statement (new CCodeExpressionStatement (cend_call));
211 creply_call.add_argument (new CCodeIdentifier ("error"));
212 cb_fun.block.add_statement (new CCodeExpressionStatement (creply_call));
214 CCodeExpression target = new CCodeConstant ("param%d_target".printf (callback_index));
215 var ma = (MemberAccess) callback;
216 if (reply_method.binding != MemberBinding.STATIC && ma.inner.value_type.data_type != null && ma.inner.value_type.data_type.is_reference_counting ()) {
217 // unref user_data after creply_call
218 var unref_call = new CCodeFunctionCall (get_destroy_func_expression (ma.inner.value_type));
219 unref_call.add_argument (new CCodeIdentifier ("user_data"));
220 cb_fun.block.add_statement (new CCodeExpressionStatement (unref_call));
222 // ref target for ccall
223 var ref_call = new CCodeFunctionCall (get_dup_func_expression (ma.inner.value_type, callback.source_reference));
224 ref_call.add_argument (target);
225 target = ref_call;
228 if (!source_declarations.add_declaration (cb_fun.name)) {
229 // avoid duplicate function definition
230 source_type_member_definition.append (cb_fun);
233 ccall.add_argument (new CCodeIdentifier (cb_fun.name));
234 ccall.add_argument (target);
235 ccall.add_argument (new CCodeConstant ("NULL"));
236 } else {
237 ccall.call = new CCodeIdentifier ("dbus_g_proxy_call");
239 ccall.add_argument (new CCodeIdentifier ("error"));
242 foreach (FormalParameter param in method.get_parameters ()) {
243 if (param.variable_type is MethodType
244 || param.variable_type is DelegateType) {
245 // callback parameter
246 break;
249 if (param.direction != ParameterDirection.IN) {
250 continue;
253 var array_type = param.variable_type as ArrayType;
254 if (array_type != null) {
255 // array parameter
256 if (array_type.element_type.data_type != string_type.data_type) {
257 // non-string arrays (use GArray)
258 ccall.add_argument (get_dbus_g_type (array_type));
260 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
261 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
263 CCodeDeclaration cdecl;
264 CCodeFunctionCall array_construct;
265 if (dbus_use_ptr_array (array_type)) {
266 cdecl = new CCodeDeclaration ("GPtrArray*");
268 array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_ptr_array_sized_new"));
269 array_construct.add_argument (new CCodeIdentifier (get_array_length_cname (param.name, 1)));
270 } else {
271 cdecl = new CCodeDeclaration ("GArray*");
273 array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_array_new"));
274 array_construct.add_argument (new CCodeConstant ("TRUE"));
275 array_construct.add_argument (new CCodeConstant ("TRUE"));
276 array_construct.add_argument (sizeof_call);
279 cdecl.add_declarator (new CCodeVariableDeclarator ("dbus_%s".printf (param.name), array_construct));
280 block.add_statement (cdecl);
282 if (dbus_use_ptr_array (array_type)) {
283 source_declarations.add_include ("string.h");
285 var memcpy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
286 memcpy_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "pdata"));
287 memcpy_call.add_argument (new CCodeIdentifier (param.name));
288 memcpy_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier (get_array_length_cname (param.name, 1)), sizeof_call));
289 block.add_statement (new CCodeExpressionStatement (memcpy_call));
291 var len_assignment = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "len"), new CCodeIdentifier (get_array_length_cname (param.name, 1)));
292 block.add_statement (new CCodeExpressionStatement (len_assignment));
293 } else {
294 var cappend_call = new CCodeFunctionCall (new CCodeIdentifier ("g_array_append_vals"));
295 cappend_call.add_argument (new CCodeIdentifier ("dbus_%s".printf (param.name)));
296 cappend_call.add_argument (new CCodeIdentifier (param.name));
297 cappend_call.add_argument (new CCodeIdentifier (get_array_length_cname (param.name, 1)));
298 block.add_statement (new CCodeExpressionStatement (cappend_call));
301 ccall.add_argument (new CCodeIdentifier ("dbus_%s".printf (param.name)));
302 } else {
303 // string arrays
304 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
305 ccall.add_argument (new CCodeIdentifier (param.name));
307 } else if (get_type_signature (param.variable_type).has_prefix ("(")) {
308 // struct parameter
309 var st = (Struct) param.variable_type.data_type;
311 var array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_new"));
312 array_construct.add_argument (new CCodeConstant ("0"));
314 var cdecl = new CCodeDeclaration ("GValueArray*");
315 cdecl.add_declarator (new CCodeVariableDeclarator ("dbus_%s".printf (param.name), array_construct));
316 block.add_statement (cdecl);
318 foreach (Field f in st.get_fields ()) {
319 if (f.binding != MemberBinding.INSTANCE) {
320 continue;
323 string val_name = "val_%s_%s".printf (param.name, f.name);
325 // 0-initialize struct with struct initializer { 0 }
326 var cvalinit = new CCodeInitializerList ();
327 cvalinit.append (new CCodeConstant ("0"));
329 var cval_decl = new CCodeDeclaration ("GValue");
330 cval_decl.add_declarator (new CCodeVariableDeclarator.zero (val_name, cvalinit));
331 block.add_statement (cval_decl);
333 var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (val_name));
335 var cinit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
336 cinit_call.add_argument (val_ptr);
337 cinit_call.add_argument (new CCodeIdentifier (f.variable_type.data_type.get_type_id ()));
338 block.add_statement (new CCodeExpressionStatement (cinit_call));
340 var cset_call = new CCodeFunctionCall (new CCodeIdentifier (f.variable_type.data_type.get_set_value_function ()));
341 cset_call.add_argument (val_ptr);
342 cset_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), f.name));
343 block.add_statement (new CCodeExpressionStatement (cset_call));
345 var cappend_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_append"));
346 cappend_call.add_argument (new CCodeIdentifier ("dbus_%s".printf (param.name)));
347 cappend_call.add_argument (val_ptr);
348 block.add_statement (new CCodeExpressionStatement (cappend_call));
351 ccall.add_argument (get_dbus_g_type (param.variable_type));
352 ccall.add_argument (new CCodeIdentifier ("dbus_%s".printf (param.name)));
353 } else {
354 ccall.add_argument (get_dbus_g_type (param.variable_type));
355 ccall.add_argument (new CCodeIdentifier (param.name));
359 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
361 var out_marshalling_fragment = new CCodeFragment ();
363 foreach (FormalParameter param in method.get_parameters ()) {
364 if (param.variable_type is MethodType) {
365 // callback parameter
366 break;
369 if (param.direction != ParameterDirection.OUT) {
370 continue;
373 if (get_type_signature (param.variable_type).has_prefix ("(")) {
374 // struct output parameter
375 var st = (Struct) param.variable_type.data_type;
377 var cdecl = new CCodeDeclaration ("GValueArray*");
378 cdecl.add_declarator (new CCodeVariableDeclarator ("dbus_%s".printf (param.name)));
379 block.add_statement (cdecl);
381 int i = 0;
382 foreach (Field f in st.get_fields ()) {
383 if (f.binding != MemberBinding.INSTANCE) {
384 continue;
387 var cget_call = new CCodeFunctionCall (new CCodeIdentifier (f.variable_type.data_type.get_get_value_function ()));
388 cget_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeElementAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "values"), new CCodeConstant (i.to_string ()))));
390 var converted_value = cget_call;
392 if (requires_copy (f.variable_type)) {
393 var dupexpr = get_dup_func_expression (f.variable_type, expr.source_reference);
394 converted_value = new CCodeFunctionCall (dupexpr);
395 converted_value.add_argument (cget_call);
398 var assign = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), f.name), converted_value);
399 out_marshalling_fragment.append (new CCodeExpressionStatement (assign));
401 i++;
404 ccall.add_argument (get_dbus_g_type (param.variable_type));
405 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("dbus_%s".printf (param.name))));
406 } else {
407 ccall.add_argument (get_dbus_g_type (param.variable_type));
408 ccall.add_argument (new CCodeIdentifier (param.name));
412 if (!(method.return_type is VoidType)) {
413 // synchronous D-Bus method call with reply
414 ccall.add_argument (get_dbus_g_type (method.return_type));
416 var array_type = method.return_type as ArrayType;
417 if (array_type != null && array_type.element_type.data_type != string_type.data_type) {
418 // non-string arrays (use GArray)
419 CCodeDeclaration cdecl;
420 if (dbus_use_ptr_array (array_type)) {
421 cdecl = new CCodeDeclaration ("GPtrArray*");
422 } else {
423 cdecl = new CCodeDeclaration ("GArray*");
425 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
426 block.add_statement (cdecl);
428 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
429 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
431 block.add_statement (new CCodeExpressionStatement (ccall));
433 // don't access result when error occured
434 var creturnblock = new CCodeBlock ();
435 creturnblock.add_statement (new CCodeReturnStatement (default_value_for_type (method.return_type, false)));
436 var cerrorif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")), creturnblock);
437 block.add_statement (cerrorif);
439 block.add_statement (out_marshalling_fragment);
441 // *result_length1 = result->len;
442 var garray_length = new CCodeMemberAccess.pointer (new CCodeIdentifier ("result"), "len");
443 var result_length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length1"));
444 var assign = new CCodeAssignment (result_length, garray_length);
445 block.add_statement (new CCodeExpressionStatement (assign));
447 // return result->data;
448 block.add_statement (new CCodeReturnStatement (new CCodeCastExpression (new CCodeMemberAccess.pointer (new CCodeIdentifier ("result"), dbus_use_ptr_array (array_type) ? "pdata" : "data"), method.return_type.get_cname ())));
449 } else if (method.return_type.is_real_non_null_struct_type ()) {
450 // structs are returned via out parameter
451 var st = (Struct) method.return_type.data_type;
453 if (st.get_full_name () == "GLib.Value") {
454 ccall.add_argument (new CCodeIdentifier ("result"));
455 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
457 block.add_statement (new CCodeExpressionStatement (ccall));
458 } else {
459 var cdecl = new CCodeDeclaration ("GValueArray*");
460 cdecl.add_declarator (new CCodeVariableDeclarator ("dbus_result"));
461 block.add_statement (cdecl);
463 int i = 0;
464 foreach (Field f in st.get_fields ()) {
465 if (f.binding != MemberBinding.INSTANCE) {
466 continue;
469 var cget_call = new CCodeFunctionCall (new CCodeIdentifier (f.variable_type.data_type.get_get_value_function ()));
470 cget_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeElementAccess (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_result"), "values"), new CCodeConstant (i.to_string ()))));
472 var converted_value = cget_call;
474 if (requires_copy (f.variable_type)) {
475 var dupexpr = get_dup_func_expression (f.variable_type, expr.source_reference);
476 converted_value = new CCodeFunctionCall (dupexpr);
477 converted_value.add_argument (cget_call);
480 var assign = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("result"), f.name), converted_value);
481 out_marshalling_fragment.append (new CCodeExpressionStatement (assign));
483 i++;
486 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("dbus_result")));
487 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
489 block.add_statement (new CCodeExpressionStatement (ccall));
492 // don't access result when error occured
493 var creturnblock = new CCodeBlock ();
494 creturnblock.add_statement (new CCodeReturnStatement ());
495 var cerrorif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")), creturnblock);
496 block.add_statement (cerrorif);
498 block.add_statement (out_marshalling_fragment);
499 } else {
500 // string arrays or other datatypes
501 var cdecl = new CCodeDeclaration (method.return_type.get_cname ());
502 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
503 block.add_statement (cdecl);
505 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
506 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
508 block.add_statement (new CCodeExpressionStatement (ccall));
510 // don't access result when error occured
511 var creturnblock = new CCodeBlock ();
512 creturnblock.add_statement (new CCodeReturnStatement (default_value_for_type (method.return_type, false)));
513 var cerrorif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")), creturnblock);
514 block.add_statement (cerrorif);
516 block.add_statement (out_marshalling_fragment);
518 if (array_type != null) {
519 // special case string array
521 // *result_length1 = g_strv_length (result);
522 var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
523 cstrvlen.add_argument (new CCodeIdentifier ("result"));
524 var result_length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length1"));
525 var assign = new CCodeAssignment (result_length, cstrvlen);
526 block.add_statement (new CCodeExpressionStatement (assign));
529 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
531 } else {
532 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
534 block.add_statement (new CCodeExpressionStatement (ccall));
536 // don't access result when error occured
537 var creturnblock = new CCodeBlock ();
538 creturnblock.add_statement (new CCodeReturnStatement ());
539 var cerrorif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")), creturnblock);
540 block.add_statement (cerrorif);
542 block.add_statement (out_marshalling_fragment);
546 public override CCodeExpression get_dbus_g_type (DataType data_type) {
547 if (data_type is ArrayType) {
548 var array_type = data_type as ArrayType;
549 if (array_type.element_type.data_type == string_type.data_type) {
550 return new CCodeIdentifier ("G_TYPE_STRV");
553 var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
554 if (dbus_use_ptr_array (array_type)) {
555 carray_type.add_argument (new CCodeConstant ("\"GPtrArray\""));
556 } else {
557 carray_type.add_argument (new CCodeConstant ("\"GArray\""));
559 carray_type.add_argument (get_dbus_g_type (array_type.element_type));
560 return carray_type;
561 } else if (data_type.data_type is Enum) {
562 var en = (Enum) data_type.data_type;
563 if (en.is_flags) {
564 return new CCodeIdentifier ("G_TYPE_UINT");
565 } else {
566 return new CCodeIdentifier ("G_TYPE_INT");
568 } else if (data_type.data_type == null) {
569 critical ("Internal error during DBus type generation with: %s", data_type.to_string ());
570 return new CCodeIdentifier ("G_TYPE_NONE");
571 } else if (data_type.data_type.get_full_name () == "GLib.HashTable") {
572 var cmap_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_map"));
573 var type_args = data_type.get_type_arguments ();
575 cmap_type.add_argument (new CCodeConstant ("\"GHashTable\""));
576 foreach (DataType type_arg in type_args) {
577 cmap_type.add_argument (get_dbus_g_type (type_arg));
580 return cmap_type;
581 } else if (get_type_signature (data_type).has_prefix ("(")) {
582 // struct parameter
583 var st = (Struct) data_type.data_type;
585 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_struct"));
586 type_call.add_argument (new CCodeConstant ("\"GValueArray\""));
588 foreach (Field f in st.get_fields ()) {
589 if (f.binding != MemberBinding.INSTANCE) {
590 continue;
593 type_call.add_argument (get_dbus_g_type (f.variable_type));
596 type_call.add_argument (new CCodeConstant ("G_TYPE_INVALID"));
598 return type_call;
599 } else {
600 return new CCodeIdentifier (data_type.data_type.get_type_id ());
604 public bool dbus_use_ptr_array (ArrayType array_type) {
605 if (array_type.element_type.data_type == string_type.data_type) {
606 // use char**
607 return false;
608 } else if (array_type.element_type.data_type == bool_type.data_type
609 || array_type.element_type.data_type == char_type.data_type
610 || array_type.element_type.data_type == uchar_type.data_type
611 || array_type.element_type.data_type == int_type.data_type
612 || array_type.element_type.data_type == uint_type.data_type
613 || array_type.element_type.data_type == long_type.data_type
614 || array_type.element_type.data_type == ulong_type.data_type
615 || array_type.element_type.data_type == int8_type.data_type
616 || array_type.element_type.data_type == uint8_type.data_type
617 || array_type.element_type.data_type == int32_type.data_type
618 || array_type.element_type.data_type == uint32_type.data_type
619 || array_type.element_type.data_type == int64_type.data_type
620 || array_type.element_type.data_type == uint64_type.data_type
621 || array_type.element_type.data_type == double_type.data_type) {
622 // use GArray
623 return false;
624 } else {
625 // use GPtrArray
626 return true;
630 public override string get_dynamic_property_getter_cname (DynamicProperty prop) {
631 if (prop.dynamic_type.data_type != dbus_object_type) {
632 return base.get_dynamic_property_getter_cname (prop);
635 string getter_cname = "_dynamic_get_%s%d".printf (prop.name, dynamic_property_id++);
637 if (get_type_signature (prop.property_type) == null) {
638 Report.error (prop.property_type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (prop.property_type.to_string ()));
639 return getter_cname;
642 var func = new CCodeFunction (getter_cname, prop.property_type.get_cname ());
643 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
645 func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
647 var block = new CCodeBlock ();
648 generate_dbus_property_getter_wrapper (prop, block);
650 // append to C source file
651 source_declarations.add_type_member_declaration (func.copy ());
653 func.block = block;
654 source_type_member_definition.append (func);
656 return getter_cname;
659 public override string get_dynamic_property_setter_cname (DynamicProperty prop) {
660 if (prop.dynamic_type.data_type != dbus_object_type) {
661 return base.get_dynamic_property_setter_cname (prop);
664 string setter_cname = "_dynamic_set_%s%d".printf (prop.name, dynamic_property_id++);
666 if (get_type_signature (prop.property_type) == null) {
667 Report.error (prop.property_type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (prop.property_type.to_string ()));
668 return setter_cname;
671 var func = new CCodeFunction (setter_cname, "void");
672 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
674 func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
675 func.add_parameter (new CCodeFormalParameter ("value", prop.property_type.get_cname ()));
677 var block = new CCodeBlock ();
678 generate_dbus_property_setter_wrapper (prop, block);
680 // append to C source file
681 source_declarations.add_type_member_declaration (func.copy ());
683 func.block = block;
684 source_type_member_definition.append (func);
686 return setter_cname;
689 void create_dbus_property_proxy (DynamicProperty node, CCodeBlock block) {
690 var prop_proxy_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_new_from_proxy"));
691 prop_proxy_call.add_argument (new CCodeIdentifier ("obj"));
692 prop_proxy_call.add_argument (new CCodeConstant ("DBUS_INTERFACE_PROPERTIES"));
693 prop_proxy_call.add_argument (new CCodeConstant ("NULL"));
695 var prop_proxy_decl = new CCodeDeclaration ("DBusGProxy*");
696 prop_proxy_decl.add_declarator (new CCodeVariableDeclarator ("property_proxy", prop_proxy_call));
697 block.add_statement (prop_proxy_decl);
700 void generate_dbus_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
701 create_dbus_property_proxy (node, block);
703 // initialize GValue
704 var cvalinit = new CCodeInitializerList ();
705 cvalinit.append (new CCodeConstant ("0"));
707 var cval_decl = new CCodeDeclaration ("GValue");
708 cval_decl.add_declarator (new CCodeVariableDeclarator.zero ("gvalue", cvalinit));
709 block.add_statement (cval_decl);
711 var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("gvalue"));
713 // call Get method on property proxy
714 var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
715 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
716 block.add_statement (cdecl);
718 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_call"));
719 ccall.add_argument (new CCodeIdentifier ("property_proxy"));
720 ccall.add_argument (new CCodeConstant ("\"Get\""));
721 ccall.add_argument (new CCodeConstant ("NULL"));
723 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
724 var get_iface = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_interface"));
725 get_iface.add_argument (new CCodeIdentifier ("obj"));
726 ccall.add_argument (get_iface);
728 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
729 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (node.name))));
731 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
733 ccall.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
734 ccall.add_argument (val_ptr);
736 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
738 block.add_statement (new CCodeExpressionStatement (ccall));
740 // unref property proxy
741 var prop_proxy_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
742 prop_proxy_unref.add_argument (new CCodeIdentifier ("property_proxy"));
743 block.add_statement (new CCodeExpressionStatement (prop_proxy_unref));
745 // assign value to result variable
746 var cget_call = new CCodeFunctionCall (new CCodeIdentifier (node.property_type.data_type.get_get_value_function ()));
747 cget_call.add_argument (val_ptr);
748 var assign = new CCodeAssignment (new CCodeIdentifier ("result"), cget_call);
749 block.add_statement (new CCodeExpressionStatement (assign));
751 // return result
752 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
755 void generate_dbus_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
756 create_dbus_property_proxy (node, block);
758 // initialize GValue
759 var cvalinit = new CCodeInitializerList ();
760 cvalinit.append (new CCodeConstant ("0"));
762 var cval_decl = new CCodeDeclaration ("GValue");
763 cval_decl.add_declarator (new CCodeVariableDeclarator.zero ("gvalue", cvalinit));
764 block.add_statement (cval_decl);
766 var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("gvalue"));
768 var cinit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
769 cinit_call.add_argument (val_ptr);
770 cinit_call.add_argument (new CCodeIdentifier (node.property_type.data_type.get_type_id ()));
771 block.add_statement (new CCodeExpressionStatement (cinit_call));
773 var cset_call = new CCodeFunctionCall (new CCodeIdentifier (node.property_type.data_type.get_set_value_function ()));
774 cset_call.add_argument (val_ptr);
775 cset_call.add_argument (new CCodeIdentifier ("value"));
776 block.add_statement (new CCodeExpressionStatement (cset_call));
778 // call Set method on property proxy
779 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_call"));
780 ccall.add_argument (new CCodeIdentifier ("property_proxy"));
781 ccall.add_argument (new CCodeConstant ("\"Set\""));
782 ccall.add_argument (new CCodeConstant ("NULL"));
784 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
785 var get_iface = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_interface"));
786 get_iface.add_argument (new CCodeIdentifier ("obj"));
787 ccall.add_argument (get_iface);
789 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
790 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (node.name))));
792 ccall.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
793 ccall.add_argument (val_ptr);
795 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
797 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
799 block.add_statement (new CCodeExpressionStatement (ccall));
801 // unref property proxy
802 var prop_proxy_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
803 prop_proxy_unref.add_argument (new CCodeIdentifier ("property_proxy"));
804 block.add_statement (new CCodeExpressionStatement (prop_proxy_unref));
807 public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig) {
808 if (sig.dynamic_type.data_type != dbus_object_type) {
809 return base.get_dynamic_signal_connect_wrapper_name (sig);
812 string connect_wrapper_name = "_%sconnect".printf (get_dynamic_signal_cname (sig));
813 var func = new CCodeFunction (connect_wrapper_name, "void");
814 func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
815 func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
816 func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
817 func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
818 var block = new CCodeBlock ();
819 generate_dbus_connect_wrapper (sig, block);
821 // append to C source file
822 source_declarations.add_type_member_declaration (func.copy ());
824 func.block = block;
825 source_type_member_definition.append (func);
827 return connect_wrapper_name;
830 public override string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal sig) {
831 if (sig.dynamic_type.data_type != dbus_object_type) {
832 return base.get_dynamic_signal_disconnect_wrapper_name (sig);
835 string disconnect_wrapper_name = "_%sdisconnect".printf (get_dynamic_signal_cname (sig));
836 var func = new CCodeFunction (disconnect_wrapper_name, "void");
837 func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
838 func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
839 func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
840 func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
841 var block = new CCodeBlock ();
842 generate_dbus_disconnect_wrapper (sig, block);
844 // append to C source file
845 source_declarations.add_type_member_declaration (func.copy ());
847 func.block = block;
848 source_type_member_definition.append (func);
850 return disconnect_wrapper_name;
853 void generate_dbus_connect_wrapper (DynamicSignal sig, CCodeBlock block) {
854 var m = (Method) sig.handler.symbol_reference;
856 sig.accept (this);
858 // FIXME should only be done once per marshaller
859 var register_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_object_register_marshaller"));
860 generate_marshaller (sig.get_parameters (), sig.return_type, true);
861 register_call.add_argument (new CCodeIdentifier (get_marshaller_function (sig.get_parameters (), sig.return_type, null, true)));
862 register_call.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
864 var add_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_add_signal"));
865 add_call.add_argument (new CCodeIdentifier ("obj"));
866 add_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (sig.name))));
868 bool first = true;
869 foreach (FormalParameter param in m.get_parameters ()) {
870 if (first) {
871 // skip sender parameter
872 first = false;
873 continue;
876 register_call.add_argument (get_dbus_g_type (param.variable_type));
877 add_call.add_argument (get_dbus_g_type (param.variable_type));
879 register_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
880 add_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
882 block.add_statement (new CCodeExpressionStatement (register_call));
883 block.add_statement (new CCodeExpressionStatement (add_call));
885 var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_connect_signal"));
886 call.add_argument (new CCodeIdentifier ("obj"));
887 call.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (sig.name))));
888 call.add_argument (new CCodeIdentifier ("handler"));
889 call.add_argument (new CCodeIdentifier ("data"));
890 call.add_argument (new CCodeConstant ("NULL"));
891 block.add_statement (new CCodeExpressionStatement (call));
894 void generate_dbus_disconnect_wrapper (DynamicSignal sig, CCodeBlock block) {
895 var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_disconnect_signal"));
896 call.add_argument (new CCodeIdentifier ("obj"));
897 call.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (sig.name))));
898 call.add_argument (new CCodeIdentifier ("handler"));
899 call.add_argument (new CCodeIdentifier ("data"));
900 block.add_statement (new CCodeExpressionStatement (call));
903 public override void visit_cast_expression (CastExpression expr) {
904 // handles casting DBus.Object instances to DBus interfaces
906 var type = expr.type_reference as ObjectType;
907 var call = expr.inner as MethodCall;
908 if (type == null || !(type.type_symbol is Interface)
909 || type.type_symbol.get_attribute ("DBus") == null || call == null) {
910 base.visit_cast_expression (expr);
911 return;
914 var mtype = call.call.value_type as MethodType;
915 if (mtype == null || mtype.method_symbol.get_cname () != "dbus_g_proxy_new_for_name") {
916 base.visit_cast_expression (expr);
917 return;
920 var args = call.get_argument_list ();
921 Expression connection = ((MemberAccess) call.call).inner;
922 Expression bus_name = args.get (0);
923 Expression object_path = args.get (1);
925 var ccall = new CCodeFunctionCall (new CCodeIdentifier (type.type_symbol.get_lower_case_cprefix () + "dbus_proxy_new"));
926 connection.emit (this);
927 ccall.add_argument ((CCodeExpression) connection.ccodenode);
928 bus_name.emit (this);
929 ccall.add_argument ((CCodeExpression) bus_name.ccodenode);
930 object_path.emit (this);
931 ccall.add_argument ((CCodeExpression) object_path.ccodenode);
932 expr.ccodenode = ccall;
935 void generate_proxy_interface_init (Interface main_iface, Interface iface) {
936 // also generate proxy for prerequisites
937 foreach (var prereq in iface.get_prerequisites ()) {
938 if (prereq.data_type is Interface) {
939 generate_proxy_interface_init (main_iface, (Interface) prereq.data_type);
943 string lower_cname = main_iface.get_lower_case_cprefix () + "dbus_proxy";
945 var proxy_iface_init = new CCodeFunction (lower_cname + "_" + iface.get_lower_case_cprefix () + "_interface_init", "void");
946 proxy_iface_init.add_parameter (new CCodeFormalParameter ("iface", iface.get_cname () + "Iface*"));
948 var iface_block = new CCodeBlock ();
950 foreach (Method m in iface.get_methods ()) {
951 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.vfunc_name);
952 if (is_dbus_no_reply (m)) {
953 if (m.coroutine) {
954 Report.error (m.source_reference, "No-reply DBus methods must not be async");
956 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_noreply_dbus_proxy_method (main_iface, iface, m)))));
957 } else if (!m.coroutine) {
958 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (main_iface, iface, m)))));
959 } else {
960 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_async_dbus_proxy_method (main_iface, iface, m)))));
961 vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.get_finish_vfunc_name ());
962 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_finish_dbus_proxy_method (main_iface, iface, m)))));
966 foreach (Property prop in iface.get_properties ()) {
967 if (prop.get_accessor != null) {
968 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "get_" + prop.name);
969 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_get (main_iface, iface, prop)))));
971 if (prop.set_accessor != null) {
972 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "set_" + prop.name);
973 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_set (main_iface, iface, prop)))));
977 proxy_iface_init.modifiers = CCodeModifiers.STATIC;
978 source_declarations.add_type_member_declaration (proxy_iface_init.copy ());
979 proxy_iface_init.block = iface_block;
980 source_type_member_definition.append (proxy_iface_init);
983 string implement_interface (CCodeFunctionCall define_type, Interface main_iface, Interface iface) {
984 string result = "";
986 // also implement prerequisites
987 foreach (var prereq in iface.get_prerequisites ()) {
988 if (prereq.data_type is Interface) {
989 result += implement_interface (define_type, main_iface, (Interface) prereq.data_type);
993 result += "G_IMPLEMENT_INTERFACE (%s, %sdbus_proxy_%s_interface_init) ".printf (
994 iface.get_upper_case_cname ("TYPE_"),
995 main_iface.get_lower_case_cprefix (),
996 iface.get_lower_case_cprefix ());
997 return result;
1000 void implement_property (CCodeBlock block, Interface main_iface, Interface iface) {
1001 // also implement prerequisites
1002 foreach (var prereq in iface.get_prerequisites ()) {
1003 if (prereq.data_type is Interface) {
1004 implement_property (block, main_iface, (Interface) prereq.data_type);
1008 var gobject_class = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
1009 gobject_class.add_argument (new CCodeIdentifier ("klass"));
1011 foreach (Property prop in iface.get_properties ()) {
1012 if (!prop.is_abstract) {
1013 continue;
1016 if (!is_gobject_property (prop)) {
1017 continue;
1020 string prop_ev = "%s_dbus_proxy_%s".printf (main_iface.get_lower_case_cname (null), Symbol.camel_case_to_lower_case (prop.name)).up ();
1022 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_override_property"));
1023 cinst.add_argument (gobject_class);
1024 cinst.add_argument (new CCodeConstant (prop_ev));
1025 cinst.add_argument (prop.get_canonical_cconstant ());
1026 block.add_statement (new CCodeExpressionStatement (cinst));
1028 prop_enum.add_value (new CCodeEnumValue (prop_ev));
1032 public override void generate_interface_declaration (Interface iface, CCodeDeclarationSpace decl_space) {
1033 base.generate_interface_declaration (iface, decl_space);
1035 string dbus_iface_name = get_dbus_name (iface);
1036 if (dbus_iface_name == null) {
1037 return;
1040 string lower_cname = iface.get_lower_case_cprefix () + "dbus_proxy";
1042 if (decl_space.add_symbol_declaration (iface, lower_cname + "_new")) {
1043 return;
1046 // declare proxy_new function
1047 var proxy_new = new CCodeFunction (lower_cname + "_new", iface.get_cname () + "*");
1048 proxy_new.add_parameter (new CCodeFormalParameter ("connection", "DBusGConnection*"));
1049 proxy_new.add_parameter (new CCodeFormalParameter ("name", "const char*"));
1050 proxy_new.add_parameter (new CCodeFormalParameter ("path", "const char*"));
1052 decl_space.add_type_member_declaration (proxy_new);
1055 public override void visit_interface (Interface iface) {
1056 base.visit_interface (iface);
1058 string dbus_iface_name = get_dbus_name (iface);
1059 if (dbus_iface_name == null) {
1060 return;
1063 // strcmp
1064 source_declarations.add_include ("string.h");
1066 // create proxy class
1067 string cname = iface.get_cname () + "DBusProxy";
1068 string lower_cname = iface.get_lower_case_cprefix () + "dbus_proxy";
1070 add_dbus_helpers ();
1072 source_declarations.add_type_declaration (new CCodeTypeDefinition ("struct _%s".printf (cname), new CCodeVariableDeclarator (cname)));
1073 source_declarations.add_type_declaration (new CCodeTypeDefinition ("DBusGProxyClass", new CCodeVariableDeclarator (cname + "Class")));
1075 var instance_struct = new CCodeStruct ("_%s".printf (cname));
1076 instance_struct.add_field ("DBusGProxy", "parent_instance");
1077 instance_struct.add_field ("gboolean", "disposed");
1079 source_declarations.add_type_definition (instance_struct);
1081 var type_fun = new CCodeFunction(lower_cname + "_get_type", "GType");
1082 type_fun.attributes = "G_GNUC_CONST";
1083 source_declarations.add_type_member_declaration (type_fun);
1085 var define_type = new CCodeFunctionCall (new CCodeIdentifier ("G_DEFINE_TYPE_EXTENDED"));
1086 define_type.add_argument (new CCodeIdentifier (cname));
1087 define_type.add_argument (new CCodeIdentifier (lower_cname));
1088 define_type.add_argument (new CCodeIdentifier ("DBUS_TYPE_G_PROXY"));
1089 define_type.add_argument (new CCodeConstant ("0"));
1090 define_type.add_argument (new CCodeIdentifier (implement_interface (define_type, iface, iface)));
1092 source_type_member_definition.append (new CCodeExpressionStatement (define_type));
1094 // generate proxy_new function
1095 var proxy_new = new CCodeFunction (lower_cname + "_new", iface.get_cname () + "*");
1096 proxy_new.add_parameter (new CCodeFormalParameter ("connection", "DBusGConnection*"));
1097 proxy_new.add_parameter (new CCodeFormalParameter ("name", "const char*"));
1098 proxy_new.add_parameter (new CCodeFormalParameter ("path", "const char*"));
1100 var new_block = new CCodeBlock ();
1102 // create proxy object
1103 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new"));
1104 new_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier (lower_cname + "_get_type")));
1105 new_call.add_argument (new CCodeConstant ("\"connection\""));
1106 new_call.add_argument (new CCodeIdentifier ("connection"));
1107 new_call.add_argument (new CCodeConstant ("\"name\""));
1108 new_call.add_argument (new CCodeIdentifier ("name"));
1109 new_call.add_argument (new CCodeConstant ("\"path\""));
1110 new_call.add_argument (new CCodeIdentifier ("path"));
1111 new_call.add_argument (new CCodeConstant ("\"interface\""));
1112 new_call.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
1113 new_call.add_argument (new CCodeConstant ("NULL"));
1115 var cdecl = new CCodeDeclaration (iface.get_cname () + "*");
1116 cdecl.add_declarator (new CCodeVariableDeclarator ("self", new_call));
1117 new_block.add_statement (cdecl);
1118 new_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("self")));
1120 proxy_new.block = new_block;
1121 source_type_member_definition.append (proxy_new);
1123 // dbus proxy construct
1124 var proxy_construct = new CCodeFunction (lower_cname + "_construct", "GObject*");
1125 proxy_construct.add_parameter (new CCodeFormalParameter ("gtype", "GType"));
1126 proxy_construct.add_parameter (new CCodeFormalParameter ("n_properties", "guint"));
1127 proxy_construct.add_parameter (new CCodeFormalParameter ("properties", "GObjectConstructParam*"));
1128 proxy_construct.modifiers = CCodeModifiers.STATIC;
1129 proxy_construct.block = new CCodeBlock ();
1131 // chain up
1132 var parent_class = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
1133 parent_class.add_argument (new CCodeIdentifier (lower_cname + "_parent_class"));
1134 var chainup = new CCodeFunctionCall (new CCodeMemberAccess.pointer (parent_class, "constructor"));
1135 chainup.add_argument (new CCodeIdentifier ("gtype"));
1136 chainup.add_argument (new CCodeIdentifier ("n_properties"));
1137 chainup.add_argument (new CCodeIdentifier ("properties"));
1139 cdecl = new CCodeDeclaration ("GObject*");
1140 cdecl.add_declarator (new CCodeVariableDeclarator ("self", chainup));
1141 proxy_construct.block.add_statement (cdecl);
1143 cdecl = new CCodeDeclaration ("DBusGConnection");
1144 cdecl.add_declarator (new CCodeVariableDeclarator ("*connection"));
1145 proxy_construct.block.add_statement (cdecl);
1147 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
1148 gconnection.add_argument (new CCodeIdentifier ("self"));
1149 gconnection.add_argument (new CCodeConstant ("\"connection\""));
1150 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("connection")));
1151 gconnection.add_argument (new CCodeConstant ("NULL"));
1152 proxy_construct.block.add_statement (new CCodeExpressionStatement (gconnection));
1154 cdecl = new CCodeDeclaration ("char*");
1155 cdecl.add_declarator (new CCodeVariableDeclarator ("path"));
1156 proxy_construct.block.add_statement (cdecl);
1158 var path = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
1159 path.add_argument (new CCodeIdentifier ("self"));
1160 path.add_argument (new CCodeConstant ("\"path\""));
1161 path.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("path")));
1162 path.add_argument (new CCodeConstant ("NULL"));
1163 proxy_construct.block.add_statement (new CCodeExpressionStatement (path));
1165 var raw_connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
1166 raw_connection.add_argument (new CCodeIdentifier ("connection"));
1168 // add filter to handle signals from the remote object
1169 var filter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_add_filter"));
1170 filter_call.add_argument (raw_connection);
1171 filter_call.add_argument (new CCodeIdentifier (lower_cname + "_filter"));
1172 filter_call.add_argument (new CCodeIdentifier ("self"));
1173 filter_call.add_argument (new CCodeConstant ("NULL"));
1174 proxy_construct.block.add_statement (new CCodeExpressionStatement (filter_call));
1176 var filter_printf = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup_printf"));
1177 filter_printf.add_argument (new CCodeConstant ("\"type='signal',path='%s'\""));
1178 filter_printf.add_argument (new CCodeIdentifier ("path"));
1180 cdecl = new CCodeDeclaration ("char*");
1181 cdecl.add_declarator (new CCodeVariableDeclarator ("filter", filter_printf));
1182 proxy_construct.block.add_statement (cdecl);
1184 // ensure we receive signals from the remote object
1185 var match_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_bus_add_match"));
1186 match_call.add_argument (raw_connection);
1187 match_call.add_argument (new CCodeIdentifier ("filter"));
1188 match_call.add_argument (new CCodeConstant ("NULL"));
1189 proxy_construct.block.add_statement (new CCodeExpressionStatement (match_call));
1191 var connection_free = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
1192 connection_free.add_argument (new CCodeIdentifier ("connection"));
1193 proxy_construct.block.add_statement (new CCodeExpressionStatement (connection_free));
1195 var path_free = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
1196 path_free.add_argument (new CCodeIdentifier ("path"));
1197 proxy_construct.block.add_statement (new CCodeExpressionStatement (path_free));
1199 var filter_free = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
1200 filter_free.add_argument (new CCodeIdentifier ("filter"));
1201 proxy_construct.block.add_statement (new CCodeExpressionStatement (filter_free));
1203 proxy_construct.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("self")));
1205 source_type_member_definition.append (proxy_construct);
1207 // dbus proxy filter function
1208 generate_proxy_filter_function (iface);
1210 // dbus proxy dispose
1211 var proxy_dispose = new CCodeFunction (lower_cname + "_dispose", "void");
1212 proxy_dispose.add_parameter (new CCodeFormalParameter ("self", "GObject*"));
1213 proxy_dispose.modifiers = CCodeModifiers.STATIC;
1214 proxy_dispose.block = new CCodeBlock ();
1216 cdecl = new CCodeDeclaration ("DBusGConnection");
1217 cdecl.add_declarator (new CCodeVariableDeclarator ("*connection"));
1218 proxy_dispose.block.add_statement (cdecl);
1220 // return if proxy is already disposed
1221 var dispose_return_block = new CCodeBlock ();
1222 dispose_return_block.add_statement (new CCodeReturnStatement ());
1223 proxy_dispose.block.add_statement (new CCodeIfStatement (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("self"), cname + "*"), "disposed"), dispose_return_block));
1225 // mark proxy as disposed
1226 proxy_dispose.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("self"), cname + "*"), "disposed"), new CCodeConstant ("TRUE"))));
1228 gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
1229 gconnection.add_argument (new CCodeIdentifier ("self"));
1230 gconnection.add_argument (new CCodeConstant ("\"connection\""));
1231 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("connection")));
1232 gconnection.add_argument (new CCodeConstant ("NULL"));
1233 proxy_dispose.block.add_statement (new CCodeExpressionStatement (gconnection));
1235 // remove filter
1236 filter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_remove_filter"));
1237 filter_call.add_argument (raw_connection);
1238 filter_call.add_argument (new CCodeIdentifier (lower_cname + "_filter"));
1239 filter_call.add_argument (new CCodeIdentifier ("self"));
1240 proxy_dispose.block.add_statement (new CCodeExpressionStatement (filter_call));
1242 // chain up
1243 parent_class = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
1244 parent_class.add_argument (new CCodeIdentifier (lower_cname + "_parent_class"));
1245 chainup = new CCodeFunctionCall (new CCodeMemberAccess.pointer (parent_class, "dispose"));
1246 chainup.add_argument (new CCodeIdentifier ("self"));
1247 proxy_dispose.block.add_statement (new CCodeExpressionStatement (chainup));
1249 source_type_member_definition.append (proxy_dispose);
1251 var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void");
1252 proxy_class_init.add_parameter (new CCodeFormalParameter ("klass", cname + "Class*"));
1253 proxy_class_init.modifiers = CCodeModifiers.STATIC;
1254 proxy_class_init.block = new CCodeBlock ();
1255 var gobject_class = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
1256 gobject_class.add_argument (new CCodeIdentifier ("klass"));
1257 proxy_class_init.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (gobject_class, "constructor"), new CCodeIdentifier (lower_cname + "_construct"))));
1258 proxy_class_init.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (gobject_class, "dispose"), new CCodeIdentifier (lower_cname + "_dispose"))));
1259 proxy_class_init.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (gobject_class, "get_property"), new CCodeIdentifier (lower_cname + "_get_property"))));
1260 proxy_class_init.block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (gobject_class, "set_property"), new CCodeIdentifier (lower_cname + "_set_property"))));
1261 source_type_member_definition.append (proxy_class_init);
1263 prop_enum = new CCodeEnum ();
1264 prop_enum.add_value (new CCodeEnumValue ("%s_DUMMY_PROPERTY".printf (lower_cname.up ())));
1266 implement_property (proxy_class_init.block, iface, iface);
1268 source_declarations.add_type_member_declaration (prop_enum);
1270 var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void");
1271 proxy_instance_init.add_parameter (new CCodeFormalParameter ("self", cname + "*"));
1272 proxy_instance_init.modifiers = CCodeModifiers.STATIC;
1273 proxy_instance_init.block = new CCodeBlock ();
1274 source_type_member_definition.append (proxy_instance_init);
1276 generate_proxy_interface_init (iface, iface);
1278 // dbus proxy get/set_property stubs
1279 // TODO add actual implementation
1280 var get_prop = new CCodeFunction ("%s_get_property".printf (lower_cname), "void");
1281 get_prop.modifiers = CCodeModifiers.STATIC;
1282 get_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
1283 get_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
1284 get_prop.add_parameter (new CCodeFormalParameter ("value", "GValue *"));
1285 get_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
1286 source_declarations.add_type_member_declaration (get_prop.copy ());
1287 get_prop.block = new CCodeBlock ();
1288 source_type_member_definition.append (get_prop);
1290 var set_prop = new CCodeFunction ("%s_set_property".printf (lower_cname), "void");
1291 set_prop.modifiers = CCodeModifiers.STATIC;
1292 set_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
1293 set_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
1294 set_prop.add_parameter (new CCodeFormalParameter ("value", "const GValue *"));
1295 set_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
1296 source_declarations.add_type_member_declaration (set_prop.copy ());
1297 set_prop.block = new CCodeBlock ();
1298 source_type_member_definition.append (set_prop);
1301 public override TypeRegisterFunction create_interface_register_function (Interface iface) {
1302 string dbus_iface_name = get_dbus_name (iface);
1303 if (dbus_iface_name == null) {
1304 return new InterfaceRegisterFunction (iface, context);
1307 return new DBusInterfaceRegisterFunction (iface, context);
1310 string generate_get_all_function (Method m) {
1311 string get_all_func = "_dbus_g_proxy_get_all";
1313 if (!add_wrapper (get_all_func)) {
1314 // wrapper already defined
1315 return get_all_func;
1318 var function = new CCodeFunction (get_all_func, "GHashTable*");
1319 function.modifiers = CCodeModifiers.STATIC;
1321 function.add_parameter (new CCodeFormalParameter ("self", "DBusGProxy*"));
1322 function.add_parameter (new CCodeFormalParameter ("interface_name", "const gchar*"));
1323 function.add_parameter (new CCodeFormalParameter ("error", "GError**"));
1325 var block = new CCodeBlock ();
1326 var prefragment = new CCodeFragment ();
1327 var postfragment = new CCodeFragment ();
1329 var cdecl = new CCodeDeclaration ("DBusError");
1330 cdecl.add_declarator (new CCodeVariableDeclarator ("_dbus_error"));
1331 block.add_statement (cdecl);
1333 var dbus_error = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_dbus_error"));
1335 cdecl = new CCodeDeclaration ("DBusGConnection");
1336 cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection"));
1337 block.add_statement (cdecl);
1339 cdecl = new CCodeDeclaration ("DBusMessage");
1340 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
1341 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
1342 block.add_statement (cdecl);
1344 cdecl = new CCodeDeclaration ("DBusMessageIter");
1345 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
1346 block.add_statement (cdecl);
1348 block.add_statement (prefragment);
1350 generate_marshalling (m, "org.freedesktop.DBus.Properties", prefragment, postfragment);
1352 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
1353 gconnection.add_argument (new CCodeIdentifier ("self"));
1354 gconnection.add_argument (new CCodeConstant ("\"connection\""));
1355 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection")));
1356 gconnection.add_argument (new CCodeConstant ("NULL"));
1357 block.add_statement (new CCodeExpressionStatement (gconnection));
1359 var dbus_error_init = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_init"));
1360 dbus_error_init.add_argument (dbus_error);
1361 block.add_statement (new CCodeExpressionStatement (dbus_error_init));
1363 var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
1364 connection.add_argument (new CCodeIdentifier ("_connection"));
1366 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send_with_reply_and_block"));
1367 ccall.add_argument (connection);
1368 ccall.add_argument (new CCodeIdentifier ("_message"));
1369 ccall.add_argument (get_dbus_timeout (m));
1370 ccall.add_argument (dbus_error);
1371 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
1373 var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
1374 conn_unref.add_argument (new CCodeIdentifier ("_connection"));
1375 block.add_statement (new CCodeExpressionStatement (conn_unref));
1377 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1378 message_unref.add_argument (new CCodeIdentifier ("_message"));
1379 block.add_statement (new CCodeExpressionStatement (message_unref));
1381 check_error_reply (m, block);
1382 check_reply_signature (m, block);
1384 block.add_statement (postfragment);
1386 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1387 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
1388 block.add_statement (new CCodeExpressionStatement (reply_unref));
1390 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
1392 source_declarations.add_type_member_declaration (function.copy ());
1394 function.block = block;
1395 source_type_member_definition.append (function);
1397 return get_all_func;
1400 public override void visit_method_call (MethodCall expr) {
1401 var mtype = expr.call.value_type as MethodType;
1402 bool proxy_new_from_type = (mtype != null && mtype.method_symbol.get_cname () == "dbus_g_proxy_new_from_type");
1403 bool proxy_get_all = (mtype != null && mtype.method_symbol.get_cname () == "dbus_g_proxy_get_all");
1404 if (!proxy_new_from_type && !proxy_get_all) {
1405 base.visit_method_call (expr);
1406 return;
1409 if (proxy_get_all) {
1410 var ma = expr.call as MemberAccess;
1411 var instance = ma.inner;
1412 instance.emit (this);
1414 var args = expr.get_argument_list ();
1415 Expression interface_name = args.get (0);
1416 interface_name.emit (this);
1418 var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_get_all_function (mtype.method_symbol)));
1419 ccall.add_argument ((CCodeExpression) instance.ccodenode);
1420 ccall.add_argument ((CCodeExpression) interface_name.ccodenode);
1422 current_method_inner_error = true;
1423 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
1425 expr.ccodenode = ccall;
1426 return;
1429 var args = expr.get_argument_list ();
1430 Expression connection = ((MemberAccess) expr.call).inner;
1431 Expression bus_name = args.get (0);
1432 Expression object_path = args.get (1);
1433 Expression interface_name = args.get (2);
1434 Expression type = args.get (3);
1436 var quark_call = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
1437 quark_call.add_argument (new CCodeConstant ("\"ValaDBusInterfaceProxyType\""));
1439 var qdata_call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
1440 type.emit (this);
1441 qdata_call.add_argument ((CCodeExpression) type.ccodenode);
1442 qdata_call.add_argument (quark_call);
1444 var get_type_call = new CCodeFunctionCall (new CCodeCastExpression (qdata_call, "GType (*)(void)"));
1446 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new"));
1447 ccall.add_argument (get_type_call);
1448 ccall.add_argument (new CCodeConstant ("\"connection\""));
1449 connection.emit (this);
1450 ccall.add_argument ((CCodeExpression) connection.ccodenode);
1451 ccall.add_argument (new CCodeConstant ("\"name\""));
1452 bus_name.emit (this);
1453 ccall.add_argument ((CCodeExpression) bus_name.ccodenode);
1454 ccall.add_argument (new CCodeConstant ("\"path\""));
1455 object_path.emit (this);
1456 ccall.add_argument ((CCodeExpression) object_path.ccodenode);
1457 ccall.add_argument (new CCodeConstant ("\"interface\""));
1458 interface_name.emit (this);
1459 ccall.add_argument ((CCodeExpression) interface_name.ccodenode);
1460 ccall.add_argument (new CCodeConstant ("NULL"));
1461 expr.ccodenode = ccall;
1464 void generate_proxy_filter_function (Interface iface) {
1465 string lower_cname = iface.get_lower_case_cprefix () + "dbus_proxy";
1467 var proxy_filter = new CCodeFunction (lower_cname + "_filter", "DBusHandlerResult");
1468 proxy_filter.add_parameter (new CCodeFormalParameter ("connection", "DBusConnection*"));
1469 proxy_filter.add_parameter (new CCodeFormalParameter ("message", "DBusMessage*"));
1470 proxy_filter.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
1472 var filter_block = new CCodeBlock ();
1474 // only handle signals concering the object path
1475 var path = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_path"));
1476 path.add_argument (new CCodeIdentifier ("user_data"));
1478 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_has_path"));
1479 ccheck.add_argument (new CCodeIdentifier ("message"));
1480 ccheck.add_argument (path);
1482 var object_filter_block = new CCodeBlock ();
1483 filter_block.add_statement (new CCodeIfStatement (ccheck, object_filter_block));
1485 handle_signals (iface, object_filter_block);
1487 filter_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
1489 source_declarations.add_type_member_declaration (proxy_filter.copy ());
1490 proxy_filter.block = filter_block;
1491 source_type_member_definition.append (proxy_filter);
1494 string generate_dbus_signal_handler (Signal sig, ObjectTypeSymbol sym) {
1495 string wrapper_name = "_dbus_handle_%s_%s".printf (sym.get_lower_case_cname (), sig.get_cname ());
1497 // declaration
1499 CCodeDeclaration cdecl;
1501 var function = new CCodeFunction (wrapper_name, "void");
1502 function.modifiers = CCodeModifiers.STATIC;
1504 function.add_parameter (new CCodeFormalParameter ("self", sym.get_cname () + "*"));
1505 function.add_parameter (new CCodeFormalParameter ("connection", "DBusConnection*"));
1506 function.add_parameter (new CCodeFormalParameter ("message", "DBusMessage*"));
1508 var block = new CCodeBlock ();
1509 var prefragment = new CCodeFragment ();
1510 var postfragment = new CCodeFragment ();
1512 cdecl = new CCodeDeclaration ("DBusMessageIter");
1513 cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
1514 block.add_statement (cdecl);
1516 block.add_statement (prefragment);
1518 var message_signature = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_get_signature"));
1519 message_signature.add_argument (new CCodeIdentifier ("message"));
1520 var signature_check = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
1521 signature_check.add_argument (message_signature);
1522 var signature_error_block = new CCodeBlock ();
1523 signature_error_block.add_statement (new CCodeReturnStatement ());
1524 prefragment.append (new CCodeIfStatement (signature_check, signature_error_block));
1526 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
1527 iter_call.add_argument (new CCodeIdentifier ("message"));
1528 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
1529 prefragment.append (new CCodeExpressionStatement (iter_call));
1531 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
1532 ccall.add_argument (new CCodeIdentifier ("self"));
1533 ccall.add_argument (sig.get_canonical_cconstant ());
1535 // expected type signature for input parameters
1536 string type_signature = "";
1538 foreach (FormalParameter param in sig.get_parameters ()) {
1539 var owned_type = param.variable_type.copy ();
1540 owned_type.value_owned = true;
1542 cdecl = new CCodeDeclaration (owned_type.get_cname ());
1543 cdecl.add_declarator (new CCodeVariableDeclarator.zero (param.name, default_value_for_type (param.variable_type, true)));
1544 prefragment.append (cdecl);
1546 if (get_type_signature (param.variable_type) == null) {
1547 Report.error (param.variable_type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (param.variable_type.to_string ()));
1548 continue;
1551 var st = param.variable_type.data_type as Struct;
1552 if (st != null && !st.is_simple_type ()) {
1553 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
1554 } else {
1555 ccall.add_argument (new CCodeIdentifier (param.name));
1558 if (param.variable_type is ArrayType) {
1559 var array_type = (ArrayType) param.variable_type;
1561 for (int dim = 1; dim <= array_type.rank; dim++) {
1562 string length_cname = get_array_length_cname (param.name, dim);
1564 cdecl = new CCodeDeclaration ("int");
1565 cdecl.add_declarator (new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
1566 prefragment.append (cdecl);
1567 ccall.add_argument (new CCodeIdentifier (length_cname));
1571 type_signature += get_type_signature (param.variable_type);
1573 var target = new CCodeIdentifier (param.name);
1574 var expr = read_expression (prefragment, param.variable_type, new CCodeIdentifier ("iter"), target);
1575 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1577 if (requires_destroy (owned_type)) {
1578 // keep local alive (symbol_reference is weak)
1579 var local = new LocalVariable (owned_type, param.name);
1580 var ma = new MemberAccess.simple (param.name);
1581 ma.symbol_reference = local;
1582 var stmt = new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (param.name), owned_type, ma));
1583 postfragment.append (stmt);
1587 signature_check.add_argument (new CCodeConstant ("\"%s\"".printf (type_signature)));
1589 block.add_statement (new CCodeExpressionStatement (ccall));
1591 block.add_statement (postfragment);
1593 cdecl = new CCodeDeclaration ("DBusMessage*");
1594 cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
1595 block.add_statement (cdecl);
1597 source_declarations.add_type_member_declaration (function.copy ());
1599 function.block = block;
1600 source_type_member_definition.append (function);
1602 return wrapper_name;
1605 void handle_signal (string dbus_iface_name, string dbus_signal_name, string handler_name, CCodeBlock block, ref CCodeIfStatement clastif) {
1606 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_is_signal"));
1607 ccheck.add_argument (new CCodeIdentifier ("message"));
1608 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
1609 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_signal_name)));
1611 var callblock = new CCodeBlock ();
1613 var ccall = new CCodeFunctionCall (new CCodeIdentifier (handler_name));
1614 ccall.add_argument (new CCodeIdentifier ("user_data"));
1615 ccall.add_argument (new CCodeIdentifier ("connection"));
1616 ccall.add_argument (new CCodeIdentifier ("message"));
1618 callblock.add_statement (new CCodeExpressionStatement (ccall));
1620 var cif = new CCodeIfStatement (ccheck, callblock);
1621 if (clastif == null) {
1622 block.add_statement (cif);
1623 } else {
1624 clastif.false_statement = cif;
1627 clastif = cif;
1630 void handle_signals (Interface iface, CCodeBlock block) {
1631 string dbus_iface_name = get_dbus_name (iface);
1633 CCodeIfStatement clastif = null;
1634 foreach (Signal sig in iface.get_signals ()) {
1635 if (sig.access != SymbolAccessibility.PUBLIC) {
1636 continue;
1639 handle_signal (dbus_iface_name, get_dbus_name_for_member (sig), generate_dbus_signal_handler (sig, iface), block, ref clastif);
1643 void generate_marshalling (Method m, string dbus_iface_name, CCodeFragment prefragment, CCodeFragment postfragment) {
1644 CCodeDeclaration cdecl;
1646 var no_reply = is_dbus_no_reply (m);
1648 var destination = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_bus_name"));
1649 destination.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*"));
1650 var path = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_path"));
1651 path.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*"));
1653 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_call"));
1654 msgcall.add_argument (destination);
1655 msgcall.add_argument (path);
1656 msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
1657 msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (m))));
1658 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_message"), msgcall)));
1660 if (no_reply) {
1661 var noreplycall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_set_no_reply"));
1662 noreplycall.add_argument (new CCodeIdentifier ("_message"));
1663 noreplycall.add_argument (new CCodeConstant ("TRUE"));
1664 prefragment.append (new CCodeExpressionStatement (noreplycall));
1667 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
1668 iter_call.add_argument (new CCodeIdentifier ("_message"));
1669 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
1670 prefragment.append (new CCodeExpressionStatement (iter_call));
1672 if (!no_reply) {
1673 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
1674 iter_call.add_argument (new CCodeIdentifier ("_reply"));
1675 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
1676 postfragment.append (new CCodeExpressionStatement (iter_call));
1679 foreach (FormalParameter param in m.get_parameters ()) {
1680 if (param.direction == ParameterDirection.IN) {
1681 if (param.variable_type.data_type != null
1682 && param.variable_type.data_type.get_full_name () == "DBus.BusName") {
1683 // ignore BusName sender parameters
1684 continue;
1686 CCodeExpression expr = new CCodeIdentifier (param.name);
1687 if (param.variable_type.is_real_struct_type ()) {
1688 expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
1690 write_expression (prefragment, param.variable_type, new CCodeIdentifier ("_iter"), expr);
1691 } else {
1692 if (no_reply) {
1693 Report.error (param.source_reference, "No-reply DBus methods must not have out parameters");
1694 break;
1696 cdecl = new CCodeDeclaration (param.variable_type.get_cname ());
1697 cdecl.add_declarator (new CCodeVariableDeclarator ("_" + param.name));
1698 postfragment.append (cdecl);
1700 var array_type = param.variable_type as ArrayType;
1702 if (array_type != null) {
1703 for (int dim = 1; dim <= array_type.rank; dim++) {
1704 cdecl = new CCodeDeclaration ("int");
1705 cdecl.add_declarator (new CCodeVariableDeclarator ("_%s_length%d".printf (param.name, dim), new CCodeConstant ("0")));
1706 postfragment.append (cdecl);
1710 var target = new CCodeIdentifier ("_" + param.name);
1711 var expr = read_expression (postfragment, param.variable_type, new CCodeIdentifier ("_iter"), target);
1712 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1714 // TODO check that parameter is not NULL (out parameters are optional)
1715 // free value if parameter is NULL
1716 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), target)));
1719 if (array_type != null) {
1720 for (int dim = 1; dim <= array_type.rank; dim++) {
1721 // TODO check that parameter is not NULL (out parameters are optional)
1722 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)))));
1728 if (!(m.return_type is VoidType)) {
1729 if (no_reply) {
1730 Report.error (m.return_type.source_reference, "No-reply DBus methods must return void");
1732 if (m.return_type.is_real_non_null_struct_type ()) {
1733 var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
1734 var expr = read_expression (postfragment, m.return_type, new CCodeIdentifier ("_iter"), target);
1735 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1736 } else {
1737 cdecl = new CCodeDeclaration (m.return_type.get_cname ());
1738 cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
1739 postfragment.append (cdecl);
1741 var array_type = m.return_type as ArrayType;
1743 if (array_type != null) {
1744 for (int dim = 1; dim <= array_type.rank; dim++) {
1745 cdecl = new CCodeDeclaration ("int");
1746 cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
1747 postfragment.append (cdecl);
1751 var target = new CCodeIdentifier ("_result");
1752 var expr = read_expression (postfragment, m.return_type, new CCodeIdentifier ("_iter"), target);
1753 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1755 if (array_type != null) {
1756 for (int dim = 1; dim <= array_type.rank; dim++) {
1757 // TODO check that parameter is not NULL (out parameters are optional)
1758 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)))));
1765 void check_error_reply (Method m, CCodeBlock block) {
1766 var error_types = m.get_error_types ();
1767 if (!has_dbus_error (error_types)) {
1768 Report.error (m.source_reference, "D-Bus methods must throw DBus.Error");
1769 return;
1771 if (is_dbus_no_reply (m)) {
1772 // no-reply messages throw no error
1773 return;
1776 var dbus_error = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_dbus_error"));
1778 var error_block = new CCodeBlock ();
1780 var cdecl = new CCodeDeclaration ("GQuark");
1781 cdecl.add_declarator (new CCodeVariableDeclarator ("_edomain"));
1782 error_block.add_statement (cdecl);
1784 cdecl = new CCodeDeclaration ("gint");
1785 cdecl.add_declarator (new CCodeVariableDeclarator ("_ecode"));
1786 error_block.add_statement (cdecl);
1788 generate_client_error_cases (error_block, error_types, new CCodeMemberAccess (new CCodeIdentifier ("_dbus_error"), "name"), new CCodeIdentifier ("_edomain"), new CCodeIdentifier ("_ecode"));
1790 var g_set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
1791 g_set_error.add_argument (new CCodeIdentifier ("error"));
1792 g_set_error.add_argument (new CCodeIdentifier ("_edomain"));
1793 g_set_error.add_argument (new CCodeIdentifier ("_ecode"));
1794 g_set_error.add_argument (new CCodeConstant ("\"%s\""));
1795 g_set_error.add_argument (new CCodeMemberAccess (new CCodeIdentifier ("_dbus_error"), "message"));
1796 error_block.add_statement (new CCodeExpressionStatement (g_set_error));
1798 var dbus_error_free = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_free"));
1799 dbus_error_free.add_argument (dbus_error);
1800 error_block.add_statement (new CCodeExpressionStatement (dbus_error_free));
1802 if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
1803 error_block.add_statement (new CCodeReturnStatement ());
1804 } else {
1805 error_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
1808 var dbus_error_is_set = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_is_set"));
1809 dbus_error_is_set.add_argument (dbus_error);
1810 block.add_statement (new CCodeIfStatement (dbus_error_is_set, error_block));
1813 string generate_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
1814 string proxy_name = "%sdbus_proxy_%s".printf (main_iface.get_lower_case_cprefix (), m.name);
1816 string dbus_iface_name = get_dbus_name (iface);
1818 CCodeDeclaration cdecl;
1820 var function = new CCodeFunction (proxy_name);
1821 function.modifiers = CCodeModifiers.STATIC;
1823 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
1825 generate_cparameters (m, source_declarations, cparam_map, function);
1827 var block = new CCodeBlock ();
1828 var prefragment = new CCodeFragment ();
1829 var postfragment = new CCodeFragment ();
1831 // throw error and return if proxy is disposed
1832 var dispose_return_block = new CCodeBlock ();
1833 if (m.get_error_types ().size > 0) {
1834 var set_error_call = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
1835 set_error_call.add_argument (new CCodeIdentifier ("error"));
1836 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR"));
1837 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR_DISCONNECTED"));
1838 set_error_call.add_argument (new CCodeConstant ("\"%s\""));
1839 set_error_call.add_argument (new CCodeConstant ("\"Connection is closed\""));
1840 dispose_return_block.add_statement (new CCodeExpressionStatement (set_error_call));
1842 if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
1843 dispose_return_block.add_statement (new CCodeReturnStatement ());
1844 } else {
1845 dispose_return_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
1847 block.add_statement (new CCodeIfStatement (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("self"), iface.get_cname () + "DBusProxy*"), "disposed"), dispose_return_block));
1849 cdecl = new CCodeDeclaration ("DBusError");
1850 cdecl.add_declarator (new CCodeVariableDeclarator ("_dbus_error"));
1851 block.add_statement (cdecl);
1853 var dbus_error = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_dbus_error"));
1855 cdecl = new CCodeDeclaration ("DBusGConnection");
1856 cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection"));
1857 block.add_statement (cdecl);
1859 cdecl = new CCodeDeclaration ("DBusMessage");
1860 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
1861 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
1862 block.add_statement (cdecl);
1864 cdecl = new CCodeDeclaration ("DBusMessageIter");
1865 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
1866 block.add_statement (cdecl);
1868 block.add_statement (prefragment);
1870 generate_marshalling (m, dbus_iface_name, prefragment, postfragment);
1872 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
1873 gconnection.add_argument (new CCodeIdentifier ("self"));
1874 gconnection.add_argument (new CCodeConstant ("\"connection\""));
1875 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection")));
1876 gconnection.add_argument (new CCodeConstant ("NULL"));
1877 block.add_statement (new CCodeExpressionStatement (gconnection));
1879 var dbus_error_init = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_init"));
1880 dbus_error_init.add_argument (dbus_error);
1881 block.add_statement (new CCodeExpressionStatement (dbus_error_init));
1883 var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
1884 connection.add_argument (new CCodeIdentifier ("_connection"));
1886 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send_with_reply_and_block"));
1887 ccall.add_argument (connection);
1888 ccall.add_argument (new CCodeIdentifier ("_message"));
1889 ccall.add_argument (get_dbus_timeout (m));
1890 ccall.add_argument (dbus_error);
1891 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
1893 var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
1894 conn_unref.add_argument (new CCodeIdentifier ("_connection"));
1895 block.add_statement (new CCodeExpressionStatement (conn_unref));
1897 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1898 message_unref.add_argument (new CCodeIdentifier ("_message"));
1899 block.add_statement (new CCodeExpressionStatement (message_unref));
1901 check_error_reply (m, block);
1902 check_reply_signature (m, block);
1904 block.add_statement (postfragment);
1906 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1907 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
1908 block.add_statement (new CCodeExpressionStatement (reply_unref));
1910 if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
1911 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
1914 source_declarations.add_type_member_declaration (function.copy ());
1915 function.block = block;
1916 source_type_member_definition.append (function);
1918 return proxy_name;
1921 string generate_noreply_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
1922 string proxy_name = "%sdbus_proxy_%s".printf (main_iface.get_lower_case_cprefix (), m.name);
1924 string dbus_iface_name = get_dbus_name (iface);
1926 CCodeDeclaration cdecl;
1928 var function = new CCodeFunction (proxy_name);
1929 function.modifiers = CCodeModifiers.STATIC;
1931 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
1933 generate_cparameters (m, source_declarations, cparam_map, function);
1935 var block = new CCodeBlock ();
1936 var prefragment = new CCodeFragment ();
1937 var postfragment = new CCodeFragment ();
1939 // throw error and return if proxy is disposed
1940 var dispose_return_block = new CCodeBlock ();
1941 if (m.get_error_types ().size > 0) {
1942 var set_error_call = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
1943 set_error_call.add_argument (new CCodeIdentifier ("error"));
1944 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR"));
1945 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR_DISCONNECTED"));
1946 set_error_call.add_argument (new CCodeConstant ("\"%s\""));
1947 set_error_call.add_argument (new CCodeConstant ("\"Connection is closed\""));
1948 dispose_return_block.add_statement (new CCodeExpressionStatement (set_error_call));
1949 dispose_return_block.add_statement (new CCodeReturnStatement ());
1951 block.add_statement (new CCodeIfStatement (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("self"), iface.get_cname () + "DBusProxy*"), "disposed"), dispose_return_block));
1953 cdecl = new CCodeDeclaration ("DBusGConnection");
1954 cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection"));
1955 block.add_statement (cdecl);
1957 cdecl = new CCodeDeclaration ("DBusMessage");
1958 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
1959 block.add_statement (cdecl);
1961 cdecl = new CCodeDeclaration ("DBusMessageIter");
1962 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
1963 block.add_statement (cdecl);
1965 block.add_statement (prefragment);
1967 generate_marshalling (m, dbus_iface_name, prefragment, postfragment);
1969 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
1970 gconnection.add_argument (new CCodeIdentifier ("self"));
1971 gconnection.add_argument (new CCodeConstant ("\"connection\""));
1972 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection")));
1973 gconnection.add_argument (new CCodeConstant ("NULL"));
1974 block.add_statement (new CCodeExpressionStatement (gconnection));
1976 var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
1977 connection.add_argument (new CCodeIdentifier ("_connection"));
1979 var oom_return_block = new CCodeBlock ();
1980 if (m.get_error_types ().size > 0) {
1981 var set_error_call = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
1982 set_error_call.add_argument (new CCodeIdentifier ("error"));
1983 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR"));
1984 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR_NO_MEMORY"));
1985 set_error_call.add_argument (new CCodeConstant ("\"%s\""));
1986 set_error_call.add_argument (new CCodeConstant ("\"Out of memory\""));
1987 oom_return_block.add_statement (new CCodeExpressionStatement (set_error_call));
1988 oom_return_block.add_statement (new CCodeReturnStatement ());
1991 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send"));
1992 ccall.add_argument (connection);
1993 ccall.add_argument (new CCodeIdentifier ("_message"));
1994 ccall.add_argument (new CCodeConstant ("NULL"));
1995 block.add_statement (new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, ccall), oom_return_block));
1997 var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
1998 conn_unref.add_argument (new CCodeIdentifier ("_connection"));
1999 block.add_statement (new CCodeExpressionStatement (conn_unref));
2001 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2002 message_unref.add_argument (new CCodeIdentifier ("_message"));
2003 block.add_statement (new CCodeExpressionStatement (message_unref));
2005 check_error_reply (m, block);
2007 block.add_statement (postfragment);
2009 source_declarations.add_type_member_declaration (function.copy ());
2010 function.block = block;
2011 source_type_member_definition.append (function);
2013 return proxy_name;
2016 void generate_client_error_cases (CCodeBlock error_block, List<DataType> error_types, CCodeExpression dbus_error_name, CCodeExpression result_edomain, CCodeExpression result_ecode) {
2017 CCodeStatement if_else_if = null;
2018 CCodeIfStatement last_statement = null;
2020 foreach (DataType error_type in error_types) {
2021 var edomain = ((ErrorType) error_type).error_domain;
2023 if (edomain == null) {
2024 Report.error (error_type.source_reference, "Generic errors cannot be serialized over DBus");
2025 continue;
2028 var edomain_dbus_name = get_dbus_name (edomain);
2029 if (edomain_dbus_name == null) {
2030 Report.error (edomain.source_reference, "Errordomain must have a DBus.name annotation to be serialized over DBus");
2033 var true_block = new CCodeBlock ();
2034 true_block.suppress_newline = true;
2036 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
2038 var cdecl = new CCodeDeclaration ("const char*");
2039 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
2040 true_block.add_statement (cdecl);
2042 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (result_edomain, new CCodeIdentifier (edomain.get_upper_case_cname ()))));
2044 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, dbus_error_name, new CCodeConstant ("%ld".printf (edomain_dbus_name.length + 1))))));
2046 CCodeStatement inner_if_else_if = null;
2047 CCodeIfStatement inner_last_statement = null;
2048 foreach (ErrorCode ecode in edomain.get_codes ()) {
2049 var inner_true_block = new CCodeBlock ();
2050 inner_true_block.suppress_newline = true;
2051 inner_true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (result_ecode, new CCodeIdentifier (ecode.get_cname ()))));
2053 var ecode_dbus_name = get_dbus_name (ecode);
2054 if (ecode_dbus_name == null) {
2055 ecode_dbus_name = Symbol.lower_case_to_camel_case (ecode.name.down ());
2058 var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
2059 string_comparison.add_argument (new CCodeIdentifier (temp_name));
2060 string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (ecode_dbus_name)));
2061 var stmt = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0")), inner_true_block);
2063 if (inner_last_statement != null) {
2064 inner_last_statement.false_statement = stmt;
2065 } else {
2066 inner_if_else_if = stmt;
2068 inner_last_statement = stmt;
2070 true_block.add_statement (inner_if_else_if);
2072 var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strstr"));
2073 string_comparison.add_argument (dbus_error_name);
2074 string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (edomain_dbus_name)));
2075 var stmt = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, dbus_error_name), true_block);
2077 if (last_statement != null) {
2078 last_statement.false_statement = stmt;
2079 } else {
2080 if_else_if = stmt;
2082 last_statement = stmt;
2084 error_block.add_statement (if_else_if);
2087 string generate_async_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
2088 string proxy_name = "%sdbus_proxy_%s_async".printf (main_iface.get_lower_case_cprefix (), m.name);
2090 string dbus_iface_name = get_dbus_name (iface);
2092 CCodeDeclaration cdecl;
2095 // generate data struct
2097 string dataname = "%sDBusProxy%sData".printf (iface.get_cname (), Symbol.lower_case_to_camel_case (m.name));
2098 var datastruct = new CCodeStruct ("_" + dataname);
2100 datastruct.add_field ("GAsyncReadyCallback", "_callback_");
2101 datastruct.add_field ("gpointer", "_user_data_");
2102 datastruct.add_field ("DBusPendingCall*", "pending");
2104 source_declarations.add_type_definition (datastruct);
2105 source_declarations.add_type_declaration (new CCodeTypeDefinition ("struct _" + dataname, new CCodeVariableDeclarator (dataname)));
2108 // generate async function
2110 var function = new CCodeFunction (proxy_name, "void");
2111 function.modifiers = CCodeModifiers.STATIC;
2113 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
2115 cparam_map.set (get_param_pos (-1), new CCodeFormalParameter ("_callback_", "GAsyncReadyCallback"));
2116 cparam_map.set (get_param_pos (-0.9), new CCodeFormalParameter ("_user_data_", "gpointer"));
2118 generate_cparameters (m, source_declarations, cparam_map, function, null, null, null, 1);
2120 var block = new CCodeBlock ();
2121 var prefragment = new CCodeFragment ();
2122 var postfragment = new CCodeFragment ();
2124 cdecl = new CCodeDeclaration ("DBusGConnection");
2125 cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection"));
2126 block.add_statement (cdecl);
2128 cdecl = new CCodeDeclaration ("DBusMessage");
2129 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
2130 block.add_statement (cdecl);
2132 cdecl = new CCodeDeclaration ("DBusPendingCall");
2133 cdecl.add_declarator (new CCodeVariableDeclarator ("*_pending"));
2134 block.add_statement (cdecl);
2136 cdecl = new CCodeDeclaration ("DBusMessageIter");
2137 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
2138 block.add_statement (cdecl);
2140 block.add_statement (prefragment);
2142 generate_marshalling (m, dbus_iface_name, prefragment, postfragment);
2144 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
2145 gconnection.add_argument (new CCodeIdentifier ("self"));
2146 gconnection.add_argument (new CCodeConstant ("\"connection\""));
2147 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection")));
2148 gconnection.add_argument (new CCodeConstant ("NULL"));
2149 block.add_statement (new CCodeExpressionStatement (gconnection));
2151 var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
2152 connection.add_argument (new CCodeIdentifier ("_connection"));
2154 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send_with_reply"));
2155 ccall.add_argument (connection);
2156 ccall.add_argument (new CCodeIdentifier ("_message"));
2157 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_pending")));
2158 ccall.add_argument (get_dbus_timeout (m));
2159 block.add_statement (new CCodeExpressionStatement (ccall));
2161 var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
2162 conn_unref.add_argument (new CCodeIdentifier ("_connection"));
2163 block.add_statement (new CCodeExpressionStatement (conn_unref));
2165 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2166 message_unref.add_argument (new CCodeIdentifier ("_message"));
2167 block.add_statement (new CCodeExpressionStatement (message_unref));
2169 var dataalloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
2170 dataalloc.add_argument (new CCodeIdentifier (dataname));
2172 var datadecl = new CCodeDeclaration (dataname + "*");
2173 datadecl.add_declarator (new CCodeVariableDeclarator ("_data_"));
2174 block.add_statement (datadecl);
2175 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_data_"), dataalloc)));
2177 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_callback_"), new CCodeIdentifier ("_callback_"))));
2178 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_user_data_"), new CCodeIdentifier ("_user_data_"))));
2179 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "pending"), new CCodeIdentifier ("_pending"))));
2181 var pending = new CCodeFunctionCall (new CCodeIdentifier ("dbus_pending_call_set_notify"));
2182 pending.add_argument (new CCodeIdentifier ("_pending"));
2183 pending.add_argument (new CCodeIdentifier ("%sdbus_proxy_%s_ready".printf (iface.get_lower_case_cprefix (), m.name)));
2184 pending.add_argument (new CCodeIdentifier ("_data_"));
2185 pending.add_argument (new CCodeConstant ("NULL"));
2186 block.add_statement (new CCodeExpressionStatement (pending));
2188 source_declarations.add_type_member_declaration (function.copy ());
2189 function.block = block;
2190 source_type_member_definition.append (function);
2193 // generate ready function
2195 function = new CCodeFunction ("%sdbus_proxy_%s_ready".printf (iface.get_lower_case_cprefix (), m.name), "void");
2196 function.modifiers = CCodeModifiers.STATIC;
2198 function.add_parameter (new CCodeFormalParameter ("pending", "DBusPendingCall*"));
2199 function.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
2201 block = new CCodeBlock ();
2203 datadecl = new CCodeDeclaration (dataname + "*");
2204 datadecl.add_declarator (new CCodeVariableDeclarator ("_data_"));
2205 block.add_statement (datadecl);
2206 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_data_"), new CCodeIdentifier ("user_data"))));
2208 // complete async call by invoking callback
2209 var obj_decl = new CCodeDeclaration ("GObject *");
2210 obj_decl.add_declarator (new CCodeVariableDeclarator ("_obj_"));
2211 block.add_statement (obj_decl);
2213 var object_creation = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
2214 object_creation.add_argument (new CCodeConstant ("G_TYPE_OBJECT"));
2215 object_creation.add_argument (new CCodeConstant ("0"));
2216 object_creation.add_argument (new CCodeConstant ("NULL"));
2217 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_obj_"), object_creation)));
2219 var async_result_decl = new CCodeDeclaration ("GSimpleAsyncResult *");
2220 async_result_decl.add_declarator (new CCodeVariableDeclarator ("_res_"));
2221 block.add_statement (async_result_decl);
2223 var async_result_creation = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_new"));
2224 async_result_creation.add_argument (new CCodeIdentifier ("_obj_"));
2225 async_result_creation.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_callback_"));
2226 async_result_creation.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_user_data_"));
2227 async_result_creation.add_argument (new CCodeIdentifier ("_data_"));
2228 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_res_"), async_result_creation)));
2230 var completecall = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
2231 completecall.add_argument (new CCodeIdentifier ("_res_"));
2232 block.add_statement (new CCodeExpressionStatement (completecall));
2234 var obj_free = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
2235 obj_free.add_argument (new CCodeIdentifier ("_obj_"));
2236 block.add_statement (new CCodeExpressionStatement (obj_free));
2238 var async_result_free = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
2239 async_result_free.add_argument (new CCodeIdentifier ("_res_"));
2240 block.add_statement (new CCodeExpressionStatement (async_result_free));
2242 var datafree = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
2243 datafree.add_argument (new CCodeIdentifier (dataname));
2244 datafree.add_argument (new CCodeIdentifier ("_data_"));
2245 block.add_statement (new CCodeExpressionStatement (datafree));
2247 var pendingfree = new CCodeFunctionCall (new CCodeIdentifier ("dbus_pending_call_unref"));
2248 pendingfree.add_argument (new CCodeIdentifier ("pending"));
2249 block.add_statement (new CCodeExpressionStatement (pendingfree));
2251 source_declarations.add_type_member_declaration (function.copy ());
2252 function.block = block;
2253 source_type_member_definition.append (function);
2256 return proxy_name;
2259 CCodeConstant get_reply_signature (Method m) {
2260 // expected type signature for output parameters
2261 string type_signature = "";
2263 foreach (FormalParameter param in m.get_parameters ()) {
2264 if (param.direction == ParameterDirection.OUT) {
2265 type_signature += get_type_signature (param.variable_type);
2269 if (!(m.return_type is VoidType)) {
2270 type_signature += get_type_signature (m.return_type);
2273 return (new CCodeConstant ("\"%s\"".printf (type_signature)));
2276 void check_reply_signature (Method m, CCodeBlock block) {
2277 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2278 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
2280 var message_signature = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_get_signature"));
2281 message_signature.add_argument (new CCodeIdentifier ("_reply"));
2283 var signature_check = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
2284 signature_check.add_argument (message_signature);
2285 signature_check.add_argument (get_reply_signature (m));
2287 var signature_error_block = new CCodeBlock ();
2288 var set_error_call = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
2289 set_error_call.add_argument (new CCodeIdentifier ("error"));
2290 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR"));
2291 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR_INVALID_SIGNATURE"));
2292 set_error_call.add_argument (new CCodeConstant ("\"Invalid signature, expected \\\"%s\\\", got \\\"%s\\\"\""));
2293 set_error_call.add_argument (get_reply_signature (m));
2294 set_error_call.add_argument (message_signature);
2295 signature_error_block.add_statement (new CCodeExpressionStatement (set_error_call));
2296 signature_error_block.add_statement (new CCodeExpressionStatement (reply_unref));
2297 signature_error_block.add_statement (new CCodeReturnStatement (default_value_for_type (m.return_type, false)));
2299 block.add_statement (new CCodeIfStatement (signature_check, signature_error_block));
2302 string generate_finish_dbus_proxy_method (Interface main_iface, Interface iface, Method m) {
2303 string proxy_name = "%sdbus_proxy_%s_finish".printf (main_iface.get_lower_case_cprefix (), m.name);
2305 string dbus_iface_name = get_dbus_name (iface);
2307 CCodeDeclaration cdecl;
2309 var function = new CCodeFunction (proxy_name);
2310 function.modifiers = CCodeModifiers.STATIC;
2312 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
2314 cparam_map.set (get_param_pos (0.1), new CCodeFormalParameter ("_res_", "GAsyncResult*"));
2316 generate_cparameters (m, source_declarations, cparam_map, function, null, null, null, 2);
2318 var block = new CCodeBlock ();
2319 var prefragment = new CCodeFragment ();
2320 var postfragment = new CCodeFragment ();
2322 string dataname = "%sDBusProxy%sData".printf (iface.get_cname (), Symbol.lower_case_to_camel_case (m.name));
2323 cdecl = new CCodeDeclaration (dataname + "*");
2324 cdecl.add_declarator (new CCodeVariableDeclarator ("_data_"));
2325 block.add_statement (cdecl);
2327 cdecl = new CCodeDeclaration ("DBusError");
2328 cdecl.add_declarator (new CCodeVariableDeclarator ("_dbus_error"));
2329 block.add_statement (cdecl);
2331 var dbus_error = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_dbus_error"));
2333 cdecl = new CCodeDeclaration ("DBusMessage");
2334 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
2335 block.add_statement (cdecl);
2337 cdecl = new CCodeDeclaration ("DBusMessageIter");
2338 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
2339 block.add_statement (cdecl);
2341 var get_source_tag = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_get_source_tag"));
2342 get_source_tag.add_argument (new CCodeCastExpression (new CCodeIdentifier ("_res_"), "GSimpleAsyncResult *"));
2343 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_data_"), get_source_tag)));
2345 var dbus_error_init = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_init"));
2346 dbus_error_init.add_argument (dbus_error);
2347 block.add_statement (new CCodeExpressionStatement (dbus_error_init));
2349 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_pending_call_steal_reply"));
2350 ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "pending"));
2351 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
2353 var set_error_from_message = new CCodeFunctionCall (new CCodeIdentifier ("dbus_set_error_from_message"));
2354 set_error_from_message.add_argument (dbus_error);
2355 set_error_from_message.add_argument (new CCodeIdentifier ("_reply"));
2356 block.add_statement (new CCodeExpressionStatement (set_error_from_message));
2358 check_error_reply (m, block);
2359 check_reply_signature (m, block);
2361 generate_marshalling (m, dbus_iface_name, prefragment, postfragment);
2363 block.add_statement (postfragment);
2365 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2366 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
2367 block.add_statement (new CCodeExpressionStatement (reply_unref));
2369 if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) {
2370 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
2373 source_declarations.add_type_member_declaration (function.copy ());
2374 function.block = block;
2375 source_type_member_definition.append (function);
2377 return proxy_name;
2380 void check_property_error_reply (PropertyAccessor acc, CCodeBlock block) {
2381 var dbus_error = new CCodeIdentifier ("_dbus_error");
2382 var dbus_error_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, dbus_error);
2384 var error_block = new CCodeBlock ();
2386 var ccritical = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
2387 ccritical.add_argument (new CCodeConstant ("\"file %s: line %d: uncaught error: %s (%s)\""));
2388 ccritical.add_argument (new CCodeConstant ("__FILE__"));
2389 ccritical.add_argument (new CCodeConstant ("__LINE__"));
2390 ccritical.add_argument (new CCodeMemberAccess (dbus_error, "message"));
2391 ccritical.add_argument (new CCodeMemberAccess (dbus_error, "name"));
2393 error_block.add_statement (new CCodeExpressionStatement (ccritical));
2395 var dbus_error_free = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_free"));
2396 dbus_error_free.add_argument (dbus_error_ptr);
2397 error_block.add_statement (new CCodeExpressionStatement (dbus_error_free));
2399 if (acc.readable && !acc.value_type.is_real_non_null_struct_type ()) {
2400 error_block.add_statement (new CCodeReturnStatement (default_value_for_type (acc.value_type, false)));
2401 } else {
2402 error_block.add_statement (new CCodeReturnStatement ());
2405 var dbus_error_is_set = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_is_set"));
2406 dbus_error_is_set.add_argument (dbus_error_ptr);
2407 block.add_statement (new CCodeIfStatement (dbus_error_is_set, error_block));
2410 CCodeConstant get_property_reply_signature (PropertyAccessor acc) {
2411 if (acc.readable) {
2412 return new CCodeConstant ("\"v\"");
2413 } else {
2414 return new CCodeConstant ("\"\"");
2418 CCodeConstant get_property_inner_signature (PropertyAccessor acc) {
2419 return new CCodeConstant ("\"%s\"".printf (get_type_signature (acc.value_type)));
2422 void check_property_reply_signature (PropertyAccessor acc, CCodeBlock block) {
2423 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2424 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
2426 var message_signature = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_get_signature"));
2427 message_signature.add_argument (new CCodeIdentifier ("_reply"));
2429 var signature_check = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
2430 signature_check.add_argument (message_signature);
2431 signature_check.add_argument (get_property_reply_signature (acc));
2433 var signature_error_block = new CCodeBlock ();
2435 var ccritical = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
2436 ccritical.add_argument (new CCodeConstant ("\"file %s: line %d: Invalid signature, expected \\\"%s\\\", got \\\"%s\\\"\""));
2437 ccritical.add_argument (new CCodeConstant ("__FILE__"));
2438 ccritical.add_argument (new CCodeConstant ("__LINE__"));
2439 ccritical.add_argument (get_property_reply_signature (acc));
2440 ccritical.add_argument (message_signature);
2442 signature_error_block.add_statement (new CCodeExpressionStatement (ccritical));
2443 signature_error_block.add_statement (new CCodeExpressionStatement (reply_unref));
2445 if (acc.readable && !acc.value_type.is_real_non_null_struct_type ()) {
2446 signature_error_block.add_statement (new CCodeReturnStatement (default_value_for_type (acc.value_type, false)));
2447 } else {
2448 signature_error_block.add_statement (new CCodeReturnStatement ());
2451 block.add_statement (new CCodeIfStatement (signature_check, signature_error_block));
2454 void check_property_inner_signature (PropertyAccessor acc, CCodeFragment fragment) {
2455 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2456 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
2458 var iter_signature = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_signature"));
2459 iter_signature.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_subiter")));
2461 var signature_check = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
2462 signature_check.add_argument (iter_signature);
2463 signature_check.add_argument (get_property_inner_signature (acc));
2465 var signature_error_block = new CCodeBlock ();
2467 var ccritical = new CCodeFunctionCall (new CCodeIdentifier ("g_critical"));
2468 ccritical.add_argument (new CCodeConstant ("\"file %s: line %d: Invalid signature, expected \\\"%s\\\", got \\\"%s\\\"\""));
2469 ccritical.add_argument (new CCodeConstant ("__FILE__"));
2470 ccritical.add_argument (new CCodeConstant ("__LINE__"));
2471 ccritical.add_argument (get_property_inner_signature (acc));
2472 ccritical.add_argument (iter_signature);
2474 signature_error_block.add_statement (new CCodeExpressionStatement (ccritical));
2475 signature_error_block.add_statement (new CCodeExpressionStatement (reply_unref));
2477 if (!acc.value_type.is_real_non_null_struct_type ()) {
2478 signature_error_block.add_statement (new CCodeReturnStatement (default_value_for_type (acc.value_type, false)));
2479 } else {
2480 signature_error_block.add_statement (new CCodeReturnStatement ());
2483 fragment.append (new CCodeIfStatement (signature_check, signature_error_block));
2486 string generate_dbus_proxy_property_get (Interface main_iface, Interface iface, Property prop) {
2487 string proxy_name = "%sdbus_proxy_get_%s".printf (main_iface.get_lower_case_cprefix (), prop.name);
2489 string dbus_iface_name = get_dbus_name (iface);
2491 var owned_type = prop.get_accessor.value_type.copy ();
2492 owned_type.value_owned = true;
2493 if (owned_type.is_disposable () && !prop.get_accessor.value_type.value_owned) {
2494 Report.error (prop.get_accessor.value_type.source_reference, "Properties used in D-Bus clients require owned get accessor");
2497 var array_type = prop.get_accessor.value_type as ArrayType;
2499 CCodeDeclaration cdecl;
2501 var function = new CCodeFunction (proxy_name);
2502 function.modifiers = CCodeModifiers.STATIC;
2504 function.add_parameter (new CCodeFormalParameter ("self", "%s*".printf (iface.get_cname ())));
2506 if (prop.property_type.is_real_non_null_struct_type ()) {
2507 function.add_parameter (new CCodeFormalParameter ("result", "%s*".printf (prop.get_accessor.value_type.get_cname ())));
2508 } else {
2509 if (array_type != null) {
2510 for (int dim = 1; dim <= array_type.rank; dim++) {
2511 function.add_parameter (new CCodeFormalParameter ("result_length%d".printf (dim), "int*"));
2515 function.return_type = prop.get_accessor.value_type.get_cname ();
2518 var block = new CCodeBlock ();
2519 var prefragment = new CCodeFragment ();
2520 var postfragment = new CCodeFragment ();
2522 var dispose_return_block = new CCodeBlock ();
2523 if (prop.property_type.is_real_non_null_struct_type ()) {
2524 dispose_return_block.add_statement (new CCodeReturnStatement ());
2525 } else {
2526 dispose_return_block.add_statement (new CCodeReturnStatement (default_value_for_type (prop.property_type, false)));
2528 block.add_statement (new CCodeIfStatement (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("self"), iface.get_cname () + "DBusProxy*"), "disposed"), dispose_return_block));
2530 cdecl = new CCodeDeclaration ("DBusError");
2531 cdecl.add_declarator (new CCodeVariableDeclarator ("_dbus_error"));
2532 block.add_statement (cdecl);
2534 var dbus_error = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_dbus_error"));
2536 cdecl = new CCodeDeclaration ("DBusGConnection");
2537 cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection"));
2538 block.add_statement (cdecl);
2540 cdecl = new CCodeDeclaration ("DBusMessage");
2541 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
2542 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
2543 block.add_statement (cdecl);
2545 cdecl = new CCodeDeclaration ("DBusMessageIter");
2546 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
2547 cdecl.add_declarator (new CCodeVariableDeclarator ("_subiter"));
2548 block.add_statement (cdecl);
2550 block.add_statement (prefragment);
2552 var destination = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_bus_name"));
2553 destination.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*"));
2554 var path = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_path"));
2555 path.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*"));
2557 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_call"));
2558 msgcall.add_argument (destination);
2559 msgcall.add_argument (path);
2560 msgcall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties\""));
2561 msgcall.add_argument (new CCodeConstant ("\"Get\""));
2562 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_message"), msgcall)));
2564 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
2565 iter_call.add_argument (new CCodeIdentifier ("_message"));
2566 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
2567 prefragment.append (new CCodeExpressionStatement (iter_call));
2569 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
2570 iter_call.add_argument (new CCodeIdentifier ("_reply"));
2571 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
2572 postfragment.append (new CCodeExpressionStatement (iter_call));
2574 // interface name
2575 write_expression (prefragment, string_type, new CCodeIdentifier ("_iter"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
2576 // property name
2577 write_expression (prefragment, string_type, new CCodeIdentifier ("_iter"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
2579 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
2580 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
2581 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_subiter")));
2582 postfragment.append (new CCodeExpressionStatement (iter_call));
2584 check_property_inner_signature (prop.get_accessor, postfragment);
2586 if (prop.property_type.is_real_non_null_struct_type ()) {
2587 var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result"));
2588 var expr = read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_subiter"), target);
2589 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
2590 } else {
2591 cdecl = new CCodeDeclaration (prop.get_accessor.value_type.get_cname ());
2592 cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
2593 postfragment.append (cdecl);
2595 if (array_type != null) {
2596 for (int dim = 1; dim <= array_type.rank; dim++) {
2597 cdecl = new CCodeDeclaration ("int");
2598 cdecl.add_declarator (new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0")));
2599 postfragment.append (cdecl);
2603 var target = new CCodeIdentifier ("_result");
2604 var expr = read_expression (postfragment, prop.get_accessor.value_type, new CCodeIdentifier ("_subiter"), target);
2605 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
2607 if (array_type != null) {
2608 for (int dim = 1; dim <= array_type.rank; dim++) {
2609 // TODO check that parameter is not NULL (out parameters are optional)
2610 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)))));
2615 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
2616 gconnection.add_argument (new CCodeIdentifier ("self"));
2617 gconnection.add_argument (new CCodeConstant ("\"connection\""));
2618 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection")));
2619 gconnection.add_argument (new CCodeConstant ("NULL"));
2620 block.add_statement (new CCodeExpressionStatement (gconnection));
2622 var dbus_error_init = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_init"));
2623 dbus_error_init.add_argument (dbus_error);
2624 block.add_statement (new CCodeExpressionStatement (dbus_error_init));
2626 var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
2627 connection.add_argument (new CCodeIdentifier ("_connection"));
2629 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send_with_reply_and_block"));
2630 ccall.add_argument (connection);
2631 ccall.add_argument (new CCodeIdentifier ("_message"));
2632 ccall.add_argument (get_dbus_timeout (prop));
2633 ccall.add_argument (dbus_error);
2634 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
2636 var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
2637 conn_unref.add_argument (new CCodeIdentifier ("_connection"));
2638 block.add_statement (new CCodeExpressionStatement (conn_unref));
2640 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2641 message_unref.add_argument (new CCodeIdentifier ("_message"));
2642 block.add_statement (new CCodeExpressionStatement (message_unref));
2644 check_property_error_reply (prop.get_accessor, block);
2645 check_property_reply_signature (prop.get_accessor, block);
2647 block.add_statement (postfragment);
2649 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2650 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
2651 block.add_statement (new CCodeExpressionStatement (reply_unref));
2653 if (prop.property_type.is_real_non_null_struct_type ()) {
2654 block.add_statement (new CCodeReturnStatement ());
2655 } else {
2656 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
2659 source_declarations.add_type_member_declaration (function.copy ());
2660 function.block = block;
2661 source_type_member_definition.append (function);
2663 return proxy_name;
2666 string generate_dbus_proxy_property_set (Interface main_iface, Interface iface, Property prop) {
2667 string proxy_name = "%sdbus_proxy_set_%s".printf (main_iface.get_lower_case_cprefix (), prop.name);
2669 string dbus_iface_name = get_dbus_name (iface);
2671 var array_type = prop.set_accessor.value_type as ArrayType;
2673 CCodeDeclaration cdecl;
2675 var function = new CCodeFunction (proxy_name);
2676 function.modifiers = CCodeModifiers.STATIC;
2678 function.add_parameter (new CCodeFormalParameter ("self", "%s*".printf (iface.get_cname ())));
2680 if (prop.property_type.is_real_non_null_struct_type ()) {
2681 function.add_parameter (new CCodeFormalParameter ("value", "%s*".printf (prop.set_accessor.value_type.get_cname ())));
2682 } else {
2683 function.add_parameter (new CCodeFormalParameter ("value", prop.set_accessor.value_type.get_cname ()));
2685 if (array_type != null) {
2686 for (int dim = 1; dim <= array_type.rank; dim++) {
2687 function.add_parameter (new CCodeFormalParameter ("value_length%d".printf (dim), "int"));
2692 var block = new CCodeBlock ();
2693 var prefragment = new CCodeFragment ();
2694 var postfragment = new CCodeFragment ();
2696 var dispose_return_block = new CCodeBlock ();
2697 dispose_return_block.add_statement (new CCodeReturnStatement ());
2698 block.add_statement (new CCodeIfStatement (new CCodeMemberAccess.pointer (new CCodeCastExpression (new CCodeIdentifier ("self"), iface.get_cname () + "DBusProxy*"), "disposed"), dispose_return_block));
2700 cdecl = new CCodeDeclaration ("DBusError");
2701 cdecl.add_declarator (new CCodeVariableDeclarator ("_dbus_error"));
2702 block.add_statement (cdecl);
2704 var dbus_error = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_dbus_error"));
2706 cdecl = new CCodeDeclaration ("DBusGConnection");
2707 cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection"));
2708 block.add_statement (cdecl);
2710 cdecl = new CCodeDeclaration ("DBusMessage");
2711 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
2712 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
2713 block.add_statement (cdecl);
2715 cdecl = new CCodeDeclaration ("DBusMessageIter");
2716 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
2717 cdecl.add_declarator (new CCodeVariableDeclarator ("_subiter"));
2718 block.add_statement (cdecl);
2720 block.add_statement (prefragment);
2722 var destination = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_bus_name"));
2723 destination.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*"));
2724 var path = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_path"));
2725 path.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*"));
2727 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_call"));
2728 msgcall.add_argument (destination);
2729 msgcall.add_argument (path);
2730 msgcall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties\""));
2731 msgcall.add_argument (new CCodeConstant ("\"Set\""));
2732 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_message"), msgcall)));
2734 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
2735 iter_call.add_argument (new CCodeIdentifier ("_message"));
2736 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
2737 prefragment.append (new CCodeExpressionStatement (iter_call));
2739 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
2740 iter_call.add_argument (new CCodeIdentifier ("_reply"));
2741 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
2742 postfragment.append (new CCodeExpressionStatement (iter_call));
2744 // interface name
2745 write_expression (prefragment, string_type, new CCodeIdentifier ("_iter"), new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
2746 // property name
2747 write_expression (prefragment, string_type, new CCodeIdentifier ("_iter"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
2749 // property value (as variant)
2750 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
2751 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
2752 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
2753 iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_signature (prop.property_type))));
2754 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_subiter")));
2755 prefragment.append (new CCodeExpressionStatement (iter_call));
2757 if (prop.property_type.is_real_non_null_struct_type ()) {
2758 write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_subiter"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("value")));
2759 } else {
2760 write_expression (prefragment, prop.set_accessor.value_type, new CCodeIdentifier ("_subiter"), new CCodeIdentifier ("value"));
2763 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
2764 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
2765 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_subiter")));
2766 prefragment.append (new CCodeExpressionStatement (iter_call));
2768 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
2769 gconnection.add_argument (new CCodeIdentifier ("self"));
2770 gconnection.add_argument (new CCodeConstant ("\"connection\""));
2771 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection")));
2772 gconnection.add_argument (new CCodeConstant ("NULL"));
2773 block.add_statement (new CCodeExpressionStatement (gconnection));
2775 var dbus_error_init = new CCodeFunctionCall (new CCodeIdentifier ("dbus_error_init"));
2776 dbus_error_init.add_argument (dbus_error);
2777 block.add_statement (new CCodeExpressionStatement (dbus_error_init));
2779 var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
2780 connection.add_argument (new CCodeIdentifier ("_connection"));
2782 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send_with_reply_and_block"));
2783 ccall.add_argument (connection);
2784 ccall.add_argument (new CCodeIdentifier ("_message"));
2785 ccall.add_argument (get_dbus_timeout (prop));
2786 ccall.add_argument (dbus_error);
2787 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
2789 var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
2790 conn_unref.add_argument (new CCodeIdentifier ("_connection"));
2791 block.add_statement (new CCodeExpressionStatement (conn_unref));
2793 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2794 message_unref.add_argument (new CCodeIdentifier ("_message"));
2795 block.add_statement (new CCodeExpressionStatement (message_unref));
2797 check_property_error_reply (prop.set_accessor, block);
2798 check_property_reply_signature (prop.set_accessor, block);
2800 block.add_statement (postfragment);
2802 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
2803 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
2804 block.add_statement (new CCodeExpressionStatement (reply_unref));
2806 source_declarations.add_type_member_declaration (function.copy ());
2807 function.block = block;
2808 source_type_member_definition.append (function);
2810 return proxy_name;