6e026b43b0225c61a888ef2c7b520949bf541dc6
[roobuilder] / src / codegen / valagdbusservermodule.vala
1 /* valagdbusservermodule.vala
2  *
3  * Copyright (C) 2010-2011  Jürg Billeter
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
18  *
19  * Author:
20  *      Jürg Billeter <j@bitron.ch>
21  */
22
23 public class Vala.GDBusServerModule : GDBusClientModule {
24         string generate_dbus_wrapper (Method m, ObjectTypeSymbol sym, bool ready = false) {
25                 string wrapper_name = "_dbus_%s".printf (get_ccode_name (m));
26                 bool need_goto_label = ready;
27
28                 if (m.base_method != null) {
29                         m = m.base_method;
30                 } else if (m.base_interface_method != null) {
31                         m = m.base_interface_method;
32                 }
33
34                 if (ready) {
35                         // async ready function
36                         wrapper_name += "_ready";
37                 }
38
39                 var function = new CCodeFunction (wrapper_name);
40                 function.modifiers = CCodeModifiers.STATIC;
41
42                 if (!ready) {
43                         function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*"));
44                         function.add_parameter (new CCodeParameter ("_parameters_", "GVariant*"));
45                         function.add_parameter (new CCodeParameter ("invocation", "GDBusMethodInvocation*"));
46                 } else {
47                         function.add_parameter (new CCodeParameter ("source_object", "GObject *"));
48                         function.add_parameter (new CCodeParameter ("_res_", "GAsyncResult *"));
49                         function.add_parameter (new CCodeParameter ("_user_data_", "gpointer"));
50                 }
51
52                 push_function (function);
53
54                 CCodeIdentifier ready_data_expr = m.coroutine ? new CCodeIdentifier ("_ready_data") : null;
55                 string ready_data_struct_name = Symbol.lower_case_to_camel_case (get_ccode_name (m)) + "ReadyData";
56
57                 if (ready) {
58                         ccode.add_declaration (ready_data_struct_name + "*", new CCodeVariableDeclarator ("_ready_data", new CCodeIdentifier ("_user_data_")));
59                         ccode.add_declaration ("GDBusMethodInvocation*", new CCodeVariableDeclarator ("invocation", new CCodeMemberAccess.pointer (ready_data_expr, "_invocation_")));
60                 }
61
62                 var connection = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_get_connection"));
63                 connection.add_argument (new CCodeIdentifier ("invocation"));
64
65                 bool no_reply = is_dbus_no_reply (m);
66                 bool uses_fd = dbus_method_uses_file_descriptor (m);
67                 if (uses_fd) {
68                         cfile.add_include ("gio/gunixfdlist.h");
69                         ccode.add_declaration ("GUnixFDList*", new CCodeVariableDeclarator ("_fd_list"));
70                 }
71
72                 bool uses_error = false;
73
74                 if (!m.coroutine || ready) {
75                         ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("error", new CCodeConstant ("NULL")));
76                         uses_error = true;
77                 }
78
79                 if (!ready) {
80                         ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_arguments_iter"));
81
82                         var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init"));
83                         iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_iter")));
84                         iter_init.add_argument (new CCodeIdentifier ("_parameters_"));
85                         ccode.add_expression (iter_init);
86                 }
87
88                 CCodeFunctionCall ccall;
89                 if (!ready) {
90                         ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (m)));
91                         ccall.add_argument (new CCodeIdentifier ("self"));
92                 } else {
93                         ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_finish_name (m)));
94                         ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("source_object"), get_ccode_name (sym) + "*"));
95                         ccall.add_argument (new CCodeIdentifier ("_res_"));
96                 }
97
98                 if (!ready) {
99                         if (uses_fd) {
100                                 ccode.add_declaration ("gint", new CCodeVariableDeclarator.zero ("_fd_index", new CCodeConstant ("0")));
101                                 ccode.add_declaration ("gint", new CCodeVariableDeclarator ("_fd"));
102                         }
103
104                         CCodeStruct? ready_data_struct = null;
105
106                         if (m.coroutine) {
107                                 ready_data_struct = new CCodeStruct ("_" + ready_data_struct_name);
108                                 ready_data_struct.add_field ("GDBusMethodInvocation*", "_invocation_");
109                                 append_struct (ready_data_struct);
110
111                                 var ready_data_alloc = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_new0"));
112                                 ready_data_alloc.add_argument (new CCodeIdentifier (ready_data_struct_name));
113
114                                 ccode.add_declaration (ready_data_struct_name + "*", new CCodeVariableDeclarator ("_ready_data"));
115                                 ccode.add_assignment (ready_data_expr, ready_data_alloc);
116
117                                 ccode.add_assignment (new CCodeMemberAccess.pointer (ready_data_expr, "_invocation_"), new CCodeIdentifier ("invocation"));
118                         }
119
120                         foreach (Parameter param in m.get_parameters ()) {
121                                 string param_name = get_variable_cname (param.name);
122                                 if (param.direction != ParameterDirection.IN) {
123                                         continue;
124                                 }
125
126                                 if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
127                                         continue;
128                                 }
129
130                                 if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.BusName") {
131                                         // ignore BusName sender parameters
132                                         continue;
133                                 }
134
135                                 CCodeExpression param_expr;
136                                 if (ready_data_expr != null) {
137                                         param_expr = new CCodeMemberAccess.pointer (ready_data_expr, param_name);
138                                 } else {
139                                         param_expr = new CCodeIdentifier (param_name);
140                                 }
141
142                                 var owned_type = param.variable_type.copy ();
143                                 owned_type.value_owned = true;
144
145                                 if (ready_data_struct != null) {
146                                         ready_data_struct.add_field (get_ccode_name (owned_type), param_name);
147                                 } else {
148                                         ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero (param_name, default_value_for_type (param.variable_type, true)));
149                                 }
150
151                                 var array_type = param.variable_type as ArrayType;
152                                 if (array_type != null) {
153                                         var length_ctype = get_ccode_array_length_type (array_type);
154                                         for (int dim = 1; dim <= array_type.rank; dim++) {
155                                                 string length_cname = get_variable_array_length_cname (param, dim);
156
157                                                 if (ready_data_struct != null) {
158                                                         ready_data_struct.add_field (length_ctype, length_cname);
159                                                 } else {
160                                                         ccode.add_declaration (length_ctype, new CCodeVariableDeclarator.zero (length_cname, new CCodeConstant ("0")));
161                                                 }
162                                         }
163                                 }
164
165                                 var message_expr = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_get_message"));
166                                 message_expr.add_argument (new CCodeIdentifier ("invocation"));
167
168                                 bool may_fail;
169                                 receive_dbus_value (param.variable_type, message_expr, new CCodeIdentifier ("_arguments_iter"), param_expr, param, new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")), out may_fail);
170
171                                 if (may_fail) {
172                                         if (!uses_error) {
173                                                 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("error", new CCodeConstant ("NULL")));
174                                                 uses_error = true;
175                                         }
176
177                                         ccode.open_if (new CCodeIdentifier ("error"));
178
179                                         var return_error = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_take_error"));
180                                         return_error.add_argument (new CCodeIdentifier ("invocation"));
181                                         return_error.add_argument (new CCodeIdentifier ("error"));
182                                         ccode.add_expression (return_error);
183
184                                         if (need_goto_label || requires_destroy (owned_type)) {
185                                                 ccode.add_goto ("_error");
186                                                 need_goto_label = true;
187                                         } else {
188                                                 ccode.add_return ();
189                                         }
190
191                                         ccode.close ();
192                                 } else if (!need_goto_label && m.tree_can_fail && requires_destroy (owned_type)) {
193                                         need_goto_label = true;
194                                 }
195                         }
196                 }
197
198                 foreach (Parameter param in m.get_parameters ()) {
199                         string param_name = get_variable_cname (param.name);
200
201                         CCodeExpression param_expr;
202                         if (ready_data_expr != null && param.direction == ParameterDirection.IN) {
203                                 param_expr = new CCodeMemberAccess.pointer (ready_data_expr, param_name);
204                         } else {
205                                 param_expr = new CCodeIdentifier (param_name);
206                         }
207
208                         if (param.direction == ParameterDirection.IN && !ready) {
209                                 if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
210                                         ccall.add_argument (new CCodeConstant ("NULL"));
211                                         continue;
212                                 }
213
214                                 if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.BusName") {
215                                         // ignore BusName sender parameters
216                                         var sender = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_get_sender"));
217                                         sender.add_argument (new CCodeIdentifier ("invocation"));
218                                         ccall.add_argument (sender);
219                                         continue;
220                                 }
221
222                                 unowned Struct? st = param.variable_type.type_symbol as Struct;
223                                 if (st != null && !st.is_simple_type ()) {
224                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, param_expr));
225                                 } else {
226                                         ccall.add_argument (param_expr);
227                                 }
228                         } else if (param.direction == ParameterDirection.OUT && (!m.coroutine || ready)) {
229                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, param_expr));
230                         }
231
232                         var array_type = param.variable_type as ArrayType;
233                         if (array_type != null) {
234                                 for (int dim = 1; dim <= array_type.rank; dim++) {
235                                         string length_cname = get_variable_array_length_cname (param, dim);
236
237                                         CCodeExpression length_expr;
238                                         if (ready_data_expr != null && param.direction == ParameterDirection.IN)
239                                                 length_expr = new CCodeMemberAccess.pointer (ready_data_expr, length_cname);
240                                         else
241                                                 length_expr = new CCodeIdentifier (length_cname);
242
243                                         if (param.direction == ParameterDirection.IN && !ready) {
244                                                 ccall.add_argument (length_expr);
245                                         } else if (param.direction == ParameterDirection.OUT && !no_reply && (!m.coroutine || ready)) {
246                                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, length_expr));
247                                         }
248                                 }
249                         }
250                 }
251
252                 if (!m.coroutine || ready) {
253                         if (!(m.return_type is VoidType)) {
254                                 if (m.return_type.is_real_non_null_struct_type ()) {
255                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
256                                 } else {
257                                         var array_type = m.return_type as ArrayType;
258                                         if (array_type != null) {
259                                                 for (int dim = 1; dim <= array_type.rank; dim++) {
260                                                         string length_cname = get_array_length_cname ("result", dim);
261
262                                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
263                                                 }
264                                         }
265                                 }
266                         }
267                 }
268
269                 if (m.coroutine && !ready) {
270                         ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (wrapper_name + "_ready"), "GAsyncReadyCallback"));
271                         ccall.add_argument (ready_data_expr);
272                 }
273
274                 if (!m.coroutine || ready) {
275                         if (m.tree_can_fail) {
276                                 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
277                         }
278                 }
279
280                 if (!no_reply && (!m.coroutine || ready)) {
281                         if (m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ()) {
282                                 ccode.add_expression (ccall);
283                         } else {
284                                 ccode.add_assignment (new CCodeIdentifier ("result"), ccall);
285                         }
286
287                         if (m.tree_can_fail) {
288                                 ccode.open_if (new CCodeIdentifier ("error"));
289
290                                 var return_error = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_take_error"));
291                                 return_error.add_argument (new CCodeIdentifier ("invocation"));
292                                 return_error.add_argument (new CCodeIdentifier ("error"));
293                                 ccode.add_expression (return_error);
294
295                                 if (need_goto_label) {
296                                         ccode.add_goto ("_error");
297                                 } else {
298                                         ccode.add_return ();
299                                 }
300
301                                 ccode.close ();
302                         }
303
304                         ccode.add_declaration ("GDBusMessage*", new CCodeVariableDeclarator.zero ("_reply_message", new CCodeConstant ("NULL")));
305
306                         var message_expr = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_get_message"));
307                         message_expr.add_argument (new CCodeIdentifier ("invocation"));
308
309                         ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_new_method_reply"));
310                         ccall.add_argument (message_expr);
311                         ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall);
312
313                         ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator ("_reply"));
314                         ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_reply_builder"));
315
316                         var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
317                         builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_builder")));
318                         builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
319                         ccode.add_expression (builder_init);
320
321                         if (uses_fd) {
322                                 ccode.add_assignment (new CCodeIdentifier ("_fd_list"), new CCodeFunctionCall (new CCodeIdentifier ("g_unix_fd_list_new")));
323                         }
324
325                         foreach (Parameter param in m.get_parameters ()) {
326                                 if (param.direction != ParameterDirection.OUT) {
327                                         continue;
328                                 }
329
330                                 string param_name = get_variable_cname (param.name);
331                                 var owned_type = param.variable_type.copy ();
332                                 owned_type.value_owned = true;
333
334                                 ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero (param_name, default_value_for_type (param.variable_type, true)));
335
336                                 var array_type = param.variable_type as ArrayType;
337                                 if (array_type != null) {
338                                         var length_ctype = get_ccode_array_length_type (array_type);
339                                         for (int dim = 1; dim <= array_type.rank; dim++) {
340                                                 string length_cname = get_variable_array_length_cname (param, dim);
341
342                                                 ccode.add_declaration (length_ctype, new CCodeVariableDeclarator.zero (length_cname, new CCodeConstant ("0")));
343                                         }
344                                 }
345
346                                 send_dbus_value (param.variable_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier (param_name), param);
347                         }
348
349                         if (!(m.return_type is VoidType)) {
350                                 if (m.return_type.is_real_non_null_struct_type ()) {
351                                         ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator.zero ("result", default_value_for_type (m.return_type, true)));
352
353                                         send_dbus_value (m.return_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier ("result"), m);
354
355                                         if (requires_destroy (m.return_type)) {
356                                                 // keep local alive (symbol_reference is weak)
357                                                 var local = new LocalVariable (m.return_type, ".result");
358                                                 ccode.add_expression (destroy_local (local));
359                                         }
360                                 } else {
361                                         ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator ("result"));
362
363                                         var array_type = m.return_type as ArrayType;
364                                         if (array_type != null) {
365                                                 var length_ctype = get_ccode_array_length_type (array_type);
366                                                 for (int dim = 1; dim <= array_type.rank; dim++) {
367                                                         string length_cname = get_array_length_cname ("result", dim);
368
369                                                         ccode.add_declaration (length_ctype, new CCodeVariableDeclarator.zero (length_cname, new CCodeConstant ("0")));
370                                                 }
371                                         }
372
373                                         send_dbus_value (m.return_type, new CCodeIdentifier ("_reply_builder"), new CCodeIdentifier ("result"), m);
374
375                                         if (requires_destroy (m.return_type)) {
376                                                 // keep local alive (symbol_reference is weak)
377                                                 var local = new LocalVariable (m.return_type, ".result");
378                                                 ccode.add_expression (destroy_local (local));
379                                         }
380                                 }
381                         }
382
383                         var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
384                         builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_builder")));
385                         ccode.add_assignment (new CCodeIdentifier ("_reply"), builder_end);
386
387                         var set_body = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_body"));
388                         set_body.add_argument (new CCodeIdentifier ("_reply_message"));
389                         set_body.add_argument (new CCodeIdentifier ("_reply"));
390                         ccode.add_expression (set_body);
391
392                         if (uses_fd) {
393                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_unix_fd_list"));
394                                 ccall.add_argument (new CCodeIdentifier ("_reply_message"));
395                                 ccall.add_argument (new CCodeIdentifier ("_fd_list"));
396                                 ccode.add_expression (ccall);
397
398                                 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
399                                 ccall.add_argument (new CCodeIdentifier ("_fd_list"));
400                                 ccode.add_expression (ccall);
401                         }
402                 } else {
403                         ccode.add_expression (ccall);
404                 }
405
406                 if (!no_reply && (!m.coroutine || ready)) {
407                         var return_value = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message"));
408                         return_value.add_argument (connection);
409                         return_value.add_argument (new CCodeIdentifier ("_reply_message"));
410                         return_value.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE"));
411                         return_value.add_argument (new CCodeConstant ("NULL"));
412                         return_value.add_argument (new CCodeConstant ("NULL"));
413                         ccode.add_expression (return_value);
414
415                         // free invocation like g_dbus_method_invocation_return_*
416                         var unref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
417                         unref_call.add_argument (new CCodeIdentifier ("invocation"));
418                         ccode.add_expression (unref_call);
419
420                         unref_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
421                         unref_call.add_argument (new CCodeIdentifier ("_reply_message"));
422                         ccode.add_expression (unref_call);
423                 }
424
425                 if (need_goto_label) {
426                         ccode.add_label ("_error");
427                 }
428
429                 foreach (Parameter param in m.get_parameters ()) {
430                         if ((param.direction == ParameterDirection.IN && (ready_data_expr == null || ready)) ||
431                             (param.direction == ParameterDirection.OUT && !no_reply && (!m.coroutine || ready))) {
432                                 if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.Cancellable") {
433                                         continue;
434                                 }
435
436                                 if (param.variable_type is ObjectType && param.variable_type.type_symbol.get_full_name () == "GLib.BusName") {
437                                         // ignore BusName sender parameters
438                                         continue;
439                                 }
440
441                                 var owned_type = param.variable_type.copy ();
442                                 owned_type.value_owned = true;
443
444                                 if (requires_destroy (owned_type)) {
445                                         if (ready_data_expr != null && param.direction == ParameterDirection.IN) {
446                                                 var target = new GLibValue (owned_type, new CCodeMemberAccess.pointer (ready_data_expr, param.name), true);
447
448                                                 var array_type = owned_type as ArrayType;
449                                                 if (array_type != null) {
450                                                         for (int dim = 1; dim <= array_type.rank; dim++) {
451                                                                 string length_cname = get_variable_array_length_cname (param, dim);
452
453                                                                 target.append_array_length_cvalue (new CCodeMemberAccess.pointer (ready_data_expr, length_cname));
454                                                         }
455                                                 }
456
457                                                 ccode.add_expression (destroy_value (target));
458                                         } else {
459                                                 // keep local alive (symbol_reference is weak)
460                                                 var local = new LocalVariable (owned_type, get_variable_cname (param.name));
461                                                 ccode.add_expression (destroy_local (local));
462                                         }
463                                 }
464                         }
465                 }
466
467                 if (ready) {
468                         var freecall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
469                         freecall.add_argument (new CCodeIdentifier (ready_data_struct_name));
470                         freecall.add_argument (ready_data_expr);
471                         ccode.add_expression (freecall);
472                 } else if (need_goto_label) {
473                         ccode.add_statement (new CCodeEmptyStatement ());
474                 }
475
476                 pop_function ();
477
478                 cfile.add_function_declaration (function);
479                 cfile.add_function (function);
480
481                 if (m.coroutine && !ready) {
482                         // generate ready function
483                         generate_dbus_wrapper (m, sym, true);
484                 }
485
486                 return wrapper_name;
487         }
488
489         string generate_dbus_signal_wrapper (Signal sig, ObjectTypeSymbol sym, string dbus_iface_name) {
490                 string wrapper_name = "_dbus_%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_lower_case_name (sig));
491
492                 var function = new CCodeFunction (wrapper_name, "void");
493                 function.modifiers = CCodeModifiers.STATIC;
494
495                 function.add_parameter (new CCodeParameter ("_sender", "GObject*"));
496
497                 foreach (var param in sig.get_parameters ()) {
498                         // ensure ccodenode of parameter is set
499                         var cparam = generate_parameter (param, cfile, new HashMap<int,CCodeParameter> (), null);
500
501                         function.add_parameter (cparam);
502                         if (param.variable_type is ArrayType) {
503                                 var array_type = (ArrayType) param.variable_type;
504                                 var length_ctype = get_ccode_array_length_type (array_type);
505                                 for (int dim = 1; dim <= array_type.rank; dim++) {
506                                         function.add_parameter (new CCodeParameter (get_variable_array_length_cname (param, dim), length_ctype));
507                                 }
508                         }
509                 }
510
511                 function.add_parameter (new CCodeParameter ("_data", "gpointer*"));
512
513                 push_function (function);
514
515                 ccode.add_declaration ("GDBusConnection *", new CCodeVariableDeclarator ("_connection", new CCodeElementAccess (new CCodeIdentifier ("_data"), new CCodeConstant ("1"))));
516                 ccode.add_declaration ("const gchar *", new CCodeVariableDeclarator ("_path", new CCodeElementAccess (new CCodeIdentifier ("_data"), new CCodeConstant ("2"))));
517                 ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
518                 ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
519
520                 var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
521                 builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
522                 builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
523                 ccode.add_expression (builder_init);
524
525                 foreach (Parameter param in sig.get_parameters ()) {
526                         string param_name = get_variable_cname (param.name);
527                         CCodeExpression expr = new CCodeIdentifier (param_name);
528                         if (param.variable_type.is_real_struct_type ()) {
529                                 expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr);
530                         }
531                         write_expression (param.variable_type, new CCodeIdentifier ("_arguments_builder"), expr, param);
532                 }
533
534                 var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
535                 builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_builder")));
536                 ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
537
538                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_emit_signal"));
539                 ccall.add_argument (new CCodeIdentifier ("_connection"));
540                 ccall.add_argument (new CCodeConstant ("NULL"));
541                 ccall.add_argument (new CCodeIdentifier ("_path"));
542                 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name)));
543                 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig))));
544                 ccall.add_argument (new CCodeIdentifier ("_arguments"));
545                 ccall.add_argument (new CCodeConstant ("NULL"));
546                 ccode.add_expression (ccall);
547
548                 pop_function ();
549
550                 cfile.add_function_declaration (function);
551                 cfile.add_function (function);
552
553                 return wrapper_name;
554         }
555
556         string generate_dbus_property_get_wrapper (Property prop, ObjectTypeSymbol sym) {
557                 string wrapper_name = "_dbus_%s".printf (get_ccode_name (prop.get_accessor));
558
559                 var function = new CCodeFunction (wrapper_name, "GVariant*");
560                 function.modifiers = CCodeModifiers.STATIC;
561                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*"));
562
563                 push_function (function);
564
565                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (prop.get_accessor)));
566                 ccall.add_argument (new CCodeIdentifier ("self"));
567
568                 if (prop.get_accessor.value_type.is_real_non_null_struct_type ()) {
569                         ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator.zero ("result", default_value_for_type (prop.get_accessor.value_type, true)));
570                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
571
572                         ccode.add_expression (ccall);
573                 } else {
574                         ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator ("result"));
575                         ccode.add_assignment (new CCodeIdentifier ("result"), ccall);
576
577                         var array_type = prop.get_accessor.value_type as ArrayType;
578                         if (array_type != null) {
579                                 var length_ctype = get_ccode_array_length_type (array_type);
580                                 for (int dim = 1; dim <= array_type.rank; dim++) {
581                                         string length_cname = get_array_length_cname ("result", dim);
582
583                                         ccode.add_declaration (length_ctype, new CCodeVariableDeclarator.zero (length_cname, new CCodeConstant ("0")));
584                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (length_cname)));
585                                 }
586                         }
587                 }
588
589                 ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator ("_reply"));
590
591                 if (get_dbus_signature (prop) != null) {
592                         // raw GVariant
593                         ccode.add_assignment (new CCodeIdentifier ("_reply"), new CCodeIdentifier("result"));
594                 } else {
595                         var reply_expr = serialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("result"));
596
597                         ccode.add_assignment (new CCodeIdentifier ("_reply"), reply_expr);
598
599                         if (requires_destroy (prop.get_accessor.value_type)) {
600                                 // keep local alive (symbol_reference is weak)
601                                 var local = new LocalVariable (prop.get_accessor.value_type, ".result");
602                                 ccode.add_expression (destroy_local (local));
603                         }
604                 }
605
606                 ccode.add_return (new CCodeIdentifier ("_reply"));
607
608                 pop_function ();
609
610                 cfile.add_function_declaration (function);
611                 cfile.add_function (function);
612
613                 return wrapper_name;
614         }
615
616         string generate_dbus_property_set_wrapper (Property prop, ObjectTypeSymbol sym) {
617                 string wrapper_name = "_dbus_%s".printf (get_ccode_name (prop.set_accessor));
618
619                 var function = new CCodeFunction (wrapper_name);
620                 function.modifiers = CCodeModifiers.STATIC;
621                 function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*"));
622                 function.add_parameter (new CCodeParameter ("_value", "GVariant*"));
623
624                 push_function (function);
625
626                 var ccall = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_name (prop.set_accessor)));
627                 ccall.add_argument (new CCodeIdentifier ("self"));
628
629                 var owned_type = prop.property_type.copy ();
630                 owned_type.value_owned = true;
631
632                 ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero ("value", default_value_for_type (prop.property_type, true)));
633
634                 unowned Struct? st = prop.property_type.type_symbol as Struct;
635                 if (st != null && !st.is_simple_type ()) {
636                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
637                 } else {
638                         ccall.add_argument (new CCodeIdentifier ("value"));
639
640                         var array_type = prop.property_type as ArrayType;
641                         if (array_type != null) {
642                                 var length_ctype = get_ccode_array_length_type (array_type);
643                                 for (int dim = 1; dim <= array_type.rank; dim++) {
644                                         ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (get_array_length_cname ("value", dim)));
645                                         ccall.add_argument (new CCodeIdentifier (get_array_length_cname ("value", dim)));
646                                 }
647                         }
648                 }
649
650                 var target = new CCodeIdentifier ("value");
651
652                 if (get_dbus_signature (prop) != null) {
653                         ccode.add_assignment (target, new CCodeIdentifier("_value"));
654                         ccode.add_expression (ccall);
655                 } else {
656                         var expr = deserialize_expression (prop.property_type, new CCodeIdentifier ("_value"), target);
657                         ccode.add_assignment (target, expr);
658                         ccode.add_expression (ccall);
659
660                         if (requires_destroy (owned_type)) {
661                                 // keep local alive (symbol_reference is weak)
662                                 var local = new LocalVariable (owned_type, "value");
663                                 ccode.add_expression (destroy_local (local));
664                         }
665                 }
666
667                 pop_function ();
668
669                 cfile.add_function_declaration (function);
670                 cfile.add_function (function);
671
672                 return wrapper_name;
673         }
674
675         void handle_signals (ObjectTypeSymbol sym, bool connect) {
676                 string dbus_iface_name = get_dbus_name (sym);
677                 if (dbus_iface_name == null) {
678                         return;
679                 }
680
681                 foreach (Signal sig in sym.get_signals ()) {
682                         if (sig.access != SymbolAccessibility.PUBLIC) {
683                                 continue;
684                         }
685                         if (!is_dbus_visible (sig)) {
686                                 continue;
687                         }
688
689                         if (connect) {
690                                 var connect_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_connect"));
691                                 connect_call.add_argument (new CCodeIdentifier ("object"));
692                                 connect_call.add_argument (get_signal_canonical_constant (sig));
693                                 connect_call.add_argument (new CCodeCastExpression (new CCodeIdentifier (generate_dbus_signal_wrapper (sig, sym, dbus_iface_name)), "GCallback"));
694                                 connect_call.add_argument (new CCodeIdentifier ("data"));
695                                 ccode.add_expression (connect_call);
696                         } else {
697                                 // disconnect the signals
698                                 var disconnect_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_handlers_disconnect_by_func"));
699                                 disconnect_call.add_argument (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0")));
700                                 disconnect_call.add_argument (new CCodeIdentifier ("_dbus_%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_lower_case_name (sig))));
701                                 disconnect_call.add_argument (new CCodeIdentifier ("data"));
702                                 ccode.add_expression (disconnect_call);
703                         }
704                 }
705         }
706
707         void generate_interface_method_call_function (ObjectTypeSymbol sym) {
708                 var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "dbus_interface_method_call", "void");
709                 cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
710                 cfunc.add_parameter (new CCodeParameter ("sender", "const gchar*"));
711                 cfunc.add_parameter (new CCodeParameter ("object_path", "const gchar*"));
712                 cfunc.add_parameter (new CCodeParameter ("interface_name", "const gchar*"));
713                 cfunc.add_parameter (new CCodeParameter ("method_name", "const gchar*"));
714                 cfunc.add_parameter (new CCodeParameter ("parameters", "GVariant*"));
715                 cfunc.add_parameter (new CCodeParameter ("invocation", "GDBusMethodInvocation*"));
716                 cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
717
718                 cfunc.modifiers |= CCodeModifiers.STATIC;
719
720                 push_function (cfunc);
721
722                 ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data")));
723                 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
724
725                 bool first = true;
726
727                 foreach (Method m in sym.get_methods ()) {
728                         if (m is CreationMethod || m.binding != MemberBinding.INSTANCE
729                             || m.overrides || m.access != SymbolAccessibility.PUBLIC) {
730                                 continue;
731                         }
732                         if (!is_dbus_visible (m)) {
733                                 continue;
734                         }
735
736                         cfile.add_include ("string.h");
737
738                         var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
739                         ccheck.add_argument (new CCodeIdentifier ("method_name"));
740                         ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (m))));
741
742                         if (first) {
743                                 ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")));
744                                 first = false;
745                         } else {
746                                 ccode.else_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")));
747                         }
748
749                         var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_wrapper (m, sym)));
750                         ccall.add_argument (new CCodeIdentifier ("object"));
751                         ccall.add_argument (new CCodeIdentifier ("parameters"));
752                         ccall.add_argument (new CCodeIdentifier ("invocation"));
753                         ccode.add_expression (ccall);
754                 }
755
756                 if (!first) {
757                         ccode.add_else ();
758                 }
759
760                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
761                 ccall.add_argument (new CCodeIdentifier ("invocation"));
762                 ccode.add_expression (ccall);
763
764                 if (!first) {
765                         ccode.close ();
766                 }
767
768                 pop_function ();
769
770                 cfile.add_function_declaration (cfunc);
771                 cfile.add_function (cfunc);
772         }
773
774         void generate_interface_get_property_function (ObjectTypeSymbol sym) {
775                 var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "dbus_interface_get_property", "GVariant*");
776                 cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
777                 cfunc.add_parameter (new CCodeParameter ("sender", "const gchar*"));
778                 cfunc.add_parameter (new CCodeParameter ("object_path", "const gchar*"));
779                 cfunc.add_parameter (new CCodeParameter ("interface_name", "const gchar*"));
780                 cfunc.add_parameter (new CCodeParameter ("property_name", "const gchar*"));
781                 cfunc.add_parameter (new CCodeParameter ("error", "GError**"));
782                 cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
783
784                 cfunc.modifiers |= CCodeModifiers.STATIC;
785
786                 cfile.add_function_declaration (cfunc);
787
788                 push_function (cfunc);
789
790                 ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data")));
791
792                 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
793
794                 bool firstif = true;
795
796                 foreach (Property prop in sym.get_properties ()) {
797                         if (prop.binding != MemberBinding.INSTANCE
798                             || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
799                                 continue;
800                         }
801                         if (!is_dbus_visible (prop)) {
802                                 continue;
803                         }
804                         if (prop.get_accessor == null) {
805                                 continue;
806                         }
807
808                         cfile.add_include ("string.h");
809
810                         var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
811                         ccheck.add_argument (new CCodeIdentifier ("property_name"));
812                         ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
813
814                         var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0"));
815                         if (firstif) {
816                                 ccode.open_if (cond);
817                                 firstif = false;
818                         } else {
819                                 ccode.else_if (cond);
820                         }
821
822                         var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_property_get_wrapper (prop, sym)));
823                         ccall.add_argument (new CCodeIdentifier ("object"));
824
825                         ccode.add_return (ccall);
826                 }
827                 if (!firstif) {
828                         ccode.close ();
829                 }
830
831                 ccode.add_return (new CCodeConstant ("NULL"));
832
833                 pop_function ();
834                 cfile.add_function (cfunc);
835         }
836
837         void generate_interface_set_property_function (ObjectTypeSymbol sym) {
838                 var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "dbus_interface_set_property", "gboolean");
839                 cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
840                 cfunc.add_parameter (new CCodeParameter ("sender", "const gchar*"));
841                 cfunc.add_parameter (new CCodeParameter ("object_path", "const gchar*"));
842                 cfunc.add_parameter (new CCodeParameter ("interface_name", "const gchar*"));
843                 cfunc.add_parameter (new CCodeParameter ("property_name", "const gchar*"));
844                 cfunc.add_parameter (new CCodeParameter ("value", "GVariant*"));
845                 cfunc.add_parameter (new CCodeParameter ("error", "GError**"));
846                 cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
847
848                 cfunc.modifiers |= CCodeModifiers.STATIC;
849
850                 cfile.add_function_declaration (cfunc);
851
852                 push_function (cfunc);
853
854                 ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data")));
855
856                 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("object", new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0"))));
857
858                 bool firstif = true;
859
860                 foreach (Property prop in sym.get_properties ()) {
861                         if (prop.binding != MemberBinding.INSTANCE
862                             || prop.overrides || prop.access != SymbolAccessibility.PUBLIC) {
863                                 continue;
864                         }
865                         if (!is_dbus_visible (prop)) {
866                                 continue;
867                         }
868                         if (prop.set_accessor == null) {
869                                 continue;
870                         }
871
872                         cfile.add_include ("string.h");
873
874                         var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
875                         ccheck.add_argument (new CCodeIdentifier ("property_name"));
876                         ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop))));
877
878                         var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0"));
879                         if (firstif) {
880                                 ccode.open_if (cond);
881                                 firstif = false;
882                         } else {
883                                 ccode.else_if (cond);
884                         }
885
886                         var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_property_set_wrapper (prop, sym)));
887                         ccall.add_argument (new CCodeIdentifier ("object"));
888                         ccall.add_argument (new CCodeIdentifier ("value"));
889
890                         ccode.add_expression (ccall);
891                         ccode.add_return (new CCodeConstant ("TRUE"));
892                 }
893                 if (!firstif) {
894                         ccode.close ();
895                 }
896                 ccode.add_return (new CCodeConstant ("FALSE"));
897
898                 pop_function ();
899                 cfile.add_function (cfunc);
900         }
901
902         CCodeExpression get_interface_vtable (ObjectTypeSymbol sym) {
903                 var vtable = new CCodeInitializerList ();
904                 vtable.append (new CCodeIdentifier (get_ccode_lower_case_prefix (sym) + "dbus_interface_method_call"));
905                 vtable.append (new CCodeIdentifier (get_ccode_lower_case_prefix (sym) + "dbus_interface_get_property"));
906                 vtable.append (new CCodeIdentifier (get_ccode_lower_case_prefix (sym) + "dbus_interface_set_property"));
907
908                 generate_interface_method_call_function (sym);
909                 generate_interface_get_property_function (sym);
910                 generate_interface_set_property_function (sym);
911
912                 var cdecl = new CCodeDeclaration ("const GDBusInterfaceVTable");
913                 cdecl.add_declarator (new CCodeVariableDeclarator ("_" + get_ccode_lower_case_prefix (sym) + "dbus_interface_vtable", vtable));
914                 cdecl.modifiers = CCodeModifiers.STATIC;
915                 cfile.add_constant_declaration (cdecl);
916
917                 return new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_interface_vtable");
918         }
919
920         string generate_register_object_function () {
921                 string register_object_func = "_vala_g_dbus_connection_register_object";
922
923                 if (!add_wrapper (register_object_func)) {
924                         return register_object_func;
925                 }
926
927                 cfile.add_include ("gio/gio.h");
928
929                 var function = new CCodeFunction (register_object_func, "guint");
930                 function.modifiers = CCodeModifiers.STATIC;
931
932                 function.add_parameter (new CCodeParameter ("type", "GType"));
933                 function.add_parameter (new CCodeParameter ("object", "void*"));
934                 function.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
935                 function.add_parameter (new CCodeParameter ("path", "const gchar*"));
936                 function.add_parameter (new CCodeParameter ("error", "GError**"));
937
938                 push_function (function);
939
940                 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
941                 quark.add_argument (new CCodeConstant ("\"vala-dbus-register-object\""));
942
943                 var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
944                 get_qdata.add_argument (new CCodeIdentifier ("type"));
945                 get_qdata.add_argument (quark);
946
947                 ccode.add_declaration ("void", new CCodeVariableDeclarator ("*func"));
948                 ccode.add_assignment (new CCodeIdentifier ("func"), get_qdata);
949
950                 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("func")));
951                 // no D-Bus interface
952                 // return error
953
954                 var set_error = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error_literal"));
955                 set_error.add_argument (new CCodeIdentifier ("error"));
956                 set_error.add_argument (new CCodeIdentifier ("G_IO_ERROR"));
957                 set_error.add_argument (new CCodeIdentifier ("G_IO_ERROR_FAILED"));
958                 set_error.add_argument (new CCodeConstant ("\"The specified type does not support D-Bus registration\""));
959                 ccode.add_expression (set_error);
960
961                 ccode.add_return (new CCodeConstant ("0"));
962
963                 ccode.close ();
964
965                 var register_object = new CCodeCastExpression (new CCodeIdentifier ("func"), "guint (*) (void *, GDBusConnection *, const gchar *, GError **)");
966
967                 var ccall = new CCodeFunctionCall (register_object);
968                 ccall.add_argument (new CCodeIdentifier ("object"));
969                 ccall.add_argument (new CCodeIdentifier ("connection"));
970                 ccall.add_argument (new CCodeIdentifier ("path"));
971                 ccall.add_argument (new CCodeIdentifier ("error"));
972
973                 ccode.add_return (ccall);
974
975                 pop_function ();
976
977                 cfile.add_function_declaration (function);
978                 cfile.add_function (function);
979
980                 return register_object_func;
981         }
982
983         public override void visit_method_call (MethodCall expr) {
984                 var mtype = expr.call.value_type as MethodType;
985                 if (mtype == null || get_ccode_name (mtype.method_symbol) != "g_dbus_connection_register_object") {
986                         base.visit_method_call (expr);
987                         return;
988                 }
989
990                 var ma = (MemberAccess) expr.call;
991                 var type_arg = ma.get_type_arguments ().get (0);
992
993                 CCodeFunctionCall cregister;
994
995                 var object_type = type_arg as ObjectType;
996                 if (object_type != null) {
997                         if (get_dbus_name (object_type.type_symbol) == null) {
998                                 Report.error (expr.source_reference, "DBusConnection.register_object requires type argument with [DBus (name = ...)] attribute");
999                                 return;
1000                         }
1001
1002                         cregister = new CCodeFunctionCall (new CCodeIdentifier ("%sregister_object".printf (get_ccode_lower_case_prefix (object_type.type_symbol))));
1003                 } else {
1004                         // use runtime type information for generic methods
1005                         cregister = new CCodeFunctionCall (new CCodeIdentifier (generate_register_object_function ()));
1006                         cregister.add_argument (get_type_id_expression (type_arg));
1007                 }
1008
1009                 var args = expr.get_argument_list ();
1010                 var path_arg = args[0];
1011                 var obj_arg = args[1];
1012
1013                 // method can fail
1014                 current_method_inner_error = true;
1015
1016                 cregister.add_argument (get_cvalue (obj_arg));
1017                 cregister.add_argument (get_cvalue (ma.inner));
1018                 cregister.add_argument (get_cvalue (path_arg));
1019                 cregister.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_inner_error_cexpression ()));
1020
1021                 if (expr.parent_node is ExpressionStatement) {
1022                         ccode.add_expression (cregister);
1023                 } else {
1024                         var temp_var = get_temp_variable (expr.value_type, expr.value_type.value_owned);
1025                         var temp_ref = get_variable_cexpression (temp_var.name);
1026
1027                         emit_temp_var (temp_var);
1028
1029                         ccode.add_assignment (temp_ref, cregister);
1030                         set_cvalue (expr, temp_ref);
1031                 }
1032         }
1033
1034         public override void generate_class_declaration (Class cl, CCodeFile decl_space) {
1035                 base.generate_class_declaration (cl, decl_space);
1036
1037                 generate_object_type_symbol_declaration (cl, decl_space);
1038         }
1039
1040         public override void generate_interface_declaration (Interface iface, CCodeFile decl_space) {
1041                 base.generate_interface_declaration (iface, decl_space);
1042
1043                 generate_object_type_symbol_declaration (iface, decl_space);
1044         }
1045
1046         public override void visit_class (Class cl) {
1047                 base.visit_class (cl);
1048
1049                 visit_object_type_symbol (cl);
1050         }
1051
1052         public override void visit_interface (Interface iface) {
1053                 base.visit_interface (iface);
1054
1055                 visit_object_type_symbol (iface);
1056         }
1057
1058         void generate_object_type_symbol_declaration (ObjectTypeSymbol sym, CCodeFile decl_space) {
1059                 string dbus_iface_name = get_dbus_name (sym);
1060                 if (dbus_iface_name == null) {
1061                         return;
1062                 }
1063
1064                 string register_object_name = "%sregister_object".printf (get_ccode_lower_case_prefix (sym));
1065
1066                 if (add_symbol_declaration (decl_space, sym, register_object_name)) {
1067                         return;
1068                 }
1069
1070                 decl_space.add_include ("gio/gio.h");
1071
1072                 // declare register_object function
1073                 var cfunc = new CCodeFunction (register_object_name, "guint");
1074                 cfunc.add_parameter (new CCodeParameter ("object", "void*"));
1075                 cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
1076                 cfunc.add_parameter (new CCodeParameter ("path", "const gchar*"));
1077                 cfunc.add_parameter (new CCodeParameter ("error", "GError**"));
1078                 if (sym.is_private_symbol ()) {
1079                         cfunc.modifiers |= CCodeModifiers.STATIC;
1080                 } else if (context.hide_internal && sym.is_internal_symbol ()) {
1081                         cfunc.modifiers |= CCodeModifiers.INTERNAL;
1082                 } else {
1083                         cfunc.modifiers |= CCodeModifiers.EXTERN;
1084                         requires_vala_extern = true;
1085                 }
1086                 decl_space.add_function_declaration (cfunc);
1087         }
1088
1089         void visit_object_type_symbol (ObjectTypeSymbol sym) {
1090                 // only support registering a single D-Bus interface at a time (unlike old D-Bus support)
1091                 // however, register_object can be invoked multiple times for the same object path with different interfaces
1092                 string dbus_iface_name = get_dbus_name (sym);
1093                 if (dbus_iface_name == null) {
1094                         return;
1095                 }
1096
1097                 cfile.add_include ("gio/gio.h");
1098
1099                 var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "register_object", "guint");
1100                 cfunc.add_parameter (new CCodeParameter ("object", "gpointer"));
1101                 cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
1102                 cfunc.add_parameter (new CCodeParameter ("path", "const gchar*"));
1103                 cfunc.add_parameter (new CCodeParameter ("error", "GError**"));
1104                 if (sym.is_private_symbol ()) {
1105                         cfunc.modifiers |= CCodeModifiers.STATIC;
1106                 } else if (context.hide_internal && sym.is_internal_symbol ()) {
1107                         cfunc.modifiers |= CCodeModifiers.INTERNAL;
1108                 }
1109
1110                 push_function (cfunc);
1111
1112                 ccode.add_declaration ("guint", new CCodeVariableDeclarator ("result"));
1113
1114
1115                 // data consists of 3 pointers: object, connection, path
1116                 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("*data"));
1117
1118                 var alloc_data = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
1119                 alloc_data.add_argument (new CCodeIdentifier ("gpointer"));
1120                 alloc_data.add_argument (new CCodeConstant ("3"));
1121                 ccode.add_assignment (new CCodeIdentifier ("data"), alloc_data);
1122
1123                 var ref_function = get_ccode_ref_function (sym);
1124                 if (sym is Interface && ref_function == null) {
1125                         Report.error (sym.source_reference, "missing class prerequisite for interface `%s', add GLib.Object to interface declaration if unsure", sym.get_full_name ());
1126                         return;
1127                 }
1128
1129                 var ref_object = new CCodeFunctionCall (new CCodeIdentifier (ref_function));
1130                 ref_object.add_argument (new CCodeIdentifier ("object"));
1131                 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0")), ref_object);
1132
1133                 ref_object = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
1134                 ref_object.add_argument (new CCodeIdentifier ("connection"));
1135                 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("1")), ref_object);
1136
1137                 var dup_path = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup"));
1138                 dup_path.add_argument (new CCodeIdentifier ("path"));
1139                 ccode.add_assignment (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("2")), dup_path);
1140
1141
1142                 var cregister = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_register_object"));
1143                 cregister.add_argument (new CCodeIdentifier ("connection"));
1144                 cregister.add_argument (new CCodeIdentifier ("path"));
1145
1146                 cregister.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_interface_info (sym)), "GDBusInterfaceInfo *"));
1147                 cregister.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_interface_vtable (sym)));
1148
1149                 cregister.add_argument (new CCodeIdentifier ("data"));
1150                 cregister.add_argument (new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "unregister_object"));
1151                 cregister.add_argument (new CCodeIdentifier ("error"));
1152
1153                 ccode.add_assignment (new CCodeIdentifier ("result"), cregister);
1154
1155                 ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("result")));
1156                 ccode.add_return (new CCodeConstant ("0"));
1157                 ccode.close ();
1158
1159                 handle_signals (sym, true);
1160
1161                 ccode.add_return (new CCodeIdentifier ("result"));
1162
1163                 pop_function ();
1164                 cfile.add_function (cfunc);
1165
1166
1167                 cfunc = new CCodeFunction ("_" + get_ccode_lower_case_prefix (sym) + "unregister_object");
1168                 cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
1169                 cfunc.modifiers |= CCodeModifiers.STATIC;
1170
1171                 push_function (cfunc);
1172
1173                 ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier ("user_data")));
1174
1175                 handle_signals (sym, false);
1176
1177                 var unref_object = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_unref_function (sym)));
1178                 unref_object.add_argument (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("0")));
1179                 ccode.add_expression (unref_object);
1180
1181                 unref_object = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
1182                 unref_object.add_argument (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("1")));
1183                 ccode.add_expression (unref_object);
1184
1185                 var free_path = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
1186                 free_path.add_argument (new CCodeElementAccess (new CCodeIdentifier ("data"), new CCodeConstant ("2")));
1187                 ccode.add_expression (free_path);
1188
1189                 var free_data = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
1190                 free_data.add_argument (new CCodeIdentifier ("data"));
1191                 ccode.add_expression (free_data);
1192
1193                 pop_function ();
1194                 cfile.add_function_declaration (cfunc);
1195                 cfile.add_function (cfunc);
1196         }
1197
1198         public override void register_dbus_info (CCodeBlock block, ObjectTypeSymbol sym) {
1199                 string dbus_iface_name = get_dbus_name (sym);
1200                 if (dbus_iface_name == null) {
1201                         return;
1202                 }
1203
1204                 base.register_dbus_info (block, sym);
1205
1206                 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1207                 quark.add_argument (new CCodeConstant ("\"vala-dbus-register-object\""));
1208
1209                 var set_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_set_qdata"));
1210                 set_qdata.add_argument (new CCodeIdentifier ("%s_type_id".printf (get_ccode_lower_case_name (sym, null))));
1211                 set_qdata.add_argument (quark);
1212                 set_qdata.add_argument (new CCodeCastExpression (new CCodeIdentifier (get_ccode_lower_case_prefix (sym) + "register_object"), "void*"));
1213
1214                 block.add_statement (new CCodeExpressionStatement (set_qdata));
1215         }
1216 }