codegen: Add destroy_local, destroy_parameter, and destroy_field
[vala-lang.git] / codegen / valadbusservermodule.vala
blob544b0b54cf1a85b84282cc660640148e995905cb
1 /* valadbusservermodule.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.DBusServerModule : DBusClientModule {
31 public static bool is_dbus_visible (CodeNode node) {
32 var dbus_attribute = node.get_attribute ("DBus");
33 if (dbus_attribute != null
34 && dbus_attribute.has_argument ("visible")
35 && !dbus_attribute.get_bool ("visible")) {
36 return false;
39 return true;
42 public static string dbus_result_name (Method m) {
43 var dbus_attribute = m.get_attribute ("DBus");
44 if (dbus_attribute != null
45 && dbus_attribute.has_argument ("result")) {
46 var result_name = dbus_attribute.get_string ("result");
47 if (result_name != null && result_name != "") {
48 return result_name;
52 return "result";
55 void send_reply (CCodeBlock block) {
56 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send"));
57 ccall.add_argument (new CCodeIdentifier ("connection"));
58 ccall.add_argument (new CCodeIdentifier ("reply"));
59 ccall.add_argument (new CCodeConstant ("NULL"));
60 block.add_statement (new CCodeExpressionStatement (ccall));
61 ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
62 ccall.add_argument (new CCodeIdentifier ("reply"));
63 block.add_statement (new CCodeExpressionStatement (ccall));
66 void handle_reply (CCodeBlock block) {
67 var handled = new CCodeBlock ();
68 send_reply (handled);
69 handled.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_HANDLED")));
71 var not_handled = new CCodeBlock ();
72 not_handled.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
74 block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("reply"), handled, not_handled));
77 string generate_dbus_wrapper (Method m, ObjectTypeSymbol sym) {
78 string wrapper_name = "_dbus_%s".printf (m.get_cname ());
80 // declaration
82 CCodeDeclaration cdecl;
84 var function = new CCodeFunction (wrapper_name, "DBusHandlerResult");
85 function.modifiers = CCodeModifiers.STATIC;
86 function.add_parameter (new CCodeParameter ("self", sym.get_cname () + "*"));
87 function.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
88 function.add_parameter (new CCodeParameter ("message", "DBusMessage*"));
89 var block = new CCodeBlock ();
91 CCodeFunction ready_function = null;
92 CCodeBlock ready_block = null;
93 if (m.coroutine) {
94 // GAsyncResult
95 cfile.add_include ("gio/gio.h");
97 ready_function = new CCodeFunction (wrapper_name + "_ready", "void");
98 ready_function.modifiers = CCodeModifiers.STATIC;
99 ready_function.add_parameter (new CCodeParameter ("source_object", "GObject *"));
100 ready_function.add_parameter (new CCodeParameter ("_res_", "GAsyncResult *"));
101 ready_function.add_parameter (new CCodeParameter ("_user_data_", "gpointer *"));
102 ready_block = new CCodeBlock ();
104 cdecl = new CCodeDeclaration ("DBusConnection *");
105 cdecl.add_declarator (new CCodeVariableDeclarator ("connection", new CCodeIdentifier ("_user_data_[0]")));
106 ready_block.add_statement (cdecl);
107 cdecl = new CCodeDeclaration ("DBusMessage *");
108 cdecl.add_declarator (new CCodeVariableDeclarator ("message", new CCodeIdentifier ("_user_data_[1]")));
109 ready_block.add_statement (cdecl);
112 var in_prefragment = new CCodeFragment ();
113 var in_postfragment = new CCodeFragment ();
114 var out_prefragment = in_prefragment;
115 var out_postfragment = in_postfragment;
117 cdecl = new CCodeDeclaration ("DBusMessageIter");
118 cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
119 block.add_statement (cdecl);
120 if (m.coroutine) {
121 out_prefragment = new CCodeFragment ();
122 out_postfragment = new CCodeFragment ();
123 ready_block.add_statement (cdecl);
126 cdecl = new CCodeDeclaration ("GError*");
127 cdecl.add_declarator (new CCodeVariableDeclarator ("error", new CCodeConstant ("NULL")));
128 if (m.coroutine) {
129 ready_block.add_statement (cdecl);
130 } else {
131 block.add_statement (cdecl);
134 block.add_statement (in_prefragment);
135 if (m.coroutine) {
136 ready_block.add_statement (out_prefragment);
139 var message_signature = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_get_signature"));
140 message_signature.add_argument (new CCodeIdentifier ("message"));
141 var signature_check = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
142 signature_check.add_argument (message_signature);
143 var signature_error_block = new CCodeBlock ();
144 signature_error_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
145 in_prefragment.append (new CCodeIfStatement (signature_check, signature_error_block));
147 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
148 iter_call.add_argument (new CCodeIdentifier ("message"));
149 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
150 in_prefragment.append (new CCodeExpressionStatement (iter_call));
152 cdecl = new CCodeDeclaration ("DBusMessage*");
153 cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
154 out_postfragment.append (cdecl);
156 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_return"));
157 msgcall.add_argument (new CCodeIdentifier ("message"));
158 out_postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), msgcall)));
160 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
161 iter_call.add_argument (new CCodeIdentifier ("reply"));
162 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
163 out_postfragment.append (new CCodeExpressionStatement (iter_call));
165 var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
167 CCodeFunctionCall finish_ccall = null;
168 if (m.coroutine) {
169 finish_ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_finish_cname ()));
170 finish_ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("source_object"), sym.get_cname () + "*"));
171 finish_ccall.add_argument (new CCodeIdentifier ("_res_"));
174 ccall.add_argument (new CCodeIdentifier ("self"));
176 // expected type signature for input parameters
177 string type_signature = "";
179 foreach (Parameter param in m.get_parameters ()) {
180 var owned_type = param.variable_type.copy ();
181 owned_type.value_owned = true;
183 cdecl = new CCodeDeclaration (owned_type.get_cname ());
184 cdecl.add_declarator (new CCodeVariableDeclarator.zero (param.name, default_value_for_type (param.variable_type, true)));
185 if (param.direction == ParameterDirection.IN) {
186 in_prefragment.append (cdecl);
187 } else {
188 out_prefragment.append (cdecl);
190 if (type_signature == ""
191 && param.direction == ParameterDirection.IN
192 && param.variable_type.data_type != null
193 && param.variable_type.data_type.get_full_name () == "DBus.BusName") {
194 // first parameter is a string parameter called 'sender'
195 // pass bus name of sender
196 var get_sender = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_get_sender"));
197 get_sender.add_argument (new CCodeIdentifier ("message"));
198 ccall.add_argument (get_sender);
199 continue;
202 if (get_type_signature (param.variable_type) == null) {
203 Report.error (param.variable_type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (param.variable_type.to_string ()));
204 continue;
207 if (!m.coroutine || param.direction == ParameterDirection.IN) {
208 var st = param.variable_type.data_type as Struct;
209 if (param.direction != ParameterDirection.IN
210 || (st != null && !st.is_simple_type ())) {
211 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
212 } else {
213 ccall.add_argument (new CCodeIdentifier (param.name));
215 } else {
216 finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param.name)));
219 if (param.variable_type is ArrayType) {
220 var array_type = (ArrayType) param.variable_type;
222 for (int dim = 1; dim <= array_type.rank; dim++) {
223 string length_cname = get_parameter_array_length_cname (param, dim);
225 cdecl = new CCodeDeclaration ("int");
226 cdecl.add_declarator (new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
227 if (!m.coroutine || param.direction == ParameterDirection.IN) {
228 if (param.direction != ParameterDirection.IN) {
229 out_prefragment.append (cdecl);
230 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
231 } else {
232 in_prefragment.append (cdecl);
233 ccall.add_argument (new CCodeIdentifier (length_cname));
235 } else {
236 out_prefragment.append (cdecl);
237 finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
242 if (param.direction == ParameterDirection.IN) {
243 type_signature += get_type_signature (param.variable_type);
245 var target = new CCodeIdentifier (param.name);
246 var expr = read_expression (in_prefragment, param.variable_type, new CCodeIdentifier ("iter"), target);
247 in_prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
248 } else {
249 write_expression (out_postfragment, param.variable_type, new CCodeIdentifier ("iter"), new CCodeIdentifier (param.name));
252 if (requires_destroy (owned_type)) {
253 // keep local alive (symbol_reference is weak)
254 var local = new LocalVariable (owned_type, param.name);
255 var stmt = new CCodeExpressionStatement (destroy_local (local));
256 if (param.direction == ParameterDirection.IN) {
257 in_postfragment.append (stmt);
258 } else {
259 out_postfragment.append (stmt);
264 signature_check.add_argument (new CCodeConstant ("\"%s\"".printf (type_signature)));
266 if (!(m.return_type is VoidType)) {
267 if (get_type_signature (m.return_type) == null) {
268 Report.error (m.return_type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (m.return_type.to_string ()));
269 } else if (m.return_type.is_real_non_null_struct_type ()) {
270 cdecl = new CCodeDeclaration (m.return_type.get_cname ());
271 cdecl.add_declarator (new CCodeVariableDeclarator.zero ("result", default_value_for_type (m.return_type, true)));
272 out_prefragment.append (cdecl);
274 if (!m.coroutine) {
275 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
276 } else {
277 finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
280 write_expression (out_postfragment, m.return_type, new CCodeIdentifier ("iter"), new CCodeIdentifier ("result"));
282 if (requires_destroy (m.return_type)) {
283 // keep local alive (symbol_reference is weak)
284 // space before `result' is work around to not trigger
285 // variable renaming, we really mean C identifier `result' here
286 var local = new LocalVariable (m.return_type, " result");
287 var ma = new MemberAccess.simple ("result");
288 ma.symbol_reference = local;
289 ma.value_type = m.return_type.copy ();
290 visit_member_access (ma);
291 out_postfragment.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("result"), m.return_type, ma)));
294 block.add_statement (new CCodeExpressionStatement (ccall));
295 if (m.coroutine) {
296 ready_block.add_statement (new CCodeExpressionStatement (finish_ccall));
298 } else {
299 cdecl = new CCodeDeclaration (m.return_type.get_cname ());
300 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
301 out_prefragment.append (cdecl);
302 if (!m.coroutine) {
303 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
304 } else {
305 block.add_statement (new CCodeExpressionStatement (ccall));
306 ready_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), finish_ccall)));
309 if (m.return_type is ArrayType) {
310 var array_type = (ArrayType) m.return_type;
312 for (int dim = 1; dim <= array_type.rank; dim++) {
313 string length_cname = get_array_length_cname ("result", dim);
315 cdecl = new CCodeDeclaration ("int");
316 cdecl.add_declarator (new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0")));
317 out_prefragment.append (cdecl);
318 if (!m.coroutine) {
319 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
320 } else {
321 finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
326 write_expression (out_postfragment, m.return_type, new CCodeIdentifier ("iter"), new CCodeIdentifier ("result"));
328 if (requires_destroy (m.return_type)) {
329 // keep local alive (symbol_reference is weak)
330 // space before `result' is work around to not trigger
331 // variable renaming, we really mean C identifier `result' here
332 var local = new LocalVariable (m.return_type, " result");
333 var ma = new MemberAccess.simple ("result");
334 ma.symbol_reference = local;
335 ma.value_type = m.return_type.copy ();
336 visit_member_access (ma);
337 out_postfragment.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("result"), m.return_type, ma)));
340 } else {
341 block.add_statement (new CCodeExpressionStatement (ccall));
342 if (m.coroutine) {
343 ready_block.add_statement (new CCodeExpressionStatement (finish_ccall));
347 if (m.coroutine) {
348 ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (wrapper_name + "_ready"), "GAsyncReadyCallback"));
350 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
351 new_call.add_argument (new CCodeIdentifier ("gpointer"));
352 new_call.add_argument (new CCodeConstant ("2"));
353 cdecl = new CCodeDeclaration ("gpointer *");
354 cdecl.add_declarator (new CCodeVariableDeclarator ("_user_data_", new_call));
355 in_prefragment.append (cdecl);
357 var ref_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_ref"));
358 ref_call.add_argument (new CCodeIdentifier ("connection"));
359 in_prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_user_data_[0]"), ref_call)));
360 ref_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_ref"));
361 ref_call.add_argument (new CCodeIdentifier ("message"));
362 in_prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_user_data_[1]"), ref_call)));
364 ccall.add_argument (new CCodeIdentifier ("_user_data_"));
367 if (m.get_error_types ().size > 0) {
368 if (m.coroutine) {
369 finish_ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
370 } else {
371 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
374 var error_block = new CCodeBlock ();
376 generate_server_error_cases (error_block, m.get_error_types (), new CCodeIdentifier ("error"), new CCodeIdentifier ("message"), new CCodeIdentifier ("reply"));
378 send_reply (error_block);
380 if (m.coroutine) {
381 error_block.add_statement (new CCodeReturnStatement ());
382 ready_block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("error"), error_block));
383 } else {
384 error_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_HANDLED")));
385 block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("error"), error_block));
389 block.add_statement (in_postfragment);
391 if (!m.coroutine) {
392 handle_reply (block);
393 } else {
394 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_HANDLED")));
396 ready_block.add_statement (out_postfragment);
398 send_reply (ready_block);
400 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_unref"));
401 unref_call.add_argument (new CCodeIdentifier ("connection"));
402 ready_block.add_statement (new CCodeExpressionStatement (unref_call));
403 unref_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
404 unref_call.add_argument (new CCodeIdentifier ("message"));
405 ready_block.add_statement (new CCodeExpressionStatement (unref_call));
406 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
407 free_call.add_argument (new CCodeIdentifier ("_user_data_"));
408 ready_block.add_statement (new CCodeExpressionStatement (free_call));
411 cfile.add_function_declaration (function);
413 function.block = block;
414 cfile.add_function (function);
416 if (m.coroutine) {
417 cfile.add_function_declaration (ready_function);
419 ready_function.block = ready_block;
420 cfile.add_function (ready_function);
423 return wrapper_name;
426 void generate_server_error_cases (CCodeBlock error_block, List<DataType> error_types, CCodeExpression error, CCodeExpression message, CCodeExpression reply) {
427 CCodeStatement if_else_if = null;
428 CCodeIfStatement last_statement = null;
430 foreach (DataType error_type in error_types) {
431 var edomain = ((ErrorType) error_type).error_domain;
433 if (edomain == null) {
434 Report.error (error_type.source_reference, "Generic errors cannot be serialized over DBus");
435 continue;
438 var edomain_dbus_name = get_dbus_name (edomain);
439 if (edomain_dbus_name == null) {
440 Report.error (edomain.source_reference, "Errordomain must have a DBus.name annotation to be serialized over DBus");
443 var true_block = new CCodeBlock ();
444 true_block.suppress_newline = true;
446 var cswitch = new CCodeSwitchStatement (new CCodeMemberAccess.pointer (error, "code"));
447 foreach (ErrorCode ecode in edomain.get_codes ()) {
448 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (ecode.get_cname ())));
450 var ecode_dbus_name = get_dbus_name (ecode);
451 if (ecode_dbus_name == null) {
452 ecode_dbus_name = Symbol.lower_case_to_camel_case (ecode.name.down ());
455 string dbus_name = "%s.%s".printf (edomain_dbus_name, ecode_dbus_name);
457 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_error"));
458 msgcall.add_argument (message);
459 msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_name)));
460 msgcall.add_argument (new CCodeMemberAccess.pointer (error, "message"));
461 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (reply, msgcall)));
463 cswitch.add_statement (new CCodeBreakStatement ());
465 true_block.add_statement (cswitch);
467 var equal_test = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeMemberAccess.pointer (error, "domain"), new CCodeIdentifier (edomain.get_upper_case_cname ()));
468 var stmt = new CCodeIfStatement (equal_test, true_block);
470 if (last_statement != null) {
471 last_statement.false_statement = stmt;
472 } else {
473 if_else_if = stmt;
475 last_statement = stmt;
477 error_block.add_statement (if_else_if);
480 string generate_dbus_signal_wrapper (Signal sig, ObjectTypeSymbol sym, string dbus_iface_name) {
481 string wrapper_name = "_dbus_%s_%s".printf (sym.get_lower_case_cname (), sig.get_cname ());
483 // declaration
485 CCodeDeclaration cdecl;
487 var function = new CCodeFunction (wrapper_name, "void");
488 function.modifiers = CCodeModifiers.STATIC;
490 function.add_parameter (new CCodeParameter ("_sender", "GObject*"));
492 foreach (var param in sig.get_parameters ()) {
493 // ensure ccodenode of parameter is set
494 var cparam = generate_parameter (param, cfile, new HashMap<int,CCodeParameter> (), null);
496 function.add_parameter (cparam);
497 if (param.variable_type is ArrayType) {
498 var array_type = (ArrayType) param.variable_type;
499 for (int dim = 1; dim <= array_type.rank; dim++) {
500 function.add_parameter (new CCodeParameter (get_parameter_array_length_cname (param, dim), "int"));
505 function.add_parameter (new CCodeParameter ("_connection", "DBusConnection*"));
507 var block = new CCodeBlock ();
508 var prefragment = new CCodeFragment ();
510 var path = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get_data"));
511 path.add_argument (new CCodeIdentifier ("_sender"));
512 path.add_argument (new CCodeConstant ("\"dbus_object_path\""));
514 cdecl = new CCodeDeclaration ("const char *");
515 cdecl.add_declarator (new CCodeVariableDeclarator ("_path", path));
516 block.add_statement (cdecl);
518 cdecl = new CCodeDeclaration ("DBusMessage");
519 cdecl.add_declarator (new CCodeVariableDeclarator ("*_message"));
520 block.add_statement (cdecl);
522 cdecl = new CCodeDeclaration ("DBusMessageIter");
523 cdecl.add_declarator (new CCodeVariableDeclarator ("_iter"));
524 block.add_statement (cdecl);
526 block.add_statement (prefragment);
528 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_signal"));
529 msgcall.add_argument (new CCodeIdentifier ("_path"));
530 msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
531 msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
532 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_message"), msgcall)));
534 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
535 iter_call.add_argument (new CCodeIdentifier ("_message"));
536 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter")));
537 prefragment.append (new CCodeExpressionStatement (iter_call));
539 foreach (Parameter param in sig.get_parameters ()) {
540 CCodeExpression expr = new CCodeIdentifier (param.name);
541 if (param.variable_type.is_real_struct_type ()) {
542 expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
544 write_expression (prefragment, param.variable_type, new CCodeIdentifier ("_iter"), expr);
547 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send"));
548 ccall.add_argument (new CCodeIdentifier ("_connection"));
549 ccall.add_argument (new CCodeIdentifier ("_message"));
550 ccall.add_argument (new CCodeConstant ("NULL"));
551 block.add_statement (new CCodeExpressionStatement (ccall));
553 var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
554 message_unref.add_argument (new CCodeIdentifier ("_message"));
555 block.add_statement (new CCodeExpressionStatement (message_unref));
557 cfile.add_function_declaration (function);
558 function.block = block;
559 cfile.add_function (function);
561 return wrapper_name;
564 void generate_register_function (ObjectType object_type) {
565 // strcmp
566 cfile.add_include ("string.h");
568 var sym = object_type.type_symbol;
570 var cfunc = new CCodeFunction (sym.get_lower_case_cprefix () + "dbus_register_object", "void");
571 cfunc.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
572 cfunc.add_parameter (new CCodeParameter ("path", "const char*"));
573 cfunc.add_parameter (new CCodeParameter ("object", "void*"));
575 add_dbus_helpers ();
577 if (sym.is_private_symbol ()) {
578 cfunc.modifiers |= CCodeModifiers.STATIC;
581 cfile.add_function_declaration (cfunc);
583 var block = new CCodeBlock ();
584 cfunc.block = block;
586 var get_path = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get_data"));
587 get_path.add_argument (new CCodeIdentifier ("object"));
588 get_path.add_argument (new CCodeConstant ("\"dbus_object_path\""));
589 var register_check = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, get_path);
591 var register_block = new CCodeBlock ();
593 var path_dup = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup"));
594 path_dup.add_argument (new CCodeIdentifier ("path"));
596 var set_path = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set_data"));
597 set_path.add_argument (new CCodeIdentifier ("object"));
598 set_path.add_argument (new CCodeConstant ("\"dbus_object_path\""));
599 set_path.add_argument (path_dup);
600 register_block.add_statement (new CCodeExpressionStatement (set_path));
602 var cregister = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_register_object_path"));
603 cregister.add_argument (new CCodeIdentifier ("connection"));
604 cregister.add_argument (new CCodeIdentifier ("path"));
605 cregister.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_path_vtable (object_type)));
606 cregister.add_argument (new CCodeIdentifier ("object"));
607 register_block.add_statement (new CCodeExpressionStatement (cregister));
609 var weak_unregister = new CCodeFunctionCall (new CCodeIdentifier ("g_object_weak_ref"));
610 weak_unregister.add_argument (new CCodeIdentifier ("object"));
611 weak_unregister.add_argument (new CCodeIdentifier ("_vala_dbus_unregister_object"));
612 weak_unregister.add_argument (new CCodeIdentifier ("connection"));
613 register_block.add_statement (new CCodeExpressionStatement (weak_unregister));
615 block.add_statement (new CCodeIfStatement (register_check, register_block));
617 handle_signals (object_type.type_symbol, block);
619 var cl = sym as Class;
620 if (cl != null) {
621 foreach (DataType base_type in cl.get_base_types ()) {
622 var base_obj_type = base_type as ObjectType;
623 if (type_implements_dbus_interface (base_obj_type.type_symbol)) {
624 var base_register = new CCodeFunctionCall (new CCodeIdentifier (base_obj_type.type_symbol.get_lower_case_cprefix () + "dbus_register_object"));
625 base_register.add_argument (new CCodeIdentifier ("connection"));
626 base_register.add_argument (new CCodeIdentifier ("path"));
627 base_register.add_argument (new CCodeIdentifier ("object"));
628 block.add_statement (new CCodeExpressionStatement (base_register));
633 cfile.add_function (cfunc);
636 void generate_unregister_function (ObjectType object_type) {
637 var sym = object_type.type_symbol;
639 var cfunc = new CCodeFunction ("_" + sym.get_lower_case_cprefix () + "dbus_unregister", "void");
640 cfunc.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
641 cfunc.add_parameter (new CCodeParameter ("_user_data_", "void*"));
643 cfile.add_function_declaration (cfunc);
645 var block = new CCodeBlock ();
646 cfunc.block = block;
648 cfile.add_function (cfunc);
651 void handle_method (string dbus_iface_name, string dbus_method_name, string handler_name, CCodeBlock block, ref CCodeIfStatement clastif) {
652 var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_is_method_call"));
653 ccheck.add_argument (new CCodeIdentifier ("message"));
654 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
655 ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_method_name)));
657 var callblock = new CCodeBlock ();
659 var ccall = new CCodeFunctionCall (new CCodeIdentifier (handler_name));
660 ccall.add_argument (new CCodeIdentifier ("object"));
661 ccall.add_argument (new CCodeIdentifier ("connection"));
662 ccall.add_argument (new CCodeIdentifier ("message"));
664 callblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
666 var cif = new CCodeIfStatement (ccheck, callblock);
667 if (clastif == null) {
668 block.add_statement (cif);
669 } else {
670 clastif.false_statement = cif;
673 clastif = cif;
676 void handle_methods (ObjectTypeSymbol sym, string dbus_iface_name, CCodeBlock block, ref CCodeIfStatement clastif) {
677 foreach (Method m in sym.get_methods ()) {
678 if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
679 || m.overrides || m.access != SymbolAccessibility.PUBLIC) {
680 continue;
682 if (!is_dbus_visible (m)) {
683 continue;
686 handle_method (dbus_iface_name, get_dbus_name_for_member (m), generate_dbus_wrapper (m, sym), block, ref clastif);
690 string generate_dbus_property_get_wrapper (ObjectTypeSymbol sym, string dbus_iface_name) {
691 string wrapper_name = "_dbus_%s_property_get".printf (sym.get_lower_case_cname ());
693 CCodeDeclaration cdecl;
695 var function = new CCodeFunction (wrapper_name, "DBusHandlerResult");
696 function.modifiers = CCodeModifiers.STATIC;
698 function.add_parameter (new CCodeParameter ("self", sym.get_cname () + "*"));
699 function.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
700 function.add_parameter (new CCodeParameter ("message", "DBusMessage*"));
702 var block = new CCodeBlock ();
703 var prefragment = new CCodeFragment ();
705 cdecl = new CCodeDeclaration ("DBusMessage*");
706 cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
707 block.add_statement (cdecl);
709 cdecl = new CCodeDeclaration ("DBusMessageIter");
710 cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
711 cdecl.add_declarator (new CCodeVariableDeclarator ("reply_iter"));
712 cdecl.add_declarator (new CCodeVariableDeclarator ("subiter"));
713 block.add_statement (cdecl);
715 var message_signature = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_get_signature"));
716 message_signature.add_argument (new CCodeIdentifier ("message"));
717 var signature_check = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
718 signature_check.add_argument (message_signature);
719 signature_check.add_argument (new CCodeConstant ("\"ss\""));
720 var signature_error_block = new CCodeBlock ();
721 signature_error_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
722 block.add_statement (new CCodeIfStatement (signature_check, signature_error_block));
724 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
725 iter_call.add_argument (new CCodeIdentifier ("message"));
726 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
727 block.add_statement (new CCodeExpressionStatement (iter_call));
729 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_return"));
730 msgcall.add_argument (new CCodeIdentifier ("message"));
731 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), msgcall)));
733 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
734 iter_call.add_argument (new CCodeIdentifier ("reply"));
735 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("reply_iter")));
736 block.add_statement (new CCodeExpressionStatement (iter_call));
738 block.add_statement (prefragment);
740 cdecl = new CCodeDeclaration ("char*");
741 cdecl.add_declarator (new CCodeVariableDeclarator ("interface_name"));
742 prefragment.append (cdecl);
743 var target = new CCodeIdentifier ("interface_name");
744 var expr = read_expression (prefragment, string_type, new CCodeIdentifier ("iter"), target);
745 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
747 cdecl = new CCodeDeclaration ("char*");
748 cdecl.add_declarator (new CCodeVariableDeclarator ("property_name"));
749 prefragment.append (cdecl);
750 target = new CCodeIdentifier ("property_name");
751 expr = read_expression (prefragment, string_type, new CCodeIdentifier ("iter"), target);
752 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
754 CCodeIfStatement clastif = null;
756 foreach (Property prop in sym.get_properties ()) {
757 if (prop.binding != MemberBinding.INSTANCE
758 || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
759 continue;
761 if (!is_dbus_visible (prop)) {
762 continue;
764 if (prop.get_accessor == null) {
765 continue;
768 var prop_block = new CCodeBlock ();
769 var postfragment = new CCodeFragment ();
770 prop_block.add_statement (postfragment);
772 var ccmp = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
773 ccmp.add_argument (new CCodeIdentifier ("interface_name"));
774 ccmp.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
775 var ccheck1 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccmp, new CCodeConstant ("0"));
777 ccmp = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
778 ccmp.add_argument (new CCodeIdentifier ("property_name"));
779 ccmp.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
780 var ccheck2 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccmp, new CCodeConstant ("0"));
782 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccheck1, ccheck2);
784 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
785 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("reply_iter")));
786 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
787 iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_signature (prop.property_type))));
788 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
789 postfragment.append (new CCodeExpressionStatement (iter_call));
791 var ccall = new CCodeFunctionCall (new CCodeIdentifier (prop.get_accessor.get_cname ()));
792 ccall.add_argument (new CCodeIdentifier ("self"));
794 cdecl = new CCodeDeclaration (prop.property_type.get_cname ());
795 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
796 postfragment.append (cdecl);
798 if (prop.property_type.is_real_non_null_struct_type ()) {
799 // structs are returned via out parameter
800 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
802 postfragment.append (new CCodeExpressionStatement (ccall));
803 } else {
804 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
806 var array_type = prop.property_type as ArrayType;
807 if (array_type != null) {
808 for (int dim = 1; dim <= array_type.rank; dim++) {
809 string length_cname = get_array_length_cname ("result", dim);
811 cdecl = new CCodeDeclaration ("int");
812 cdecl.add_declarator (new CCodeVariableDeclarator (length_cname));
813 postfragment.append (cdecl);
815 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
820 write_expression (postfragment, prop.property_type, new CCodeIdentifier ("subiter"), new CCodeIdentifier ("result"));
822 if (requires_destroy (prop.get_accessor.value_type)) {
823 // keep local alive (symbol_reference is weak)
824 // space before `result' is work around to not trigger
825 // variable renaming, we really mean C identifier `result' here
826 var local = new LocalVariable (prop.get_accessor.value_type, " result");
827 var ma = new MemberAccess.simple ("result");
828 ma.symbol_reference = local;
829 ma.value_type = local.variable_type.copy ();
830 visit_member_access (ma);
831 postfragment.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("result"), prop.get_accessor.value_type, ma)));
834 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
835 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("reply_iter")));
836 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
837 postfragment.append (new CCodeExpressionStatement (iter_call));
839 var cif = new CCodeIfStatement (ccheck, prop_block);
840 if (clastif == null) {
841 block.add_statement (cif);
842 } else {
843 clastif.false_statement = cif;
846 clastif = cif;
849 // free interface_name and property_name
850 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
851 free_call.add_argument (new CCodeIdentifier ("interface_name"));
852 block.add_statement (new CCodeExpressionStatement (free_call));
854 free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
855 free_call.add_argument (new CCodeIdentifier ("property_name"));
856 block.add_statement (new CCodeExpressionStatement (free_call));
858 if (clastif == null) {
859 block = new CCodeBlock ();
860 block.add_statement (new CCodeReturnStatement (new CCodeConstant ("NULL")));
861 } else {
862 var else_block = new CCodeBlock ();
863 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
864 unref_call.add_argument (new CCodeIdentifier ("reply"));
865 else_block.add_statement (new CCodeExpressionStatement (unref_call));
866 else_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), new CCodeConstant ("NULL"))));
867 clastif.false_statement = else_block;
869 handle_reply (block);
872 cfile.add_function_declaration (function);
874 function.block = block;
875 cfile.add_function (function);
877 return wrapper_name;
880 string generate_dbus_property_get_all_wrapper (ObjectTypeSymbol sym, string dbus_iface_name) {
881 string wrapper_name = "_dbus_%s_property_get_all".printf (sym.get_lower_case_cname ());
883 bool has_readable_properties = false;
884 foreach (Property prop in sym.get_properties ()) {
885 if (prop.binding != MemberBinding.INSTANCE
886 || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
887 continue;
889 if (!is_dbus_visible (prop)) {
890 continue;
892 if (prop.get_accessor != null) {
893 has_readable_properties = true;
897 CCodeDeclaration cdecl;
899 var function = new CCodeFunction (wrapper_name, "DBusHandlerResult");
900 function.modifiers = CCodeModifiers.STATIC;
902 function.add_parameter (new CCodeParameter ("self", sym.get_cname () + "*"));
903 function.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
904 function.add_parameter (new CCodeParameter ("message", "DBusMessage*"));
906 var block = new CCodeBlock ();
907 var prefragment = new CCodeFragment ();
909 cdecl = new CCodeDeclaration ("DBusMessage*");
910 cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
911 block.add_statement (cdecl);
913 cdecl = new CCodeDeclaration ("DBusMessageIter");
914 cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
915 cdecl.add_declarator (new CCodeVariableDeclarator ("reply_iter"));
916 cdecl.add_declarator (new CCodeVariableDeclarator ("subiter"));
917 if (has_readable_properties) {
918 cdecl.add_declarator (new CCodeVariableDeclarator ("entry_iter"));
919 cdecl.add_declarator (new CCodeVariableDeclarator ("value_iter"));
921 block.add_statement (cdecl);
923 var message_signature = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_get_signature"));
924 message_signature.add_argument (new CCodeIdentifier ("message"));
925 var signature_check = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
926 signature_check.add_argument (message_signature);
927 signature_check.add_argument (new CCodeConstant ("\"s\""));
928 var signature_error_block = new CCodeBlock ();
929 signature_error_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
930 block.add_statement (new CCodeIfStatement (signature_check, signature_error_block));
932 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
933 iter_call.add_argument (new CCodeIdentifier ("message"));
934 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
935 block.add_statement (new CCodeExpressionStatement (iter_call));
937 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_return"));
938 msgcall.add_argument (new CCodeIdentifier ("message"));
939 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), msgcall)));
941 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
942 iter_call.add_argument (new CCodeIdentifier ("reply"));
943 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("reply_iter")));
944 block.add_statement (new CCodeExpressionStatement (iter_call));
946 block.add_statement (prefragment);
948 cdecl = new CCodeDeclaration ("char*");
949 cdecl.add_declarator (new CCodeVariableDeclarator ("interface_name"));
950 prefragment.append (cdecl);
951 var target = new CCodeIdentifier ("interface_name");
952 var expr = read_expression (prefragment, string_type, new CCodeIdentifier ("iter"), target);
953 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
955 if (has_readable_properties) {
956 cdecl = new CCodeDeclaration ("const char*");
957 cdecl.add_declarator (new CCodeVariableDeclarator ("property_name"));
958 prefragment.append (cdecl);
961 var prop_block = new CCodeBlock ();
963 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
964 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("reply_iter")));
965 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
966 iter_call.add_argument (new CCodeConstant ("\"{sv}\""));
967 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
968 prop_block.add_statement (new CCodeExpressionStatement (iter_call));
970 foreach (Property prop in sym.get_properties ()) {
971 if (prop.binding != MemberBinding.INSTANCE
972 || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
973 continue;
975 if (!is_dbus_visible (prop)) {
976 continue;
978 if (prop.get_accessor == null) {
979 continue;
982 var inner_block = new CCodeBlock ();
983 prop_block.add_statement (inner_block);
984 var postfragment = new CCodeFragment ();
985 inner_block.add_statement (postfragment);
987 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
988 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
989 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_DICT_ENTRY"));
990 iter_call.add_argument (new CCodeConstant ("NULL"));
991 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entry_iter")));
992 postfragment.append (new CCodeExpressionStatement (iter_call));
994 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("property_name"), new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))))));
996 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic"));
997 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entry_iter")));
998 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_STRING"));
999 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("property_name")));
1000 postfragment.append (new CCodeExpressionStatement (iter_call));
1002 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
1003 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entry_iter")));
1004 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
1005 iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (get_type_signature (prop.property_type))));
1006 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value_iter")));
1007 postfragment.append (new CCodeExpressionStatement (iter_call));
1009 var ccall = new CCodeFunctionCall (new CCodeIdentifier (prop.get_accessor.get_cname ()));
1010 ccall.add_argument (new CCodeIdentifier ("self"));
1012 cdecl = new CCodeDeclaration (prop.property_type.get_cname ());
1013 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
1014 postfragment.append (cdecl);
1016 if (prop.property_type.is_real_non_null_struct_type ()) {
1017 // structs are returned via out parameter
1018 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
1020 postfragment.append (new CCodeExpressionStatement (ccall));
1021 } else {
1022 postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("result"), ccall)));
1024 var array_type = prop.property_type as ArrayType;
1025 if (array_type != null) {
1026 for (int dim = 1; dim <= array_type.rank; dim++) {
1027 string length_cname = get_array_length_cname ("result", dim);
1029 cdecl = new CCodeDeclaration ("int");
1030 cdecl.add_declarator (new CCodeVariableDeclarator (length_cname));
1031 postfragment.append (cdecl);
1033 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
1038 write_expression (postfragment, prop.property_type, new CCodeIdentifier ("value_iter"), new CCodeIdentifier ("result"));
1040 if (requires_destroy (prop.get_accessor.value_type)) {
1041 // keep local alive (symbol_reference is weak)
1042 // space before `result' is work around to not trigger
1043 // variable renaming, we really mean C identifier `result' here
1044 var local = new LocalVariable (prop.get_accessor.value_type, " result");
1045 var ma = new MemberAccess.simple ("result");
1046 ma.symbol_reference = local;
1047 ma.value_type = local.variable_type.copy ();
1048 visit_member_access (ma);
1049 postfragment.append (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("result"), prop.get_accessor.value_type, ma)));
1052 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
1053 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entry_iter")));
1054 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value_iter")));
1055 postfragment.append (new CCodeExpressionStatement (iter_call));
1057 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
1058 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
1059 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("entry_iter")));
1060 postfragment.append (new CCodeExpressionStatement (iter_call));
1063 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
1064 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("reply_iter")));
1065 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
1066 prop_block.add_statement (new CCodeExpressionStatement (iter_call));
1068 var ccmp = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
1069 ccmp.add_argument (new CCodeIdentifier ("interface_name"));
1070 ccmp.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
1071 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccmp, new CCodeConstant ("0"));
1073 var else_block = new CCodeBlock ();
1074 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1075 unref_call.add_argument (new CCodeIdentifier ("reply"));
1076 else_block.add_statement (new CCodeExpressionStatement (unref_call));
1077 else_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), new CCodeConstant ("NULL"))));
1079 block.add_statement (new CCodeIfStatement (ccheck, prop_block, else_block));
1081 // free interface_name
1082 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
1083 free_call.add_argument (new CCodeIdentifier ("interface_name"));
1084 block.add_statement (new CCodeExpressionStatement (free_call));
1086 handle_reply (block);
1088 cfile.add_function_declaration (function);
1090 function.block = block;
1091 cfile.add_function (function);
1093 return wrapper_name;
1096 string generate_dbus_property_set_wrapper (ObjectTypeSymbol sym, string dbus_iface_name) {
1097 string wrapper_name = "_dbus_%s_property_set".printf (sym.get_lower_case_cname ());
1099 var function = new CCodeFunction (wrapper_name, "DBusHandlerResult");
1100 function.modifiers = CCodeModifiers.STATIC;
1102 function.add_parameter (new CCodeParameter ("self", sym.get_cname () + "*"));
1103 function.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
1104 function.add_parameter (new CCodeParameter ("message", "DBusMessage*"));
1106 var block = new CCodeBlock ();
1107 var prefragment = new CCodeFragment ();
1109 var cdecl = new CCodeDeclaration ("DBusMessage*");
1110 cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
1111 block.add_statement (cdecl);
1113 cdecl = new CCodeDeclaration ("DBusMessageIter");
1114 cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
1115 cdecl.add_declarator (new CCodeVariableDeclarator ("subiter"));
1116 block.add_statement (cdecl);
1118 var message_signature = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_get_signature"));
1119 message_signature.add_argument (new CCodeIdentifier ("message"));
1120 var signature_check = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
1121 signature_check.add_argument (message_signature);
1122 signature_check.add_argument (new CCodeConstant ("\"ssv\""));
1123 var signature_error_block = new CCodeBlock ();
1124 signature_error_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
1125 block.add_statement (new CCodeIfStatement (signature_check, signature_error_block));
1127 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init"));
1128 iter_call.add_argument (new CCodeIdentifier ("message"));
1129 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
1130 block.add_statement (new CCodeExpressionStatement (iter_call));
1132 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_return"));
1133 msgcall.add_argument (new CCodeIdentifier ("message"));
1134 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), msgcall)));
1136 block.add_statement (prefragment);
1138 cdecl = new CCodeDeclaration ("char*");
1139 cdecl.add_declarator (new CCodeVariableDeclarator ("interface_name"));
1140 prefragment.append (cdecl);
1141 var target = new CCodeIdentifier ("interface_name");
1142 var expr = read_expression (prefragment, string_type, new CCodeIdentifier ("iter"), target);
1143 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1145 cdecl = new CCodeDeclaration ("char*");
1146 cdecl.add_declarator (new CCodeVariableDeclarator ("property_name"));
1147 prefragment.append (cdecl);
1148 target = new CCodeIdentifier ("property_name");
1149 expr = read_expression (prefragment, string_type, new CCodeIdentifier ("iter"), target);
1150 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1152 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
1153 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
1154 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("subiter")));
1155 prefragment.append (new CCodeExpressionStatement (iter_call));
1157 CCodeIfStatement clastif = null;
1159 foreach (Property prop in sym.get_properties ()) {
1160 if (prop.binding != MemberBinding.INSTANCE
1161 || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
1162 continue;
1164 if (!is_dbus_visible (prop)) {
1165 continue;
1167 if (prop.set_accessor == null) {
1168 continue;
1171 var prop_block = new CCodeBlock ();
1172 prefragment = new CCodeFragment ();
1173 prop_block.add_statement (prefragment);
1175 var ccmp = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
1176 ccmp.add_argument (new CCodeIdentifier ("interface_name"));
1177 ccmp.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
1178 var ccheck1 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccmp, new CCodeConstant ("0"));
1180 ccmp = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
1181 ccmp.add_argument (new CCodeIdentifier ("property_name"));
1182 ccmp.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
1183 var ccheck2 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccmp, new CCodeConstant ("0"));
1185 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccheck1, ccheck2);
1187 var owned_type = prop.property_type.copy ();
1188 owned_type.value_owned = true;
1190 cdecl = new CCodeDeclaration (owned_type.get_cname ());
1191 cdecl.add_declarator (new CCodeVariableDeclarator ("value"));
1192 prefragment.append (cdecl);
1194 target = new CCodeIdentifier ("value");
1195 expr = read_expression (prefragment, prop.property_type, new CCodeIdentifier ("subiter"), target);
1196 prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr)));
1198 var ccall = new CCodeFunctionCall (new CCodeIdentifier (prop.set_accessor.get_cname ()));
1199 ccall.add_argument (new CCodeIdentifier ("self"));
1201 if (prop.property_type.is_real_non_null_struct_type ()) {
1202 // structs are passed by reference
1203 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
1204 } else {
1205 ccall.add_argument (new CCodeIdentifier ("value"));
1207 var array_type = prop.property_type as ArrayType;
1208 if (array_type != null) {
1209 for (int dim = 1; dim <= array_type.rank; dim++) {
1210 cdecl = new CCodeDeclaration ("int");
1211 cdecl.add_declarator (new CCodeVariableDeclarator (get_array_length_cname ("value", dim)));
1212 prefragment.append (cdecl);
1214 ccall.add_argument (new CCodeIdentifier (get_array_length_cname ("value", dim)));
1219 prop_block.add_statement (new CCodeExpressionStatement (ccall));
1221 if (requires_destroy (owned_type)) {
1222 // keep local alive (symbol_reference is weak)
1223 var local = new LocalVariable (owned_type, "value");
1224 var ma = new MemberAccess.simple ("value");
1225 ma.symbol_reference = local;
1226 ma.value_type = local.variable_type.copy ();
1227 visit_member_access (ma);
1228 prop_block.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier ("value"), owned_type, ma)));
1231 var cif = new CCodeIfStatement (ccheck, prop_block);
1232 if (clastif == null) {
1233 block.add_statement (cif);
1234 } else {
1235 clastif.false_statement = cif;
1238 clastif = cif;
1241 // free interface_name and property_name
1242 var free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
1243 free_call.add_argument (new CCodeIdentifier ("interface_name"));
1244 block.add_statement (new CCodeExpressionStatement (free_call));
1246 free_call = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
1247 free_call.add_argument (new CCodeIdentifier ("property_name"));
1248 block.add_statement (new CCodeExpressionStatement (free_call));
1250 if (clastif == null) {
1251 block = new CCodeBlock ();
1252 block.add_statement (new CCodeReturnStatement (new CCodeConstant ("NULL")));
1253 } else {
1254 var else_block = new CCodeBlock ();
1255 var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref"));
1256 unref_call.add_argument (new CCodeIdentifier ("reply"));
1257 else_block.add_statement (new CCodeExpressionStatement (unref_call));
1258 else_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), new CCodeIdentifier ("NULL"))));
1259 clastif.false_statement = else_block;
1261 handle_reply (block);
1264 cfile.add_function_declaration (function);
1266 function.block = block;
1267 cfile.add_function (function);
1269 return wrapper_name;
1272 string get_dbus_type_introspection (ObjectTypeSymbol sym) {
1273 string result = "";
1275 var cl = sym as Class;
1276 if (cl != null) {
1277 foreach (DataType base_type in cl.get_base_types ()) {
1278 var base_obj_type = base_type as ObjectType;
1279 result += get_dbus_type_introspection (base_obj_type.type_symbol);
1283 string dbus_iface_name = get_dbus_name (sym);
1284 if (dbus_iface_name == null) {
1285 return result;
1288 result += "<interface name=\"%s\">\n".printf (dbus_iface_name);
1290 foreach (var m in sym.get_methods ()) {
1291 if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
1292 || m.overrides || m.access != SymbolAccessibility.PUBLIC) {
1293 continue;
1295 if (!is_dbus_visible (m)) {
1296 continue;
1299 result += " <method name=\"%s\">\n".printf (get_dbus_name_for_member (m));
1301 foreach (var param in m.get_parameters ()) {
1302 if (param.variable_type.data_type != null
1303 && param.variable_type.data_type.get_full_name () == "DBus.BusName") {
1304 // skip sender parameter
1305 // (implicit in D-Bus)
1306 continue;
1309 string direction = param.direction == ParameterDirection.IN ? "in" : "out";
1310 result += " <arg name=\"%s\" type=\"%s\" direction=\"%s\"/>\n".printf (param.name, get_type_signature (param.variable_type), direction);
1312 if (!(m.return_type is VoidType)) {
1313 result += " <arg name=\"%s\" type=\"%s\" direction=\"out\"/>\n".printf (dbus_result_name (m), get_type_signature (m.return_type));
1316 result += " </method>\n";
1319 foreach (var prop in sym.get_properties ()) {
1320 if (prop.binding != MemberBinding.INSTANCE
1321 || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
1322 continue;
1324 if (!is_dbus_visible (prop)) {
1325 continue;
1328 string access = (prop.get_accessor != null ? "read" : "") + (prop.set_accessor != null ? "write" : "");
1329 result += " <property name=\"%s\" type=\"%s\" access=\"%s\"/>\n".printf (get_dbus_name_for_member (prop), get_type_signature (prop.property_type), access);
1332 foreach (var sig in sym.get_signals ()) {
1333 if (sig.access != SymbolAccessibility.PUBLIC) {
1334 continue;
1336 if (!is_dbus_visible (sig)) {
1337 continue;
1340 result += " <signal name=\"%s\">\n".printf (get_dbus_name_for_member (sig));
1342 foreach (var param in sig.get_parameters ()) {
1343 result += " <arg name=\"%s\" type=\"%s\"/>\n".printf (param.name, get_type_signature (param.variable_type));
1346 result += " </signal>\n";
1349 result += "</interface>\n";
1351 return result;
1354 string generate_dbus_introspect (ObjectTypeSymbol sym) {
1355 string wrapper_name = "_dbus_%s_introspect".printf (sym.get_lower_case_cname ());
1357 var function = new CCodeFunction (wrapper_name, "DBusHandlerResult");
1358 function.modifiers = CCodeModifiers.STATIC;
1360 function.add_parameter (new CCodeParameter ("self", sym.get_cname () + "*"));
1361 function.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
1362 function.add_parameter (new CCodeParameter ("message", "DBusMessage*"));
1364 var block = new CCodeBlock ();
1366 var cdecl = new CCodeDeclaration ("DBusMessage*");
1367 cdecl.add_declarator (new CCodeVariableDeclarator ("reply"));
1368 block.add_statement (cdecl);
1370 cdecl = new CCodeDeclaration ("DBusMessageIter");
1371 cdecl.add_declarator (new CCodeVariableDeclarator ("iter"));
1372 block.add_statement (cdecl);
1374 var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_return"));
1375 msgcall.add_argument (new CCodeIdentifier ("message"));
1376 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("reply"), msgcall)));
1378 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append"));
1379 iter_call.add_argument (new CCodeIdentifier ("reply"));
1380 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
1381 block.add_statement (new CCodeExpressionStatement (iter_call));
1383 cdecl = new CCodeDeclaration ("GString*");
1384 cdecl.add_declarator (new CCodeVariableDeclarator ("xml_data"));
1385 block.add_statement (cdecl);
1387 cdecl = new CCodeDeclaration ("char**");
1388 cdecl.add_declarator (new CCodeVariableDeclarator ("children"));
1389 block.add_statement (cdecl);
1391 cdecl = new CCodeDeclaration ("int");
1392 cdecl.add_declarator (new CCodeVariableDeclarator ("i"));
1393 block.add_statement (cdecl);
1395 string xml_data = "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n";
1396 var str_call = new CCodeFunctionCall (new CCodeIdentifier ("g_string_new"));
1397 str_call.add_argument (new CCodeConstant ("\"%s\"".printf (xml_data.escape (""))));
1398 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("xml_data"), str_call)));
1400 xml_data = "<node>\n";
1401 xml_data +=
1402 """<interface name="org.freedesktop.DBus.Introspectable">
1403 <method name="Introspect">
1404 <arg name="data" direction="out" type="s"/>
1405 </method>
1406 </interface>
1407 <interface name="org.freedesktop.DBus.Properties">
1408 <method name="Get">
1409 <arg name="interface" direction="in" type="s"/>
1410 <arg name="propname" direction="in" type="s"/>
1411 <arg name="value" direction="out" type="v"/>
1412 </method>
1413 <method name="Set">
1414 <arg name="interface" direction="in" type="s"/>
1415 <arg name="propname" direction="in" type="s"/>
1416 <arg name="value" direction="in" type="v"/>
1417 </method>
1418 <method name="GetAll">
1419 <arg name="interface" direction="in" type="s"/>
1420 <arg name="props" direction="out" type="a{sv}"/>
1421 </method>
1422 </interface>
1423 """;
1424 xml_data += get_dbus_type_introspection (sym);
1425 str_call = new CCodeFunctionCall (new CCodeIdentifier ("g_string_append"));
1426 str_call.add_argument (new CCodeIdentifier ("xml_data"));
1427 str_call.add_argument (new CCodeConstant ("\"%s\"".printf (xml_data.escape (""))));
1428 block.add_statement (new CCodeExpressionStatement (str_call));
1430 var get_path = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get_data"));
1431 get_path.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *"));
1432 get_path.add_argument (new CCodeConstant ("\"dbus_object_path\""));
1434 var list_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_list_registered"));
1435 list_call.add_argument (new CCodeIdentifier ("connection"));
1436 list_call.add_argument (get_path);
1437 list_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("children")));
1438 block.add_statement (new CCodeExpressionStatement (list_call));
1440 // add child nodes
1441 var child_block = new CCodeBlock ();
1442 str_call = new CCodeFunctionCall (new CCodeIdentifier ("g_string_append_printf"));
1443 str_call.add_argument (new CCodeIdentifier ("xml_data"));
1444 str_call.add_argument (new CCodeConstant ("\"%s\"".printf ("<node name=\"%s\"/>\n".escape (""))));
1445 str_call.add_argument (new CCodeElementAccess (new CCodeIdentifier ("children"), new CCodeIdentifier ("i")));
1446 child_block.add_statement (new CCodeExpressionStatement (str_call));
1447 var cfor = new CCodeForStatement (new CCodeElementAccess (new CCodeIdentifier ("children"), new CCodeIdentifier ("i")), child_block);
1448 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
1449 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
1450 block.add_statement (cfor);
1452 var list_free_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_free_string_array"));
1453 list_free_call.add_argument (new CCodeIdentifier ("children"));
1454 block.add_statement (new CCodeExpressionStatement (list_free_call));
1456 xml_data = "</node>\n";
1457 str_call = new CCodeFunctionCall (new CCodeIdentifier ("g_string_append"));
1458 str_call.add_argument (new CCodeIdentifier ("xml_data"));
1459 str_call.add_argument (new CCodeConstant ("\"%s\"".printf (xml_data.escape (""))));
1460 block.add_statement (new CCodeExpressionStatement (str_call));
1462 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic"));
1463 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("iter")));
1464 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_STRING"));
1465 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (new CCodeIdentifier ("xml_data"), "str")));
1466 block.add_statement (new CCodeExpressionStatement (iter_call));
1468 str_call = new CCodeFunctionCall (new CCodeIdentifier ("g_string_free"));
1469 str_call.add_argument (new CCodeIdentifier ("xml_data"));
1470 str_call.add_argument (new CCodeConstant ("TRUE"));
1471 block.add_statement (new CCodeExpressionStatement (str_call));
1473 handle_reply (block);
1475 cfile.add_function_declaration (function);
1477 function.block = block;
1478 cfile.add_function (function);
1480 return wrapper_name;
1483 void handle_signals (ObjectTypeSymbol sym, CCodeBlock block) {
1484 string dbus_iface_name = get_dbus_name (sym);
1485 if (dbus_iface_name == null) {
1486 return;
1489 foreach (Signal sig in sym.get_signals ()) {
1490 if (sig.access != SymbolAccessibility.PUBLIC) {
1491 continue;
1493 if (!is_dbus_visible (sig)) {
1494 continue;
1497 var connect = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_connect"));
1498 connect.add_argument (new CCodeIdentifier ("object"));
1499 connect.add_argument (sig.get_canonical_cconstant ());
1500 connect.add_argument (new CCodeCastExpression (new CCodeIdentifier (generate_dbus_signal_wrapper (sig, sym, dbus_iface_name)), "GCallback"));
1501 connect.add_argument (new CCodeIdentifier ("connection"));
1502 block.add_statement (new CCodeExpressionStatement (connect));
1506 void generate_message_function (ObjectType object_type) {
1507 var sym = object_type.type_symbol;
1509 add_dbus_helpers ();
1511 var cfunc = new CCodeFunction (sym.get_lower_case_cprefix () + "dbus_message", "DBusHandlerResult");
1512 cfunc.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
1513 cfunc.add_parameter (new CCodeParameter ("message", "DBusMessage*"));
1514 cfunc.add_parameter (new CCodeParameter ("object", "void*"));
1516 if (sym.is_private_symbol ()) {
1517 cfunc.modifiers |= CCodeModifiers.STATIC;
1520 cfile.add_function_declaration (cfunc);
1522 var block = new CCodeBlock ();
1523 cfunc.block = block;
1525 var cdecl = new CCodeDeclaration ("DBusHandlerResult");
1526 cdecl.add_declarator (new CCodeVariableDeclarator ("result", new CCodeConstant ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
1527 block.add_statement (cdecl);
1529 CCodeIfStatement clastif = null;
1531 handle_method ("org.freedesktop.DBus.Introspectable", "Introspect", generate_dbus_introspect (sym), block, ref clastif);
1533 string dbus_iface_name = get_dbus_name (sym);
1534 if (dbus_iface_name != null) {
1535 bool need_property_get = false;
1536 bool need_property_set = false;
1537 foreach (Property prop in sym.get_properties ()) {
1538 if (prop.binding != MemberBinding.INSTANCE
1539 || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
1540 continue;
1542 if (!is_dbus_visible (prop)) {
1543 continue;
1545 if (prop.get_accessor != null) {
1546 need_property_get = true;
1548 if (prop.set_accessor != null) {
1549 need_property_set = true;
1553 if (need_property_get) {
1554 handle_method ("org.freedesktop.DBus.Properties", "Get", generate_dbus_property_get_wrapper (sym, dbus_iface_name), block, ref clastif);
1556 if (need_property_set) {
1557 handle_method ("org.freedesktop.DBus.Properties", "Set", generate_dbus_property_set_wrapper (sym, dbus_iface_name), block, ref clastif);
1559 handle_method ("org.freedesktop.DBus.Properties", "GetAll", generate_dbus_property_get_all_wrapper (sym, dbus_iface_name), block, ref clastif);
1561 handle_methods (sym, dbus_iface_name, block, ref clastif);
1564 var resultblock = new CCodeBlock ();
1565 resultblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
1566 var cif = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("result"), new CCodeIdentifier ("DBUS_HANDLER_RESULT_HANDLED")), resultblock);
1567 block.add_statement (cif);
1568 clastif = cif;
1570 var cl = sym as Class;
1571 if (cl != null) {
1572 foreach (DataType base_type in cl.get_base_types ()) {
1573 var base_obj_type = base_type as ObjectType;
1574 if (type_implements_dbus_interface (base_obj_type.type_symbol)) {
1575 var base_call = new CCodeFunctionCall (new CCodeIdentifier (base_obj_type.type_symbol.get_lower_case_cprefix () + "dbus_message"));
1576 base_call.add_argument (new CCodeIdentifier ("connection"));
1577 base_call.add_argument (new CCodeIdentifier ("message"));
1578 base_call.add_argument (new CCodeIdentifier ("object"));
1580 var ccheck = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, base_call, new CCodeIdentifier ("DBUS_HANDLER_RESULT_HANDLED"));
1582 var base_block = new CCodeBlock ();
1583 base_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_HANDLED")));
1585 cif = new CCodeIfStatement (ccheck, base_block);
1586 clastif.false_statement = cif;
1588 clastif = cif;
1593 var retblock = new CCodeBlock ();
1594 retblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("DBUS_HANDLER_RESULT_NOT_YET_HANDLED")));
1595 clastif.false_statement = retblock;
1597 cfile.add_function (cfunc);
1600 CCodeExpression get_vtable (ObjectType object_type) {
1601 var sym = object_type.type_symbol;
1603 if (add_wrapper ("_" + sym.get_lower_case_cprefix () + "dbus_vtable")) {
1604 var vtable = new CCodeInitializerList ();
1605 vtable.append (new CCodeIdentifier (sym.get_lower_case_cprefix () + "dbus_register_object"));
1607 generate_register_function (object_type);
1609 var cdecl = new CCodeDeclaration ("const _DBusObjectVTable");
1610 cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_vtable", vtable));
1611 cdecl.modifiers = CCodeModifiers.STATIC;
1612 cfile.add_constant_declaration (cdecl);
1615 return new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_vtable");
1618 CCodeExpression get_path_vtable (ObjectType object_type) {
1619 var sym = object_type.type_symbol;
1621 var vtable = new CCodeInitializerList ();
1622 vtable.append (new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_unregister"));
1623 vtable.append (new CCodeIdentifier (sym.get_lower_case_cprefix () + "dbus_message"));
1625 generate_unregister_function (object_type);
1626 generate_message_function (object_type);
1628 var cdecl = new CCodeDeclaration ("const DBusObjectPathVTable");
1629 cdecl.add_declarator (new CCodeVariableDeclarator ("_" + sym.get_lower_case_cprefix () + "dbus_path_vtable", vtable));
1630 cdecl.modifiers = CCodeModifiers.STATIC;
1631 cfile.add_constant_declaration (cdecl);
1633 return new CCodeIdentifier ("_" + sym.get_lower_case_cprefix () + "dbus_path_vtable");
1636 public override void visit_method_call (MethodCall expr) {
1637 var mtype = expr.call.value_type as MethodType;
1638 if (mtype == null || (mtype.method_symbol.get_cname () != "dbus_connection_register_g_object" &&
1639 mtype.method_symbol.get_cname () != "dbus_g_connection_register_g_object")) {
1640 base.visit_method_call (expr);
1641 return;
1644 add_dbus_helpers ();
1646 var ma = (MemberAccess) expr.call;
1648 var raw_conn = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection"));
1649 raw_conn.add_argument (get_cvalue (ma.inner));
1651 var args_it = expr.get_argument_list ().iterator ();
1652 args_it.next ();
1653 var path_arg = args_it.get ();
1654 args_it.next ();
1655 var obj_arg = args_it.get ();
1657 var cregister = new CCodeFunctionCall (new CCodeIdentifier ("_vala_dbus_register_object"));
1658 if (mtype.method_symbol.get_cname () == "dbus_g_connection_register_g_object") {
1659 cregister.add_argument (raw_conn);
1660 } else {
1661 cregister.add_argument (get_cvalue (ma.inner));
1663 cregister.add_argument (get_cvalue (path_arg));
1664 cregister.add_argument (get_cvalue (obj_arg));
1666 ccode.add_expression (cregister);
1669 bool type_implements_dbus_interface (ObjectTypeSymbol sym) {
1670 var dbus = sym.get_attribute ("DBus");
1671 if (dbus != null) {
1672 return true;
1675 var cl = sym as Class;
1676 if (cl != null) {
1677 foreach (DataType base_type in cl.get_base_types ()) {
1678 var base_obj_type = base_type as ObjectType;
1679 if (type_implements_dbus_interface (base_obj_type.type_symbol)) {
1680 return true;
1685 return false;
1688 public override void register_dbus_info (CCodeBlock block, ObjectTypeSymbol sym) {
1689 if (!type_implements_dbus_interface (sym)) {
1690 return;
1693 base.register_dbus_info (block, sym);
1695 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1696 quark.add_argument (new CCodeConstant ("\"DBusObjectVTable\""));
1698 var set_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_set_qdata"));
1699 set_qdata.add_argument (new CCodeIdentifier ("%s_type_id".printf (sym.get_lower_case_cname (null))));
1700 set_qdata.add_argument (quark);
1701 set_qdata.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_vtable (new ObjectType (sym))), "void*"));
1703 block.add_statement (new CCodeExpressionStatement (set_qdata));