change run to use meson/ninja and then exec. - remove libvala code from application...
[roobuilder] / src / codegen / valagobjectmodule.vala
1 /* valagobjectmodule.vala
2  *
3  * Copyright (C) 2006-2011  Jürg Billeter
4  * Copyright (C) 2006-2008  Raffaele Sandrini
5  *
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.
10
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.
15
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
19  *
20  * Author:
21  *      Jürg Billeter <j@bitron.ch>
22  *      Raffaele Sandrini <raffaele@sandrini.ch>
23  */
24
25
26 public class Vala.GObjectModule : GTypeModule {
27         int signal_wrapper_id;
28
29         public override void visit_class (Class cl) {
30                 base.visit_class (cl);
31
32                 if (!cl.is_subtype_of (gobject_type)) {
33                         return;
34                 }
35
36                 push_line (cl.source_reference);
37                 if (class_has_readable_properties (cl) || cl.has_type_parameters ()) {
38                         add_get_property_function (cl);
39                 }
40                 if (class_has_writable_properties (cl) || cl.has_type_parameters ()) {
41                         add_set_property_function (cl);
42                 }
43                 pop_line ();
44         }
45
46         public override void generate_class_init (Class cl) {
47                 if (!cl.is_subtype_of (gobject_type)) {
48                         return;
49                 }
50
51                 /* set property handlers */
52                 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
53                 ccall.add_argument (new CCodeIdentifier ("klass"));
54                 if (class_has_readable_properties (cl) || cl.has_type_parameters ()) {
55                         ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("_vala_%s_get_property".printf (get_ccode_lower_case_name (cl, null))));
56                 }
57                 if (class_has_writable_properties (cl) || cl.has_type_parameters ()) {
58                         ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("_vala_%s_set_property".printf (get_ccode_lower_case_name (cl, null))));
59                 }
60
61                 /* set constructor */
62                 if (cl.constructor != null) {
63                         var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
64                         ccast.add_argument (new CCodeIdentifier ("klass"));
65                         ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%sconstructor".printf (get_ccode_lower_case_prefix (cl))));
66                 }
67
68                 /* set finalize function */
69                 if (cl.get_fields ().size > 0 || cl.destructor != null) {
70                         var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
71                         ccast.add_argument (new CCodeIdentifier ("klass"));
72                         ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "finalize"), new CCodeIdentifier ("%sfinalize".printf (get_ccode_lower_case_prefix (cl))));
73                 }
74
75                 /* create type, dup_func, and destroy_func properties for generic types */
76                 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
77                         string func_name, enum_value;
78                         CCodeConstant func_name_constant;
79                         CCodeFunctionCall cinst, cspec;
80
81
82                         func_name = get_ccode_type_id (type_param);
83                         func_name_constant = new CCodeConstant ("\"%s\"".printf (func_name.replace ("_", "-")));
84                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
85                         cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
86                         cinst.add_argument (ccall);
87                         cinst.add_argument (new CCodeConstant (enum_value));
88                         cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_gtype"));
89                         cspec.add_argument (func_name_constant);
90                         cspec.add_argument (new CCodeConstant ("\"type\""));
91                         cspec.add_argument (new CCodeConstant ("\"type\""));
92                         cspec.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
93                         cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY"));
94                         cinst.add_argument (cspec);
95                         ccode.add_expression (cinst);
96                         prop_enum.add_value (new CCodeEnumValue (enum_value));
97
98
99                         func_name = get_ccode_copy_function (type_param);
100                         func_name_constant = new CCodeConstant ("\"%s\"".printf (func_name.replace ("_", "-")));
101                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
102                         cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
103                         cinst.add_argument (ccall);
104                         cinst.add_argument (new CCodeConstant (enum_value));
105                         cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
106                         cspec.add_argument (func_name_constant);
107                         cspec.add_argument (new CCodeConstant ("\"dup func\""));
108                         cspec.add_argument (new CCodeConstant ("\"dup func\""));
109                         cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY"));
110                         cinst.add_argument (cspec);
111                         ccode.add_expression (cinst);
112                         prop_enum.add_value (new CCodeEnumValue (enum_value));
113
114
115                         func_name = get_ccode_destroy_function (type_param);
116                         func_name_constant = new CCodeConstant ("\"%s\"".printf (func_name.replace ("_", "-")));
117                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
118                         cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
119                         cinst.add_argument (ccall);
120                         cinst.add_argument (new CCodeConstant (enum_value));
121                         cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
122                         cspec.add_argument (func_name_constant);
123                         cspec.add_argument (new CCodeConstant ("\"destroy func\""));
124                         cspec.add_argument (new CCodeConstant ("\"destroy func\""));
125                         cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY"));
126                         cinst.add_argument (cspec);
127                         ccode.add_expression (cinst);
128                         prop_enum.add_value (new CCodeEnumValue (enum_value));
129                 }
130
131                 /* create properties */
132                 var props = cl.get_properties ();
133                 foreach (Property prop in props) {
134                         if (!context.analyzer.is_gobject_property (prop)) {
135                                 if (!context.analyzer.is_gobject_property_type (prop.property_type)) {
136                                         Report.warning (prop.source_reference, "Type `%s' can not be used for a GLib.Object property", prop.property_type.to_qualified_string ());
137                                 }
138                                 continue;
139                         }
140
141                         if (prop.comment != null) {
142                                 ccode.add_statement (new CCodeComment (prop.comment.content));
143                         }
144
145                         var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
146                         cinst.add_argument (ccall);
147                         cinst.add_argument (new CCodeConstant ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
148                         cinst.add_argument (get_param_spec (prop));
149
150                         ccode.add_expression (cinst);
151                 }
152         }
153
154         private bool class_has_readable_properties (Class cl) {
155                 foreach (Property prop in cl.get_properties ()) {
156                         if (prop.get_accessor != null) {
157                                 return true;
158                         }
159                 }
160                 return false;
161         }
162
163         private bool class_has_writable_properties (Class cl) {
164                 foreach (Property prop in cl.get_properties ()) {
165                         if (prop.set_accessor != null) {
166                                 return true;
167                         }
168                 }
169                 return false;
170         }
171
172         private void add_guarded_expression (Symbol sym, CCodeExpression expression) {
173                 // prevent deprecation warnings
174                 if (sym.version.deprecated) {
175                         var guard = new CCodeGGnucSection (GGnucSectionType.IGNORE_DEPRECATIONS);
176                         ccode.add_statement (guard);
177                         guard.append (new CCodeExpressionStatement (expression));
178                 } else {
179                         ccode.add_expression (expression);
180                 }
181         }
182
183         private void add_get_property_function (Class cl) {
184                 var get_prop = new CCodeFunction ("_vala_%s_get_property".printf (get_ccode_lower_case_name (cl, null)), "void");
185                 get_prop.modifiers = CCodeModifiers.STATIC;
186                 get_prop.add_parameter (new CCodeParameter ("object", "GObject *"));
187                 get_prop.add_parameter (new CCodeParameter ("property_id", "guint"));
188                 get_prop.add_parameter (new CCodeParameter ("value", "GValue *"));
189                 get_prop.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
190
191                 push_function (get_prop);
192
193                 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
194                 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", ccall));
195
196                 ccode.open_switch (new CCodeIdentifier ("property_id"));
197                 var props = cl.get_properties ();
198                 foreach (Property prop in props) {
199                         if (prop.get_accessor == null || prop.is_abstract) {
200                                 continue;
201                         }
202                         if (!context.analyzer.is_gobject_property (prop)) {
203                                 // don't register private properties
204                                 continue;
205                         }
206
207                         Property base_prop = prop;
208                         CCodeExpression cself = new CCodeIdentifier ("self");
209                         if (prop.base_property != null) {
210                                 var base_type = (Class) prop.base_property.parent_symbol;
211                                 base_prop = prop.base_property;
212                                 cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
213
214                                 generate_property_accessor_declaration (prop.base_property.get_accessor, cfile);
215                         } else if (prop.base_interface_property != null) {
216                                 var base_type = (Interface) prop.base_interface_property.parent_symbol;
217                                 base_prop = prop.base_interface_property;
218                                 cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
219
220                                 generate_property_accessor_declaration (prop.base_interface_property.get_accessor, cfile);
221                         }
222
223                         CCodeExpression cfunc;
224                         if (!get_ccode_no_accessor_method (base_prop) && !get_ccode_concrete_accessor (base_prop)) {
225                                 cfunc = new CCodeIdentifier (get_ccode_name (base_prop.get_accessor));
226                         } else {
227                                 // use the static real function as helper
228                                 cfunc = new CCodeIdentifier (get_ccode_real_name (prop.get_accessor));
229                         }
230
231                         ccode.add_case (new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
232                         if (prop.property_type.is_real_struct_type ()) {
233                                 ccode.open_block ();
234                                 ccode.add_declaration (get_ccode_name (prop.property_type), new CCodeVariableDeclarator ("boxed"));
235
236                                 ccall = new CCodeFunctionCall (cfunc);
237                                 ccall.add_argument (cself);
238                                 if (prop.property_type.nullable) {
239                                         ccode.add_assignment (new CCodeIdentifier ("boxed"), ccall);
240                                 } else {
241                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed")));
242                                         ccode.add_expression (ccall);
243                                 }
244
245                                 var csetcall = new CCodeFunctionCall ();
246                                 csetcall.call = get_value_setter_function (prop.property_type);
247                                 csetcall.add_argument (new CCodeIdentifier ("value"));
248                                 if (prop.property_type.nullable) {
249                                         csetcall.add_argument (new CCodeIdentifier ("boxed"));
250                                 } else {
251                                         csetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed")));
252                                 }
253                                 add_guarded_expression (prop, csetcall);
254
255                                 if (requires_destroy (prop.get_accessor.value_type)) {
256                                         ccode.add_expression (destroy_value (new GLibValue (prop.get_accessor.value_type, new CCodeIdentifier ("boxed"), true)));
257                                 }
258                                 ccode.close ();
259                         } else {
260                                 ccall = new CCodeFunctionCall (cfunc);
261                                 ccall.add_argument (cself);
262                                 var array_type = prop.property_type as ArrayType;
263                                 if (array_type != null && get_ccode_array_length (prop) && array_type.element_type.type_symbol == string_type.type_symbol) {
264                                         // G_TYPE_STRV
265                                         ccode.open_block ();
266                                         ccode.add_declaration ("int", new CCodeVariableDeclarator ("length"));
267                                         ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("length")));
268                                 }
269                                 var csetcall = new CCodeFunctionCall ();
270                                 if (prop.get_accessor.value_type.value_owned) {
271                                         csetcall.call = get_value_taker_function (prop.property_type);
272                                 } else {
273                                         csetcall.call = get_value_setter_function (prop.property_type);
274                                 }
275                                 csetcall.add_argument (new CCodeIdentifier ("value"));
276                                 csetcall.add_argument (ccall);
277                                 add_guarded_expression (prop, csetcall);
278                                 if (array_type != null && get_ccode_array_length (prop) && array_type.element_type.type_symbol == string_type.type_symbol) {
279                                         ccode.close ();
280                                 }
281                         }
282                         ccode.add_break ();
283                 }
284
285                 /* type, dup func, and destroy func properties for generic types */
286                 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
287                         string func_name, enum_value;
288                         CCodeMemberAccess cfield;
289                         CCodeFunctionCall csetcall;
290
291                         func_name = get_ccode_type_id (type_param);
292                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
293                         ccode.add_case (new CCodeIdentifier (enum_value));
294                         cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
295                         csetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_gtype"));
296                         csetcall.add_argument (new CCodeIdentifier ("value"));
297                         csetcall.add_argument (cfield);
298                         ccode.add_expression (csetcall);
299                         ccode.add_break ();
300
301                         func_name = get_ccode_copy_function (type_param);
302                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
303                         ccode.add_case (new CCodeIdentifier (enum_value));
304                         cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
305                         csetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
306                         csetcall.add_argument (new CCodeIdentifier ("value"));
307                         csetcall.add_argument (cfield);
308                         ccode.add_expression (csetcall);
309                         ccode.add_break ();
310
311                         func_name = get_ccode_destroy_function (type_param);
312                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
313                         ccode.add_case (new CCodeIdentifier (enum_value));
314                         cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
315                         csetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
316                         csetcall.add_argument (new CCodeIdentifier ("value"));
317                         csetcall.add_argument (cfield);
318                         ccode.add_expression (csetcall);
319                         ccode.add_break ();
320                 }
321                 ccode.add_default ();
322                 emit_invalid_property_id_warn ();
323                 ccode.add_break ();
324
325                 ccode.close ();
326
327                 pop_function ();
328
329                 cfile.add_function_declaration (get_prop);
330                 cfile.add_function (get_prop);
331         }
332
333         private void add_set_property_function (Class cl) {
334                 var set_prop = new CCodeFunction ("_vala_%s_set_property".printf (get_ccode_lower_case_name (cl, null)), "void");
335                 set_prop.modifiers = CCodeModifiers.STATIC;
336                 set_prop.add_parameter (new CCodeParameter ("object", "GObject *"));
337                 set_prop.add_parameter (new CCodeParameter ("property_id", "guint"));
338                 set_prop.add_parameter (new CCodeParameter ("value", "const GValue *"));
339                 set_prop.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
340
341                 push_function (set_prop);
342
343                 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
344                 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", ccall));
345
346                 ccode.open_switch (new CCodeIdentifier ("property_id"));
347                 var props = cl.get_properties ();
348                 foreach (Property prop in props) {
349                         if (prop.set_accessor == null || prop.is_abstract) {
350                                 continue;
351                         }
352                         if (!context.analyzer.is_gobject_property (prop)) {
353                                 continue;
354                         }
355
356                         Property base_prop = prop;
357                         CCodeExpression cself = new CCodeIdentifier ("self");
358                         if (prop.base_property != null) {
359                                 var base_type = (Class) prop.base_property.parent_symbol;
360                                 base_prop = prop.base_property;
361                                 cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
362
363                                 generate_property_accessor_declaration (prop.base_property.set_accessor, cfile);
364                         } else if (prop.base_interface_property != null) {
365                                 var base_type = (Interface) prop.base_interface_property.parent_symbol;
366                                 base_prop = prop.base_interface_property;
367                                 cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
368
369                                 generate_property_accessor_declaration (prop.base_interface_property.set_accessor, cfile);
370                         }
371
372                         CCodeExpression cfunc;
373                         if (!get_ccode_no_accessor_method (base_prop) && !get_ccode_concrete_accessor (base_prop)) {
374                                 cfunc = new CCodeIdentifier (get_ccode_name (base_prop.set_accessor));
375                         } else {
376                                 // use the static real function as helper
377                                 cfunc = new CCodeIdentifier (get_ccode_real_name (prop.set_accessor));
378                         }
379
380                         ccode.add_case (new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
381                         ccall = new CCodeFunctionCall (cfunc);
382                         ccall.add_argument (cself);
383                         if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.type_symbol == string_type.type_symbol) {
384                                 ccode.open_block ();
385                                 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("boxed"));
386
387                                 var cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_boxed"));
388                                 cgetcall.add_argument (new CCodeIdentifier ("value"));
389                                 ccode.add_assignment (new CCodeIdentifier ("boxed"), cgetcall);
390                                 ccall.add_argument (new CCodeIdentifier ("boxed"));
391
392                                 if (get_ccode_array_length (prop)) {
393                                         var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("boxed"), new CCodeConstant ("NULL"));
394                                         var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
395                                         cstrvlen.add_argument (new CCodeIdentifier ("boxed"));
396                                         var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cstrvlen);
397
398                                         ccall.add_argument (ccond);
399                                 }
400                                 add_guarded_expression (prop, ccall);
401                                 ccode.close ();
402                         } else {
403                                 var cgetcall = new CCodeFunctionCall ();
404                                 if (prop.property_type.type_symbol != null) {
405                                         cgetcall.call = new CCodeIdentifier (get_ccode_get_value_function (prop.property_type.type_symbol));
406                                 } else {
407                                         cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
408                                 }
409                                 cgetcall.add_argument (new CCodeIdentifier ("value"));
410                                 ccall.add_argument (cgetcall);
411                                 add_guarded_expression (prop, ccall);
412                         }
413                         ccode.add_break ();
414                 }
415
416                 /* type, dup func, and destroy func properties for generic types */
417                 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
418                         string func_name, enum_value;
419                         CCodeMemberAccess cfield;
420                         CCodeFunctionCall cgetcall;
421
422                         func_name = get_ccode_type_id (type_param);
423                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
424                         ccode.add_case (new CCodeIdentifier (enum_value));
425                         cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
426                         cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_gtype"));
427                         cgetcall.add_argument (new CCodeIdentifier ("value"));
428                         ccode.add_assignment (cfield, cgetcall);
429                         ccode.add_break ();
430
431                         func_name = get_ccode_copy_function (type_param);
432                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
433                         ccode.add_case (new CCodeIdentifier (enum_value));
434                         cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
435                         cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
436                         cgetcall.add_argument (new CCodeIdentifier ("value"));
437                         ccode.add_assignment (cfield, cgetcall);
438                         ccode.add_break ();
439
440                         func_name = get_ccode_destroy_function (type_param);
441                         enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
442                         ccode.add_case (new CCodeIdentifier (enum_value));
443                         cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
444                         cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
445                         cgetcall.add_argument (new CCodeIdentifier ("value"));
446                         ccode.add_assignment (cfield, cgetcall);
447                         ccode.add_break ();
448                 }
449                 ccode.add_default ();
450                 emit_invalid_property_id_warn ();
451                 ccode.add_break ();
452
453                 ccode.close ();
454
455                 pop_function ();
456
457                 cfile.add_function_declaration (set_prop);
458                 cfile.add_function (set_prop);
459         }
460
461         private void emit_invalid_property_id_warn () {
462                 // warn on invalid property id
463                 var cwarn = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
464                 cwarn.add_argument (new CCodeIdentifier ("object"));
465                 cwarn.add_argument (new CCodeIdentifier ("property_id"));
466                 cwarn.add_argument (new CCodeIdentifier ("pspec"));
467                 ccode.add_expression (cwarn);
468         }
469
470         public override void visit_constructor (Constructor c) {
471                 push_line (c.source_reference);
472
473                 var cl = (Class) c.parent_symbol;
474
475                 if (c.binding == MemberBinding.INSTANCE) {
476                         if (!cl.is_subtype_of (gobject_type)) {
477                                 Report.error (c.source_reference, "construct blocks require GLib.Object");
478                                 c.error = true;
479                                 return;
480                         }
481
482                         push_context (new EmitContext (c));
483
484                         var function = new CCodeFunction ("%sconstructor".printf (get_ccode_lower_case_prefix (cl)), "GObject *");
485                         function.modifiers = CCodeModifiers.STATIC;
486
487                         function.add_parameter (new CCodeParameter ("type", "GType"));
488                         function.add_parameter (new CCodeParameter ("n_construct_properties", "guint"));
489                         function.add_parameter (new CCodeParameter ("construct_properties", "GObjectConstructParam *"));
490
491                         cfile.add_function_declaration (function);
492
493                         push_function (function);
494
495                         ccode.add_declaration ("GObject *", new CCodeVariableDeclarator ("obj"));
496                         ccode.add_declaration ("GObjectClass *", new CCodeVariableDeclarator ("parent_class"));
497
498                         if (cl.is_singleton) {
499                                 var singleton_ref_name = "%s_singleton__ref".printf (get_ccode_name (cl));
500                                 var singleton_lock_name = "%s_singleton__lock".printf (get_ccode_name (cl));
501                                 var singleton_once_name = "%s_singleton__once".printf (get_ccode_name (cl));
502
503                                 var singleton_ref = new CCodeDeclaration("GObject *");
504                                 singleton_ref.add_declarator (new CCodeVariableDeclarator (singleton_ref_name, new CCodeConstant ("NULL")));
505                                 singleton_ref.modifiers = CCodeModifiers.STATIC;
506                                 ccode.add_statement (singleton_ref);
507
508                                 var mutex_lock = new CCodeDeclaration("GMutex");
509                                 mutex_lock.add_declarator (new CCodeVariableDeclarator (singleton_lock_name));
510                                 mutex_lock.modifiers = CCodeModifiers.STATIC;
511                                 ccode.add_statement (mutex_lock);
512
513                                 var once_lock = new CCodeDeclaration("gsize");
514                                 once_lock.add_declarator (new CCodeVariableDeclarator (singleton_once_name, new CCodeConstant ("0")));
515                                 if (context.require_glib_version (2, 68)) {
516                                         once_lock.modifiers = CCodeModifiers.STATIC;
517                                 } else {
518                                         once_lock.modifiers = CCodeModifiers.STATIC | CCodeModifiers.VOLATILE;
519                                 }
520                                 ccode.add_statement (once_lock);
521
522                                 var once_init = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_enter"));
523                                 once_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_once_name)));
524
525                                 var once_block = new CCodeBlock();
526
527                                 var singleton_mutex_init = new CCodeFunctionCall (new CCodeIdentifier ("g_mutex_init"));
528                                 singleton_mutex_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_lock_name)));
529                                 once_block.add_statement (new CCodeExpressionStatement (singleton_mutex_init));
530
531                                 var once_leave = new CCodeFunctionCall (new CCodeIdentifier ("g_once_init_leave"));
532                                 once_leave.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_once_name)));
533                                 once_leave.add_argument (new CCodeConstant ("42"));
534                                 once_block.add_statement (new CCodeExpressionStatement (once_leave));
535
536                                 var if_once = new CCodeIfStatement (once_init, once_block);
537                                 ccode.add_statement (if_once);
538
539                                 var singleton_mutex_lock = new CCodeFunctionCall (new CCodeIdentifier ("g_mutex_lock"));
540                                 singleton_mutex_lock.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_lock_name)));
541                                 ccode.add_statement (new CCodeExpressionStatement (singleton_mutex_lock));
542
543                                 var check_existance = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (singleton_ref_name), new CCodeConstant ("NULL"));
544                                 var return_singleton = new CCodeBlock();
545
546                                 var ref_object = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref"));
547                                 ref_object.add_argument (new CCodeIdentifier (singleton_ref_name));
548                                 return_singleton.add_statement (new CCodeExpressionStatement (ref_object));
549
550                                 var singleton_mutex_unlock = new CCodeFunctionCall (new CCodeIdentifier ("g_mutex_unlock"));
551                                 singleton_mutex_unlock.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_lock_name)));
552                                 return_singleton.add_statement (new CCodeExpressionStatement (singleton_mutex_unlock));
553                                 return_singleton.add_statement (new CCodeReturnStatement (new CCodeIdentifier (singleton_ref_name)));
554
555                                 var if_singleton_alive = new CCodeIfStatement (check_existance, return_singleton);
556                                 ccode.add_statement (if_singleton_alive);
557                         }
558
559                         var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
560                         ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (cl, null))));
561                         ccode.add_assignment (new CCodeIdentifier ("parent_class"), ccast);
562
563                         var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
564                         ccall.add_argument (new CCodeIdentifier ("type"));
565                         ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
566                         ccall.add_argument (new CCodeIdentifier ("construct_properties"));
567                         ccode.add_assignment (new CCodeIdentifier ("obj"), ccall);
568
569
570                         ccall = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
571
572                         ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
573                         ccode.add_assignment (new CCodeIdentifier ("self"), ccall);
574
575                         c.body.emit (this);
576
577                         if (current_method_inner_error) {
578                                 /* always separate error parameter and inner_error local variable
579                                  * as error may be set to NULL but we're always interested in inner errors
580                                  */
581                                 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
582                         }
583
584                         if (cl.is_singleton) {
585                                 var singleton_ref_name = "%s_singleton__ref".printf (get_ccode_name (cl));
586                                 var singleton_lock_name = "%s_singleton__lock".printf (get_ccode_name (cl));
587
588                                 ccode.add_assignment (new CCodeIdentifier (singleton_ref_name), new CCodeIdentifier ("obj"));
589
590                                 var set_weak_ref_to_volatile = new CCodeFunctionCall (new CCodeIdentifier ("g_object_add_weak_pointer"));
591                                 set_weak_ref_to_volatile.add_argument (new CCodeIdentifier (singleton_ref_name));
592                                 set_weak_ref_to_volatile.add_argument (new CCodeCastExpression (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_ref_name)), "gpointer"));
593                                 ccode.add_statement (new CCodeExpressionStatement (set_weak_ref_to_volatile));
594
595                                 var final_singleton_mutex_unlock = new CCodeFunctionCall (new CCodeIdentifier ("g_mutex_unlock"));
596                                 final_singleton_mutex_unlock.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_lock_name)));
597                                 ccode.add_statement (new CCodeExpressionStatement (final_singleton_mutex_unlock));
598                         }
599
600                         ccode.add_return (new CCodeIdentifier ("obj"));
601
602                         pop_function ();
603                         cfile.add_function (function);
604
605                         pop_context ();
606                 } else if (c.binding == MemberBinding.CLASS) {
607                         // class constructor
608
609                         if (cl.is_compact) {
610                                 Report.error (c.source_reference, "class constructors are not supported in compact classes");
611                                 c.error = true;
612                                 return;
613                         }
614
615                         push_context (base_init_context);
616
617                         c.body.emit (this);
618
619                         if (current_method_inner_error) {
620                                 /* always separate error parameter and inner_error local variable
621                                  * as error may be set to NULL but we're always interested in inner errors
622                                  */
623                                 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
624                         }
625
626                         pop_context ();
627                 } else if (c.binding == MemberBinding.STATIC) {
628                         // static class constructor
629                         // add to class_init
630
631                         if (cl.is_compact) {
632                                 Report.error (c.source_reference, "static constructors are not supported in compact classes");
633                                 c.error = true;
634                                 return;
635                         }
636
637                         push_context (class_init_context);
638
639                         c.body.emit (this);
640
641                         if (current_method_inner_error) {
642                                 /* always separate error parameter and inner_error local variable
643                                  * as error may be set to NULL but we're always interested in inner errors
644                                  */
645                                 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
646                         }
647
648                         pop_context ();
649                 } else {
650                         Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
651                 }
652
653                 pop_line ();
654         }
655
656         public override string get_dynamic_signal_cname (DynamicSignal node) {
657                 return "dynamic_%s%d_".printf (node.name, signal_wrapper_id++);
658         }
659
660         public override void visit_property (Property prop) {
661                 base.visit_property (prop);
662
663                 if (context.analyzer.is_gobject_property (prop) && prop.parent_symbol is Class) {
664                         prop_enum.add_value (new CCodeEnumValue ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
665                 }
666         }
667
668         public override void visit_method_call (MethodCall expr) {
669                 if (expr.call is MemberAccess) {
670                         push_line (expr.source_reference);
671
672                         var ma = expr.call as MemberAccess;
673                         if (ma.inner != null && ma.inner.symbol_reference == gobject_type &&
674                             (ma.member_name == "new" || ma.member_name == "newv"
675                              || ma.member_name == "new_valist" || ma.member_name == "new_with_properties")) {
676                                 // Object.new (...) creation
677                                 // runtime check to ref_sink the instance if it's a floating type
678                                 base.visit_method_call (expr);
679
680                                 var initiallyunowned_ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_INITIALLY_UNOWNED"));
681                                 initiallyunowned_ccall.add_argument (get_cvalue (expr));
682                                 var sink_ref_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
683                                 sink_ref_ccall.add_argument (get_cvalue (expr));
684                                 var cexpr = new CCodeConditionalExpression (initiallyunowned_ccall, sink_ref_ccall, get_cvalue (expr));
685
686                                 expr.target_value = store_temp_value (new GLibValue (expr.value_type, cexpr), expr);
687                                 return;
688                         } else if (ma.symbol_reference == gobject_type) {
689                                 // Object (...) chain up
690                                 // check it's only used with valid properties
691                                 foreach (var arg in expr.get_argument_list ()) {
692                                         var named_argument = arg as NamedArgument;
693                                         if (named_argument == null) {
694                                                 Report.error (arg.source_reference, "Named argument expected");
695                                                 break;
696                                         }
697                                         var prop = SemanticAnalyzer.symbol_lookup_inherited (current_class, named_argument.name) as Property;
698                                         if (prop == null) {
699                                                 Report.error (arg.source_reference, "Property `%s' not found in `%s'", named_argument.name, current_class.get_full_name ());
700                                                 break;
701                                         }
702                                         if (!context.analyzer.is_gobject_property (prop)) {
703                                                 Report.error (arg.source_reference, "Property `%s' not supported in Object (property: value) constructor chain up", named_argument.name);
704                                                 break;
705                                         }
706                                         if (!arg.value_type.compatible (prop.property_type)) {
707                                                 Report.error (arg.source_reference, "Cannot convert from `%s' to `%s'", arg.value_type.to_string (), prop.property_type.to_string ());
708                                                 break;
709                                         }
710                                 }
711                         }
712
713                         pop_line ();
714                 }
715
716                 base.visit_method_call (expr);
717         }
718 }
719