Fix order of commandline arguments passed to C compiler, patch by
[vala-lang.git] / gobject / valadbusclientmodule.vala
blob87a2d02e407ffab3bdb0262855bcc5139bf25031
1 /* valadbusclientmodule.vala
3 * Copyright (C) 2007-2008 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;
26 using Gee;
28 /**
29 * The link between a dynamic method and generated code.
31 public class Vala.DBusClientModule : DBusModule {
32 int dynamic_property_id;
34 public DBusClientModule (CCodeGenerator codegen, CCodeModule? next) {
35 base (codegen, next);
38 string get_dynamic_dbus_name (string vala_name) {
39 // TODO switch default to no transformation as soon as we have static D-Bus client support
40 // keep transformation by default for static D-Bus client and server support
41 if (context.dbus_transformation) {
42 return Symbol.lower_case_to_camel_case (vala_name);
43 } else {
44 return vala_name;
48 public override void generate_dynamic_method_wrapper (DynamicMethod method) {
49 var dynamic_method = (DynamicMethod) method;
51 var func = new CCodeFunction (method.get_cname (), method.return_type.get_cname ());
53 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
55 generate_cparameters (method, method.return_type, false, cparam_map, func);
57 var block = new CCodeBlock ();
58 if (dynamic_method.dynamic_type.data_type == dbus_object_type) {
59 generate_dbus_method_wrapper (method, block);
60 } else {
61 Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ()));
64 // append to C source file
65 source_type_member_declaration.append (func.copy ());
67 func.block = block;
68 source_type_member_definition.append (func);
71 void generate_dbus_method_wrapper (Method method, CCodeBlock block) {
72 var dynamic_method = (DynamicMethod) method;
74 var expr = dynamic_method.invocation;
76 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_begin_call"));
78 ccall.add_argument (new CCodeIdentifier ("self"));
80 bool found_out = false;
81 Expression callback = null;
82 int callback_index = -1;
83 int arg_index = 1;
84 foreach (Expression arg in expr.get_argument_list ()) {
85 if (arg.symbol_reference is Method) {
86 // callback
87 if (callback != null) {
88 Report.error (expr.source_reference, "only one reply callback may be specified in invocation of DBus method");
89 expr.error = true;
90 return;
91 } else if (found_out) {
92 Report.error (expr.source_reference, "out argument and reply callback conflict in invocation of DBus method");
93 expr.error = true;
94 return;
96 callback = arg;
97 callback_index = arg_index;
98 } else if (arg is UnaryExpression && ((UnaryExpression) arg).operator == UnaryOperator.OUT) {
99 // out arg
100 if (callback != null) {
101 Report.error (expr.source_reference, "out argument and reply callback conflict in invocation of DBus method");
102 expr.error = true;
103 return;
105 found_out = true;
106 } else {
107 // in arg
108 if (callback != null || found_out) {
109 Report.error (expr.source_reference, "in argument must not follow out argument or reply callback in invocation of DBus method");
110 expr.error = true;
111 return;
114 arg_index++;
117 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (method.name))));
119 if (callback != null) {
120 var reply_method = (Method) callback.symbol_reference;
122 var cb_fun = new CCodeFunction ("_%s_cb".printf (reply_method.get_cname ()), "void");
123 cb_fun.modifiers = CCodeModifiers.STATIC;
124 cb_fun.add_parameter (new CCodeFormalParameter ("proxy", "DBusGProxy*"));
125 cb_fun.add_parameter (new CCodeFormalParameter ("call", "DBusGProxyCall*"));
126 cb_fun.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
127 cb_fun.block = new CCodeBlock ();
128 var cerrdecl = new CCodeDeclaration ("GError*");
129 cerrdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("error", new CCodeConstant ("NULL")));
130 cb_fun.block.add_statement (cerrdecl);
131 var cend_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_end_call"));
132 cend_call.add_argument (new CCodeIdentifier ("proxy"));
133 cend_call.add_argument (new CCodeIdentifier ("call"));
134 cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
135 var creply_call = new CCodeFunctionCall ((CCodeExpression) callback.ccodenode);
136 creply_call.add_argument (new CCodeIdentifier ("user_data"));
137 int param_count = reply_method.get_parameters ().size;
138 int i = 0;
139 foreach (FormalParameter param in reply_method.get_parameters ()) {
140 if ((++i) == param_count) {
141 if (!(param.parameter_type is ErrorType)) {
142 Report.error (null, "DBus reply callbacks must end with GLib.Error argument");
143 return;
146 break;
148 if (param.parameter_type is ArrayType && ((ArrayType) param.parameter_type).element_type.data_type != string_type.data_type) {
149 var array_type = (ArrayType) param.parameter_type;
150 CCodeDeclaration cdecl;
151 if (dbus_use_ptr_array (array_type)) {
152 cdecl = new CCodeDeclaration ("GPtrArray*");
153 } else {
154 cdecl = new CCodeDeclaration ("GArray*");
156 cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
157 cb_fun.block.add_statement (cdecl);
158 cend_call.add_argument (get_dbus_g_type (array_type));
159 cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
160 creply_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), dbus_use_ptr_array (array_type) ? "pdata" : "data"));
161 creply_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), "len"));
162 } else {
163 var cdecl = new CCodeDeclaration (param.parameter_type.get_cname ());
164 cdecl.add_declarator (new CCodeVariableDeclarator (param.name));
165 cb_fun.block.add_statement (cdecl);
166 if (param.parameter_type is ArrayType && ((ArrayType) param.parameter_type).element_type.data_type == string_type.data_type) {
167 // special case string array
168 cend_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
169 } else {
170 cend_call.add_argument (get_dbus_g_type (param.parameter_type));
172 cend_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
173 creply_call.add_argument (new CCodeIdentifier (param.name));
175 if (param.parameter_type is ArrayType && ((ArrayType) param.parameter_type).element_type.data_type == string_type.data_type) {
176 var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
177 cstrvlen.add_argument (new CCodeIdentifier (param.name));
178 creply_call.add_argument (cstrvlen);
183 cend_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
184 cb_fun.block.add_statement (new CCodeExpressionStatement (cend_call));
185 creply_call.add_argument (new CCodeIdentifier ("error"));
186 cb_fun.block.add_statement (new CCodeExpressionStatement (creply_call));
187 source_type_member_definition.append (cb_fun);
189 ccall.add_argument (new CCodeIdentifier (cb_fun.name));
190 ccall.add_argument (new CCodeConstant ("param%d_target".printf (callback_index)));
191 ccall.add_argument (new CCodeConstant ("NULL"));
192 } else if (found_out || !(method.return_type is VoidType)) {
193 ccall.call = new CCodeIdentifier ("dbus_g_proxy_call");
195 ccall.add_argument (new CCodeIdentifier ("error"));
196 } else {
197 ccall.call = new CCodeIdentifier ("dbus_g_proxy_call_no_reply");
200 foreach (FormalParameter param in method.get_parameters ()) {
201 if (param.parameter_type is MethodType
202 || param.parameter_type is DelegateType) {
203 // callback parameter
204 break;
207 if (param.direction != ParameterDirection.IN) {
208 continue;
211 var array_type = param.parameter_type as ArrayType;
212 if (array_type != null) {
213 // array parameter
214 if (array_type.element_type.data_type != string_type.data_type) {
215 // non-string arrays (use GArray)
216 ccall.add_argument (get_dbus_g_type (array_type));
218 var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
219 sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
221 CCodeDeclaration cdecl;
222 CCodeFunctionCall array_construct;
223 if (dbus_use_ptr_array (array_type)) {
224 cdecl = new CCodeDeclaration ("GPtrArray*");
226 array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_ptr_array_sized_new"));
227 array_construct.add_argument (new CCodeIdentifier (head.get_array_length_cname (param.name, 1)));
228 } else {
229 cdecl = new CCodeDeclaration ("GArray*");
231 array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_array_new"));
232 array_construct.add_argument (new CCodeConstant ("TRUE"));
233 array_construct.add_argument (new CCodeConstant ("TRUE"));
234 array_construct.add_argument (sizeof_call);
237 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("dbus_%s".printf (param.name), array_construct));
238 block.add_statement (cdecl);
240 if (dbus_use_ptr_array (array_type)) {
241 var memcpy_call = new CCodeFunctionCall (new CCodeIdentifier ("memcpy"));
242 memcpy_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "pdata"));
243 memcpy_call.add_argument (new CCodeIdentifier (param.name));
244 memcpy_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier (head.get_array_length_cname (param.name, 1)), sizeof_call));
245 block.add_statement (new CCodeExpressionStatement (memcpy_call));
247 var len_assignment = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("dbus_%s".printf (param.name)), "len"), new CCodeIdentifier (head.get_array_length_cname (param.name, 1)));
248 block.add_statement (new CCodeExpressionStatement (len_assignment));
249 } else {
250 var cappend_call = new CCodeFunctionCall (new CCodeIdentifier ("g_array_append_vals"));
251 cappend_call.add_argument (new CCodeIdentifier ("dbus_%s".printf (param.name)));
252 cappend_call.add_argument (new CCodeIdentifier (param.name));
253 cappend_call.add_argument (new CCodeIdentifier (head.get_array_length_cname (param.name, 1)));
254 block.add_statement (new CCodeExpressionStatement (cappend_call));
257 ccall.add_argument (new CCodeIdentifier ("dbus_%s".printf (param.name)));
258 } else {
259 // string arrays
260 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
261 ccall.add_argument (new CCodeIdentifier (param.name));
263 } else if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
264 // struct parameter
265 var st = (Struct) param.parameter_type.data_type;
267 var array_construct = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_new"));
268 array_construct.add_argument (new CCodeConstant ("0"));
270 var cdecl = new CCodeDeclaration ("GValueArray*");
271 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("dbus_%s".printf (param.name), array_construct));
272 block.add_statement (cdecl);
274 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_struct"));
275 type_call.add_argument (new CCodeConstant ("\"GValueArray\""));
277 foreach (Field f in st.get_fields ()) {
278 if (f.binding != MemberBinding.INSTANCE) {
279 continue;
282 string val_name = "val_%s_%s".printf (param.name, f.name);
284 // 0-initialize struct with struct initializer { 0 }
285 var cvalinit = new CCodeInitializerList ();
286 cvalinit.append (new CCodeConstant ("0"));
288 var cval_decl = new CCodeDeclaration ("GValue");
289 cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer (val_name, cvalinit));
290 block.add_statement (cval_decl);
292 var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (val_name));
294 var cinit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
295 cinit_call.add_argument (val_ptr);
296 cinit_call.add_argument (new CCodeIdentifier (f.field_type.data_type.get_type_id ()));
297 block.add_statement (new CCodeExpressionStatement (cinit_call));
299 var cset_call = new CCodeFunctionCall (new CCodeIdentifier (f.field_type.data_type.get_set_value_function ()));
300 cset_call.add_argument (val_ptr);
301 cset_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), f.name));
302 block.add_statement (new CCodeExpressionStatement (cset_call));
304 var cappend_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_array_append"));
305 cappend_call.add_argument (new CCodeIdentifier ("dbus_%s".printf (param.name)));
306 cappend_call.add_argument (val_ptr);
307 block.add_statement (new CCodeExpressionStatement (cappend_call));
309 type_call.add_argument (new CCodeIdentifier (f.field_type.data_type.get_type_id ()));
312 type_call.add_argument (new CCodeConstant ("G_TYPE_INVALID"));
314 ccall.add_argument (type_call);
315 ccall.add_argument (new CCodeIdentifier ("dbus_%s".printf (param.name)));
316 } else {
317 ccall.add_argument (get_dbus_g_type (param.parameter_type));
318 ccall.add_argument (new CCodeIdentifier (param.name));
322 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
324 var out_marshalling_fragment = new CCodeFragment ();
326 foreach (FormalParameter param in method.get_parameters ()) {
327 if (param.parameter_type is MethodType) {
328 // callback parameter
329 break;
332 if (param.direction != ParameterDirection.OUT) {
333 continue;
336 if (param.parameter_type.get_type_signature ().has_prefix ("(")) {
337 // struct output parameter
338 var st = (Struct) param.parameter_type.data_type;
340 var cdecl = new CCodeDeclaration ("GValueArray*");
341 cdecl.add_declarator (new CCodeVariableDeclarator ("dbus_%s".printf (param.name)));
342 block.add_statement (cdecl);
344 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_struct"));
345 type_call.add_argument (new CCodeConstant ("\"GValueArray\""));
347 int i = 0;
348 foreach (Field f in st.get_fields ()) {
349 if (f.binding != MemberBinding.INSTANCE) {
350 continue;
353 var cget_call = new CCodeFunctionCall (new CCodeIdentifier (f.field_type.data_type.get_get_value_function ()));
354 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 ()))));
356 var converted_value = cget_call;
358 if (requires_copy (f.field_type)) {
359 var dupexpr = get_dup_func_expression (f.field_type, expr.source_reference);
360 converted_value = new CCodeFunctionCall (dupexpr);
361 converted_value.add_argument (cget_call);
364 var assign = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier (param.name), f.name), converted_value);
365 out_marshalling_fragment.append (new CCodeExpressionStatement (assign));
367 type_call.add_argument (new CCodeIdentifier (f.field_type.data_type.get_type_id ()));
368 i++;
371 type_call.add_argument (new CCodeConstant ("G_TYPE_INVALID"));
373 ccall.add_argument (type_call);
374 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("dbus_%s".printf (param.name))));
375 } else {
376 ccall.add_argument (new CCodeIdentifier (param.parameter_type.data_type.get_type_id ()));
377 ccall.add_argument (new CCodeIdentifier (param.name));
381 if (!(method.return_type is VoidType)) {
382 // synchronous D-Bus method call with reply
383 var array_type = method.return_type as ArrayType;
384 if (array_type != null && array_type.element_type.data_type != string_type.data_type) {
385 // non-string arrays (use GArray)
386 ccall.add_argument (get_dbus_g_type (array_type));
388 CCodeDeclaration cdecl;
389 if (dbus_use_ptr_array (array_type)) {
390 cdecl = new CCodeDeclaration ("GPtrArray*");
391 } else {
392 cdecl = new CCodeDeclaration ("GArray*");
394 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
395 block.add_statement (cdecl);
397 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
398 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
400 block.add_statement (new CCodeExpressionStatement (ccall));
402 // don't access result when error occured
403 var creturnblock = new CCodeBlock ();
404 creturnblock.add_statement (new CCodeReturnStatement (default_value_for_type (method.return_type, false)));
405 var cerrorif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")), creturnblock);
406 block.add_statement (cerrorif);
408 block.add_statement (out_marshalling_fragment);
410 // *result_length1 = result->len;
411 var garray_length = new CCodeMemberAccess.pointer (new CCodeIdentifier ("result"), "len");
412 var result_length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length1"));
413 var assign = new CCodeAssignment (result_length, garray_length);
414 block.add_statement (new CCodeExpressionStatement (assign));
416 // return result->data;
417 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 ())));
418 } else {
419 // string arrays or other datatypes
421 ccall.add_argument (get_dbus_g_type (method.return_type));
423 var cdecl = new CCodeDeclaration (method.return_type.get_cname ());
424 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
425 block.add_statement (cdecl);
427 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
428 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
430 block.add_statement (new CCodeExpressionStatement (ccall));
432 // don't access result when error occured
433 var creturnblock = new CCodeBlock ();
434 creturnblock.add_statement (new CCodeReturnStatement (default_value_for_type (method.return_type, false)));
435 var cerrorif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")), creturnblock);
436 block.add_statement (cerrorif);
438 block.add_statement (out_marshalling_fragment);
440 if (array_type != null) {
441 // special case string array
443 // *result_length1 = g_strv_length (result);
444 var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
445 cstrvlen.add_argument (new CCodeIdentifier ("result"));
446 var result_length = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length1"));
447 var assign = new CCodeAssignment (result_length, cstrvlen);
448 block.add_statement (new CCodeExpressionStatement (assign));
451 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
453 } else {
454 if (found_out) {
455 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
458 block.add_statement (new CCodeExpressionStatement (ccall));
460 // don't access result when error occured
461 var creturnblock = new CCodeBlock ();
462 creturnblock.add_statement (new CCodeReturnStatement ());
463 var cerrorif = new CCodeIfStatement (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")), creturnblock);
464 block.add_statement (cerrorif);
466 block.add_statement (out_marshalling_fragment);
470 public override CCodeExpression get_dbus_g_type (DataType data_type) {
471 if (data_type is ArrayType) {
472 var array_type = data_type as ArrayType;
473 if (array_type.element_type.data_type == string_type.data_type) {
474 return new CCodeIdentifier ("G_TYPE_STRV");
477 var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
478 if (dbus_use_ptr_array (array_type)) {
479 carray_type.add_argument (new CCodeConstant ("\"GPtrArray\""));
480 } else {
481 carray_type.add_argument (new CCodeConstant ("\"GArray\""));
483 carray_type.add_argument (get_dbus_g_type (array_type.element_type));
484 return carray_type;
485 } else if (data_type.data_type is Enum) {
486 var en = (Enum) data_type.data_type;
487 if (en.is_flags) {
488 return new CCodeIdentifier ("G_TYPE_UINT");
489 } else {
490 return new CCodeIdentifier ("G_TYPE_INT");
492 } else if (data_type.data_type == null) {
493 critical ("Internal error during DBus type generation with: %s", data_type.to_string ());
494 return new CCodeIdentifier ("G_TYPE_NONE");
495 } else if (data_type.data_type.get_full_name () == "GLib.HashTable") {
496 var cmap_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_map"));
497 var type_args = data_type.get_type_arguments ();
499 cmap_type.add_argument (new CCodeConstant ("\"GHashTable\""));
500 foreach (DataType type_arg in type_args) {
501 cmap_type.add_argument (get_dbus_g_type (type_arg));
504 return cmap_type;
505 } else if (data_type.data_type.get_type_signature ().has_prefix ("(")) {
506 // struct parameter
507 var st = (Struct) data_type.data_type;
509 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_struct"));
510 type_call.add_argument (new CCodeConstant ("\"GValueArray\""));
512 foreach (Field f in st.get_fields ()) {
513 if (f.binding != MemberBinding.INSTANCE) {
514 continue;
517 type_call.add_argument (get_dbus_g_type (f.field_type));
520 type_call.add_argument (new CCodeConstant ("G_TYPE_INVALID"));
522 return type_call;
523 } else {
524 return new CCodeIdentifier (data_type.data_type.get_type_id ());
528 public bool dbus_use_ptr_array (ArrayType array_type) {
529 if (array_type.element_type.data_type == string_type.data_type) {
530 // use char**
531 return false;
532 } else if (array_type.element_type.data_type == bool_type.data_type
533 || array_type.element_type.data_type == char_type.data_type
534 || array_type.element_type.data_type == uchar_type.data_type
535 || array_type.element_type.data_type == int_type.data_type
536 || array_type.element_type.data_type == uint_type.data_type
537 || array_type.element_type.data_type == long_type.data_type
538 || array_type.element_type.data_type == ulong_type.data_type
539 || array_type.element_type.data_type == int8_type.data_type
540 || array_type.element_type.data_type == uint8_type.data_type
541 || array_type.element_type.data_type == int32_type.data_type
542 || array_type.element_type.data_type == uint32_type.data_type
543 || array_type.element_type.data_type == int64_type.data_type
544 || array_type.element_type.data_type == uint64_type.data_type
545 || array_type.element_type.data_type == double_type.data_type) {
546 // use GArray
547 return false;
548 } else {
549 // use GPtrArray
550 return true;
554 public override string get_dynamic_property_getter_cname (DynamicProperty prop) {
555 if (prop.dynamic_type.data_type != dbus_object_type) {
556 return base.get_dynamic_property_getter_cname (prop);
559 string getter_cname = "_dynamic_get_%s%d".printf (prop.name, dynamic_property_id++);
561 var func = new CCodeFunction (getter_cname, prop.property_type.get_cname ());
562 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
564 func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
566 var block = new CCodeBlock ();
567 generate_dbus_property_getter_wrapper (prop, block);
569 // append to C source file
570 source_type_member_declaration.append (func.copy ());
572 func.block = block;
573 source_type_member_definition.append (func);
575 return getter_cname;
578 public override string get_dynamic_property_setter_cname (DynamicProperty prop) {
579 if (prop.dynamic_type.data_type != dbus_object_type) {
580 return base.get_dynamic_property_setter_cname (prop);
583 string setter_cname = "_dynamic_set_%s%d".printf (prop.name, dynamic_property_id++);
585 var func = new CCodeFunction (setter_cname, "void");
586 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
588 func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
589 func.add_parameter (new CCodeFormalParameter ("value", prop.property_type.get_cname ()));
591 var block = new CCodeBlock ();
592 generate_dbus_property_setter_wrapper (prop, block);
594 // append to C source file
595 source_type_member_declaration.append (func.copy ());
597 func.block = block;
598 source_type_member_definition.append (func);
600 return setter_cname;
603 void create_dbus_property_proxy (DynamicProperty node, CCodeBlock block) {
604 var prop_proxy_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_new_from_proxy"));
605 prop_proxy_call.add_argument (new CCodeIdentifier ("obj"));
606 prop_proxy_call.add_argument (new CCodeConstant ("DBUS_INTERFACE_PROPERTIES"));
607 prop_proxy_call.add_argument (new CCodeConstant ("NULL"));
609 var prop_proxy_decl = new CCodeDeclaration ("DBusGProxy*");
610 prop_proxy_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("property_proxy", prop_proxy_call));
611 block.add_statement (prop_proxy_decl);
614 void generate_dbus_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
615 create_dbus_property_proxy (node, block);
617 // initialize GValue
618 var cvalinit = new CCodeInitializerList ();
619 cvalinit.append (new CCodeConstant ("0"));
621 var cval_decl = new CCodeDeclaration ("GValue");
622 cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("gvalue", cvalinit));
623 block.add_statement (cval_decl);
625 var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("gvalue"));
627 // call Get method on property proxy
628 var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
629 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
630 block.add_statement (cdecl);
632 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_call"));
633 ccall.add_argument (new CCodeIdentifier ("property_proxy"));
634 ccall.add_argument (new CCodeConstant ("\"Get\""));
635 ccall.add_argument (new CCodeConstant ("NULL"));
637 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
638 var get_iface = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_interface"));
639 get_iface.add_argument (new CCodeIdentifier ("obj"));
640 ccall.add_argument (get_iface);
642 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
643 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (node.name))));
645 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
647 ccall.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
648 ccall.add_argument (val_ptr);
650 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
652 block.add_statement (new CCodeExpressionStatement (ccall));
654 // unref property proxy
655 var prop_proxy_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
656 prop_proxy_unref.add_argument (new CCodeIdentifier ("property_proxy"));
657 block.add_statement (new CCodeExpressionStatement (prop_proxy_unref));
659 // assign value to result variable
660 var cget_call = new CCodeFunctionCall (new CCodeIdentifier (node.property_type.data_type.get_get_value_function ()));
661 cget_call.add_argument (val_ptr);
662 var assign = new CCodeAssignment (new CCodeIdentifier ("result"), cget_call);
663 block.add_statement (new CCodeExpressionStatement (assign));
665 // return result
666 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
669 void generate_dbus_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
670 create_dbus_property_proxy (node, block);
672 // initialize GValue
673 var cvalinit = new CCodeInitializerList ();
674 cvalinit.append (new CCodeConstant ("0"));
676 var cval_decl = new CCodeDeclaration ("GValue");
677 cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("gvalue", cvalinit));
678 block.add_statement (cval_decl);
680 var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("gvalue"));
682 var cinit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
683 cinit_call.add_argument (val_ptr);
684 cinit_call.add_argument (new CCodeIdentifier (node.property_type.data_type.get_type_id ()));
685 block.add_statement (new CCodeExpressionStatement (cinit_call));
687 var cset_call = new CCodeFunctionCall (new CCodeIdentifier (node.property_type.data_type.get_set_value_function ()));
688 cset_call.add_argument (val_ptr);
689 cset_call.add_argument (new CCodeIdentifier ("value"));
690 block.add_statement (new CCodeExpressionStatement (cset_call));
692 // call Set method on property proxy
693 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_call"));
694 ccall.add_argument (new CCodeIdentifier ("property_proxy"));
695 ccall.add_argument (new CCodeConstant ("\"Set\""));
696 ccall.add_argument (new CCodeConstant ("NULL"));
698 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
699 var get_iface = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_interface"));
700 get_iface.add_argument (new CCodeIdentifier ("obj"));
701 ccall.add_argument (get_iface);
703 ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
704 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (node.name))));
706 ccall.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
707 ccall.add_argument (val_ptr);
709 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
711 ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
713 block.add_statement (new CCodeExpressionStatement (ccall));
715 // unref property proxy
716 var prop_proxy_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
717 prop_proxy_unref.add_argument (new CCodeIdentifier ("property_proxy"));
718 block.add_statement (new CCodeExpressionStatement (prop_proxy_unref));
721 public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig) {
722 if (sig.dynamic_type.data_type != dbus_object_type) {
723 return base.get_dynamic_signal_connect_wrapper_name (sig);
726 string connect_wrapper_name = "_%sconnect".printf (get_dynamic_signal_cname (sig));
727 var func = new CCodeFunction (connect_wrapper_name, "void");
728 func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
729 func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
730 func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
731 func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
732 var block = new CCodeBlock ();
733 generate_dbus_connect_wrapper (sig, block);
735 // append to C source file
736 source_type_member_declaration.append (func.copy ());
738 func.block = block;
739 source_type_member_definition.append (func);
741 return connect_wrapper_name;
744 public override string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal sig) {
745 if (sig.dynamic_type.data_type != dbus_object_type) {
746 return base.get_dynamic_signal_disconnect_wrapper_name (sig);
749 string disconnect_wrapper_name = "_%sdisconnect".printf (get_dynamic_signal_cname (sig));
750 var func = new CCodeFunction (disconnect_wrapper_name, "void");
751 func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
752 func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
753 func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
754 func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
755 var block = new CCodeBlock ();
756 generate_dbus_disconnect_wrapper (sig, block);
758 // append to C source file
759 source_type_member_declaration.append (func.copy ());
761 func.block = block;
762 source_type_member_definition.append (func);
764 return disconnect_wrapper_name;
767 void generate_dbus_connect_wrapper (DynamicSignal sig, CCodeBlock block) {
768 var m = (Method) sig.handler.symbol_reference;
770 sig.accept (codegen);
772 // FIXME should only be done once per marshaller
773 var register_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_object_register_marshaller"));
774 head.generate_marshaller (sig.get_parameters (), sig.return_type, true);
775 register_call.add_argument (new CCodeIdentifier (head.get_marshaller_function (sig.get_parameters (), sig.return_type, null, true)));
776 register_call.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
778 var add_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_add_signal"));
779 add_call.add_argument (new CCodeIdentifier ("obj"));
780 add_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_dynamic_dbus_name (sig.name))));
782 bool first = true;
783 foreach (FormalParameter param in m.get_parameters ()) {
784 if (first) {
785 // skip sender parameter
786 first = false;
787 continue;
790 var array_type = param.parameter_type as ArrayType;
791 if (array_type != null) {
792 if (array_type.element_type.data_type == string_type.data_type) {
793 register_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
794 add_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
795 } else {
796 if (array_type.element_type.data_type.get_type_id () == null) {
797 Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
798 return;
801 var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
802 carray_type.add_argument (new CCodeConstant ("\"GArray\""));
803 carray_type.add_argument (new CCodeIdentifier (array_type.element_type.data_type.get_type_id ()));
804 register_call.add_argument (carray_type);
805 add_call.add_argument (carray_type);
807 } else {
808 if (param.parameter_type.get_type_id () == null) {
809 Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
810 return;
813 register_call.add_argument (new CCodeIdentifier (param.parameter_type.get_type_id ()));
814 add_call.add_argument (new CCodeIdentifier (param.parameter_type.get_type_id ()));
817 register_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
818 add_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
820 block.add_statement (new CCodeExpressionStatement (register_call));
821 block.add_statement (new CCodeExpressionStatement (add_call));
823 var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_connect_signal"));
824 call.add_argument (new CCodeIdentifier ("obj"));
825 call.add_argument (new CCodeIdentifier ("signal_name"));
826 call.add_argument (new CCodeIdentifier ("handler"));
827 call.add_argument (new CCodeIdentifier ("data"));
828 call.add_argument (new CCodeConstant ("NULL"));
829 block.add_statement (new CCodeExpressionStatement (call));
832 void generate_dbus_disconnect_wrapper (DynamicSignal sig, CCodeBlock block) {
833 var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_disconnect_signal"));
834 call.add_argument (new CCodeIdentifier ("obj"));
835 call.add_argument (new CCodeIdentifier ("signal_name"));
836 call.add_argument (new CCodeIdentifier ("handler"));
837 call.add_argument (new CCodeIdentifier ("data"));
838 block.add_statement (new CCodeExpressionStatement (call));
841 public override void visit_cast_expression (CastExpression expr) {
842 // handles casting DBus.Object instances to DBus interfaces
844 var type = expr.type_reference as ObjectType;
845 var call = expr.inner as MethodCall;
846 if (type == null || !(type.type_symbol is Interface)
847 || type.type_symbol.get_attribute ("DBus") == null || call == null) {
848 base.visit_cast_expression (expr);
849 return;
852 var mtype = call.call.value_type as MethodType;
853 if (mtype == null || mtype.method_symbol.get_cname () != "dbus_g_proxy_new_for_name") {
854 base.visit_cast_expression (expr);
855 return;
858 var args = call.get_argument_list ();
859 Expression connection = ((MemberAccess) call.call).inner;
860 Expression bus_name = args.get (0);
861 Expression object_path = args.get (1);
863 var ccall = new CCodeFunctionCall (new CCodeIdentifier (type.type_symbol.get_lower_case_cprefix () + "dbus_proxy_new"));
864 connection.accept (codegen);
865 ccall.add_argument ((CCodeExpression) connection.ccodenode);
866 bus_name.accept (codegen);
867 ccall.add_argument ((CCodeExpression) bus_name.ccodenode);
868 object_path.accept (codegen);
869 ccall.add_argument ((CCodeExpression) object_path.ccodenode);
870 expr.ccodenode = ccall;
873 public override void visit_interface (Interface iface) {
874 base.visit_interface (iface);
876 var dbus = iface.get_attribute ("DBus");
877 if (dbus == null) {
878 return;
880 string dbus_iface_name = dbus.get_string ("name");
881 if (dbus_iface_name == null) {
882 return;
885 // create proxy class
886 string cname = iface.get_cname () + "DBusProxy";
887 string lower_cname = iface.get_lower_case_cprefix () + "dbus_proxy";
889 CCodeFragment decl_frag;
890 CCodeFragment def_frag;
891 CCodeFragment member_decl_frag;
892 if (iface.access != SymbolAccessibility.PRIVATE) {
893 decl_frag = header_type_declaration;
894 def_frag = header_type_definition;
895 member_decl_frag = header_type_member_declaration;
896 dbus_glib_h_needed_in_header = true;
897 } else {
898 decl_frag = source_type_declaration;
899 def_frag = source_type_definition;
900 member_decl_frag = source_type_member_declaration;
901 dbus_glib_h_needed = true;
904 source_type_declaration.append (new CCodeTypeDefinition ("DBusGProxy", new CCodeVariableDeclarator (cname)));
905 source_type_declaration.append (new CCodeTypeDefinition ("DBusGProxyClass", new CCodeVariableDeclarator (cname + "Class")));
907 var implement = new CCodeFunctionCall (new CCodeIdentifier ("G_IMPLEMENT_INTERFACE"));
908 implement.add_argument (new CCodeIdentifier (iface.get_upper_case_cname ("TYPE_")));
909 implement.add_argument (new CCodeIdentifier (lower_cname + "_interface_init"));
911 var define_type = new CCodeFunctionCall (new CCodeIdentifier ("G_DEFINE_TYPE_EXTENDED"));
912 define_type.add_argument (new CCodeIdentifier (cname));
913 define_type.add_argument (new CCodeIdentifier (lower_cname));
914 define_type.add_argument (new CCodeIdentifier ("DBUS_TYPE_G_PROXY"));
915 define_type.add_argument (new CCodeConstant ("0"));
916 define_type.add_argument (implement);
918 source_type_member_definition.append (new CCodeExpressionStatement (define_type));
920 var proxy_new = new CCodeFunction (lower_cname + "_new", iface.get_cname () + "*");
921 proxy_new.add_parameter (new CCodeFormalParameter ("connection", "DBusGConnection*"));
922 proxy_new.add_parameter (new CCodeFormalParameter ("name", "const char*"));
923 proxy_new.add_parameter (new CCodeFormalParameter ("path", "const char*"));
925 var new_block = new CCodeBlock ();
927 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new"));
928 new_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier (lower_cname + "_get_type")));
929 new_call.add_argument (new CCodeConstant ("\"connection\""));
930 new_call.add_argument (new CCodeIdentifier ("connection"));
931 new_call.add_argument (new CCodeConstant ("\"name\""));
932 new_call.add_argument (new CCodeIdentifier ("name"));
933 new_call.add_argument (new CCodeConstant ("\"path\""));
934 new_call.add_argument (new CCodeIdentifier ("path"));
935 new_call.add_argument (new CCodeConstant ("\"interface\""));
936 new_call.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
937 new_call.add_argument (new CCodeConstant ("NULL"));
939 new_block.add_statement (new CCodeReturnStatement (new_call));
941 member_decl_frag.append (proxy_new.copy ());
942 proxy_new.block = new_block;
943 source_type_member_definition.append (proxy_new);
945 var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void");
946 proxy_class_init.add_parameter (new CCodeFormalParameter ("klass", cname + "Class*"));
947 proxy_class_init.modifiers = CCodeModifiers.STATIC;
948 proxy_class_init.block = new CCodeBlock ();
949 source_type_member_definition.append (proxy_class_init);
951 var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void");
952 proxy_instance_init.add_parameter (new CCodeFormalParameter ("self", cname + "*"));
953 proxy_instance_init.modifiers = CCodeModifiers.STATIC;
954 proxy_instance_init.block = new CCodeBlock ();
955 source_type_member_definition.append (proxy_instance_init);
957 var proxy_iface_init = new CCodeFunction (lower_cname + "_interface_init", "void");
958 proxy_iface_init.add_parameter (new CCodeFormalParameter ("iface", iface.get_cname () + "Iface*"));
960 var iface_block = new CCodeBlock ();
962 foreach (Method m in iface.get_methods ()) {
963 var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.vfunc_name);
964 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (iface, m)))));
965 if (m.coroutine) {
966 vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.vfunc_name + "_async");
967 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_async_dbus_proxy_method (iface, m)))));
968 vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.vfunc_name + "_finish");
969 iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_finish_dbus_proxy_method (iface, m)))));
973 proxy_iface_init.modifiers = CCodeModifiers.STATIC;
974 source_type_member_declaration.append (proxy_iface_init.copy ());
975 proxy_iface_init.block = iface_block;
976 source_type_member_definition.append (proxy_iface_init);
979 void generate_marshalling (Method m, string dbus_iface_name, CCodeFragment prefragment, CCodeFragment postfragment) {
980 CCodeDeclaration cdecl;
982 var destination = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_bus_name"));
983 destination.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*"));
984 var path = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_path"));
985 path.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*"));
987 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_call"));
988 msgcall.add_argument (destination);
989 msgcall.add_argument (path);
990 msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
991 msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (m.name))));
992 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_message"), msgcall)));
994 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
995 iter_call.add_argument (new CCodeIdentifier ("_message"));
996 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
997 prefragment.append (new CCodeExpressionStatement (iter_call));
999 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
1000 iter_call.add_argument (new CCodeIdentifier ("_reply"));
1001 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
1002 postfragment.append (new CCodeExpressionStatement (iter_call));
1004 foreach (FormalParameter param in m.get_parameters ()) {
1005 if (param.direction == ParameterDirection.IN) {
1006 CCodeExpression expr = new CCodeIdentifier (param.name);
1007 if (param.parameter_type.is_real_struct_type ()) {
1008 expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
1010 write_expression (prefragment, param.parameter_type, new CCodeIdentifier ("_iter"), expr);
1011 } else {
1012 cdecl = new CCodeDeclaration (param.parameter_type.get_cname ());
1013 cdecl.add_declarator (new CCodeVariableDeclarator ("_" + param.name));
1014 postfragment.append (cdecl);
1016 var target = new CCodeIdentifier ("_" + param.name);
1017 var expr = read_expression (postfragment, param.parameter_type, new CCodeIdentifier ("_iter"), target);
1018 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1020 // TODO check that parameter is not NULL (out parameters are optional)
1021 // free value if parameter is NULL
1022 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), target)));
1025 if (param.parameter_type is ArrayType) {
1026 cdecl = new CCodeDeclaration ("int");
1027 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("_%s_length1".printf (param.name), new CCodeConstant ("0")));
1028 postfragment.append (cdecl);
1030 // TODO check that parameter is not NULL (out parameters are optional)
1031 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("%s_length1".printf (param.name))), new CCodeIdentifier ("_%s_length1".printf (param.name)))));
1036 if (!(m.return_type is VoidType)) {
1037 cdecl = new CCodeDeclaration (m.return_type.get_cname ());
1038 cdecl.add_declarator (new CCodeVariableDeclarator ("_result"));
1039 postfragment.append (cdecl);
1041 var array_type = m.return_type as ArrayType;
1043 if (array_type != null) {
1044 for (int dim = 1; dim <= array_type.rank; dim++) {
1045 cdecl = new CCodeDeclaration ("int");
1046 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("_result_length%d".printf (dim), new CCodeConstant ("0")));
1047 postfragment.append (cdecl);
1051 var target = new CCodeIdentifier ("_result");
1052 var expr = read_expression (postfragment, m.return_type, new CCodeIdentifier ("_iter"), target);
1053 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1055 if (array_type != null) {
1056 for (int dim = 1; dim <= array_type.rank; dim++) {
1057 // TODO check that parameter is not NULL (out parameters are optional)
1058 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)))));
1064 string generate_dbus_proxy_method (Interface iface, Method m) {
1065 string proxy_name = "%sdbus_proxy_%s".printf (iface.get_lower_case_cprefix (), m.name);
1067 string dbus_iface_name = iface.get_attribute ("DBus").get_string ("name");
1069 CCodeDeclaration cdecl;
1071 var function = new CCodeFunction (proxy_name, m.return_type.get_cname ());
1072 function.modifiers = CCodeModifiers.STATIC;
1074 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
1076 generate_cparameters (m, m.return_type, false, cparam_map, function);
1078 var block = new CCodeBlock ();
1079 var prefragment = new CCodeFragment ();
1080 var postfragment = new CCodeFragment ();
1082 cdecl = new CCodeDeclaration ("DBusGConnection");
1083 cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection"));
1084 block.add_statement (cdecl);
1086 cdecl = new CCodeDeclaration ("DBusMessage");
1087 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
1088 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
1089 block.add_statement (cdecl);
1091 cdecl = new CCodeDeclaration ("DBusMessageIter");
1092 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
1093 block.add_statement (cdecl);
1095 block.add_statement (prefragment);
1097 generate_marshalling (m, dbus_iface_name, prefragment, postfragment);
1099 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
1100 gconnection.add_argument (new CCodeIdentifier ("self"));
1101 gconnection.add_argument (new CCodeConstant ("\"connection\""));
1102 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection")));
1103 gconnection.add_argument (new CCodeConstant ("NULL"));
1104 block.add_statement (new CCodeExpressionStatement (gconnection));
1106 var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
1107 connection.add_argument (new CCodeIdentifier ("_connection"));
1109 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send_with_reply_and_block"));
1110 ccall.add_argument (connection);
1111 ccall.add_argument (new CCodeIdentifier ("_message"));
1112 ccall.add_argument (new CCodeConstant ("-1"));
1113 ccall.add_argument (new CCodeConstant ("NULL"));
1114 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
1116 var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
1117 conn_unref.add_argument (new CCodeIdentifier ("_connection"));
1118 block.add_statement (new CCodeExpressionStatement (conn_unref));
1120 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1121 message_unref.add_argument (new CCodeIdentifier ("_message"));
1122 block.add_statement (new CCodeExpressionStatement (message_unref));
1124 block.add_statement (postfragment);
1126 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1127 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
1128 block.add_statement (new CCodeExpressionStatement (reply_unref));
1130 if (!(m.return_type is VoidType)) {
1131 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
1134 source_type_member_declaration.append (function.copy ());
1135 function.block = block;
1136 source_type_member_definition.append (function);
1138 return proxy_name;
1141 string generate_async_dbus_proxy_method (Interface iface, Method m) {
1142 string proxy_name = "%sdbus_proxy_%s_async".printf (iface.get_lower_case_cprefix (), m.name);
1144 string dbus_iface_name = iface.get_attribute ("DBus").get_string ("name");
1146 CCodeDeclaration cdecl;
1149 // generate data struct
1151 string dataname = "%sDBusProxy%sData".printf (iface.get_cname (), Symbol.lower_case_to_camel_case (m.name));
1152 var datastruct = new CCodeStruct ("_" + dataname);
1154 datastruct.add_field ("GAsyncReadyCallback", "callback");
1155 datastruct.add_field ("gpointer", "user_data");
1156 datastruct.add_field ("DBusPendingCall*", "pending");
1158 source_type_definition.append (datastruct);
1159 source_type_declaration.append (new CCodeTypeDefinition ("struct _" + dataname, new CCodeVariableDeclarator (dataname)));
1162 // generate async function
1164 var function = new CCodeFunction (proxy_name, "void");
1165 function.modifiers = CCodeModifiers.STATIC;
1167 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
1169 cparam_map.set (get_param_pos (-1), new CCodeFormalParameter ("callback", "GAsyncReadyCallback"));
1170 cparam_map.set (get_param_pos (-0.9), new CCodeFormalParameter ("user_data", "gpointer"));
1172 generate_cparameters (m, m.return_type, false, cparam_map, function, null, null, null, 1);
1174 var block = new CCodeBlock ();
1175 var prefragment = new CCodeFragment ();
1176 var postfragment = new CCodeFragment ();
1178 cdecl = new CCodeDeclaration ("DBusGConnection");
1179 cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection"));
1180 block.add_statement (cdecl);
1182 cdecl = new CCodeDeclaration ("DBusMessage");
1183 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
1184 block.add_statement (cdecl);
1186 cdecl = new CCodeDeclaration ("DBusPendingCall");
1187 cdecl.add_declarator (new CCodeVariableDeclarator ("*_pending"));
1188 block.add_statement (cdecl);
1190 cdecl = new CCodeDeclaration ("DBusMessageIter");
1191 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
1192 block.add_statement (cdecl);
1194 block.add_statement (prefragment);
1196 generate_marshalling (m, dbus_iface_name, prefragment, postfragment);
1198 var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
1199 gconnection.add_argument (new CCodeIdentifier ("self"));
1200 gconnection.add_argument (new CCodeConstant ("\"connection\""));
1201 gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection")));
1202 gconnection.add_argument (new CCodeConstant ("NULL"));
1203 block.add_statement (new CCodeExpressionStatement (gconnection));
1205 var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
1206 connection.add_argument (new CCodeIdentifier ("_connection"));
1208 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send_with_reply"));
1209 ccall.add_argument (connection);
1210 ccall.add_argument (new CCodeIdentifier ("_message"));
1211 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_pending")));
1212 ccall.add_argument (new CCodeConstant ("-1"));
1213 block.add_statement (new CCodeExpressionStatement (ccall));
1215 var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref"));
1216 conn_unref.add_argument (new CCodeIdentifier ("_connection"));
1217 block.add_statement (new CCodeExpressionStatement (conn_unref));
1219 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1220 message_unref.add_argument (new CCodeIdentifier ("_message"));
1221 block.add_statement (new CCodeExpressionStatement (message_unref));
1223 var dataalloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
1224 dataalloc.add_argument (new CCodeIdentifier (dataname));
1226 var datadecl = new CCodeDeclaration (dataname + "*");
1227 datadecl.add_declarator (new CCodeVariableDeclarator ("data"));
1228 block.add_statement (datadecl);
1229 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data"), dataalloc)));
1231 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "callback"), new CCodeIdentifier ("callback"))));
1232 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "user_data"), new CCodeIdentifier ("user_data"))));
1233 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "pending"), new CCodeIdentifier ("_pending"))));
1235 var pending = new CCodeFunctionCall (new CCodeIdentifier ("dbus_pending_call_set_notify"));
1236 pending.add_argument (new CCodeIdentifier ("_pending"));
1237 pending.add_argument (new CCodeIdentifier ("%sdbus_proxy_%s_ready".printf (iface.get_lower_case_cprefix (), m.name)));
1238 pending.add_argument (new CCodeIdentifier ("data"));
1239 pending.add_argument (new CCodeConstant ("NULL"));
1240 block.add_statement (new CCodeExpressionStatement (pending));
1242 source_type_member_declaration.append (function.copy ());
1243 function.block = block;
1244 source_type_member_definition.append (function);
1247 // generate ready function
1249 function = new CCodeFunction ("%sdbus_proxy_%s_ready".printf (iface.get_lower_case_cprefix (), m.name), "void");
1250 function.modifiers = CCodeModifiers.STATIC;
1252 function.add_parameter (new CCodeFormalParameter ("pending", "DBusPendingCall*"));
1253 function.add_parameter (new CCodeFormalParameter ("user_data", "void*"));
1255 block = new CCodeBlock ();
1257 datadecl = new CCodeDeclaration (dataname + "*");
1258 datadecl.add_declarator (new CCodeVariableDeclarator ("data"));
1259 block.add_statement (datadecl);
1260 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data"), new CCodeIdentifier ("user_data"))));
1262 // complete async call by invoking callback
1263 var object_creation = new CCodeFunctionCall (new CCodeIdentifier ("g_object_newv"));
1264 object_creation.add_argument (new CCodeConstant ("G_TYPE_OBJECT"));
1265 object_creation.add_argument (new CCodeConstant ("0"));
1266 object_creation.add_argument (new CCodeConstant ("NULL"));
1268 var async_result_creation = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_new"));
1269 async_result_creation.add_argument (object_creation);
1270 async_result_creation.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "callback"));
1271 async_result_creation.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "user_data"));
1272 async_result_creation.add_argument (new CCodeIdentifier ("data"));
1274 var completecall = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_complete"));
1275 completecall.add_argument (async_result_creation);
1276 block.add_statement (new CCodeExpressionStatement (completecall));
1278 source_type_member_declaration.append (function.copy ());
1279 function.block = block;
1280 source_type_member_definition.append (function);
1283 return proxy_name;
1286 string generate_finish_dbus_proxy_method (Interface iface, Method m) {
1287 string proxy_name = "%sdbus_proxy_%s_finish".printf (iface.get_lower_case_cprefix (), m.name);
1289 string dbus_iface_name = iface.get_attribute ("DBus").get_string ("name");
1291 CCodeDeclaration cdecl;
1293 var function = new CCodeFunction (proxy_name, m.return_type.get_cname ());
1294 function.modifiers = CCodeModifiers.STATIC;
1296 var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
1298 cparam_map.set (get_param_pos (0.1), new CCodeFormalParameter ("res", "GAsyncResult*"));
1300 generate_cparameters (m, m.return_type, false, cparam_map, function, null, null, null, 2);
1302 var block = new CCodeBlock ();
1303 var prefragment = new CCodeFragment ();
1304 var postfragment = new CCodeFragment ();
1306 string dataname = "%sDBusProxy%sData".printf (iface.get_cname (), Symbol.lower_case_to_camel_case (m.name));
1307 cdecl = new CCodeDeclaration (dataname + "*");
1308 cdecl.add_declarator (new CCodeVariableDeclarator ("data"));
1309 block.add_statement (cdecl);
1311 cdecl = new CCodeDeclaration ("DBusMessage");
1312 cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply"));
1313 block.add_statement (cdecl);
1315 cdecl = new CCodeDeclaration ("DBusMessageIter");
1316 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
1317 block.add_statement (cdecl);
1319 var get_user_data = new CCodeFunctionCall (new CCodeIdentifier ("g_async_result_get_user_data"));
1320 get_user_data.add_argument (new CCodeIdentifier ("res"));
1321 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data"), get_user_data)));
1323 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_pending_call_steal_reply"));
1324 ccall.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("data"), "pending"));
1325 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall)));
1327 generate_marshalling (m, dbus_iface_name, prefragment, postfragment);
1329 block.add_statement (postfragment);
1331 var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1332 reply_unref.add_argument (new CCodeIdentifier ("_reply"));
1333 block.add_statement (new CCodeExpressionStatement (reply_unref));
1335 if (!(m.return_type is VoidType)) {
1336 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result")));
1339 source_type_member_declaration.append (function.copy ());
1340 function.block = block;
1341 source_type_member_definition.append (function);
1343 return proxy_name;