1 /* valagobjectmodule.vala
3 * Copyright (C) 2006-2011 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 public class Vala.GObjectModule : GTypeModule {
27 int signal_wrapper_id;
29 public override void visit_class (Class cl) {
30 base.visit_class (cl);
32 if (!cl.is_subtype_of (gobject_type)) {
36 push_line (cl.source_reference);
37 if (class_has_readable_properties (cl) || cl.has_type_parameters ()) {
38 add_get_property_function (cl);
40 if (class_has_writable_properties (cl) || cl.has_type_parameters ()) {
41 add_set_property_function (cl);
46 public override void generate_class_init (Class cl) {
47 if (!cl.is_subtype_of (gobject_type)) {
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))));
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))));
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))));
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))));
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;
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));
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));
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));
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 ());
141 if (prop.comment != null) {
142 ccode.add_statement (new CCodeComment (prop.comment.content));
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));
150 ccode.add_expression (cinst);
154 private bool class_has_readable_properties (Class cl) {
155 foreach (Property prop in cl.get_properties ()) {
156 if (prop.get_accessor != null) {
163 private bool class_has_writable_properties (Class cl) {
164 foreach (Property prop in cl.get_properties ()) {
165 if (prop.set_accessor != null) {
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));
179 ccode.add_expression (expression);
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 *"));
191 push_function (get_prop);
193 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
194 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", ccall));
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) {
202 if (!context.analyzer.is_gobject_property (prop)) {
203 // don't register private properties
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));
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));
220 generate_property_accessor_declaration (prop.base_interface_property.get_accessor, cfile);
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));
227 // use the static real function as helper
228 cfunc = new CCodeIdentifier (get_ccode_real_name (prop.get_accessor));
231 ccode.add_case (new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
232 if (prop.property_type.is_real_struct_type ()) {
234 ccode.add_declaration (get_ccode_name (prop.property_type), new CCodeVariableDeclarator ("boxed"));
236 ccall = new CCodeFunctionCall (cfunc);
237 ccall.add_argument (cself);
238 if (prop.property_type.nullable) {
239 ccode.add_assignment (new CCodeIdentifier ("boxed"), ccall);
241 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed")));
242 ccode.add_expression (ccall);
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"));
251 csetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed")));
253 add_guarded_expression (prop, csetcall);
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)));
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) {
266 ccode.add_declaration ("int", new CCodeVariableDeclarator ("length"));
267 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("length")));
269 var csetcall = new CCodeFunctionCall ();
270 if (prop.get_accessor.value_type.value_owned) {
271 csetcall.call = get_value_taker_function (prop.property_type);
273 csetcall.call = get_value_setter_function (prop.property_type);
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) {
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;
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);
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);
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);
321 ccode.add_default ();
322 emit_invalid_property_id_warn ();
329 cfile.add_function_declaration (get_prop);
330 cfile.add_function (get_prop);
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 *"));
341 push_function (set_prop);
343 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
344 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", ccall));
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) {
352 if (!context.analyzer.is_gobject_property (prop)) {
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));
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));
369 generate_property_accessor_declaration (prop.base_interface_property.set_accessor, cfile);
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));
376 // use the static real function as helper
377 cfunc = new CCodeIdentifier (get_ccode_real_name (prop.set_accessor));
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) {
385 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("boxed"));
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"));
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);
398 ccall.add_argument (ccond);
400 add_guarded_expression (prop, ccall);
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));
407 cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
409 cgetcall.add_argument (new CCodeIdentifier ("value"));
410 ccall.add_argument (cgetcall);
411 add_guarded_expression (prop, ccall);
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;
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);
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);
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);
449 ccode.add_default ();
450 emit_invalid_property_id_warn ();
457 cfile.add_function_declaration (set_prop);
458 cfile.add_function (set_prop);
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);
470 public override void visit_constructor (Constructor c) {
471 push_line (c.source_reference);
473 var cl = (Class) c.parent_symbol;
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");
482 push_context (new EmitContext (c));
484 var function = new CCodeFunction ("%sconstructor".printf (get_ccode_lower_case_prefix (cl)), "GObject *");
485 function.modifiers = CCodeModifiers.STATIC;
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 *"));
491 cfile.add_function_declaration (function);
493 push_function (function);
495 ccode.add_declaration ("GObject *", new CCodeVariableDeclarator ("obj"));
496 ccode.add_declaration ("GObjectClass *", new CCodeVariableDeclarator ("parent_class"));
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));
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);
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);
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;
518 once_lock.modifiers = CCodeModifiers.STATIC | CCodeModifiers.VOLATILE;
520 ccode.add_statement (once_lock);
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)));
525 var once_block = new CCodeBlock();
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));
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));
536 var if_once = new CCodeIfStatement (once_init, once_block);
537 ccode.add_statement (if_once);
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));
543 var check_existance = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (singleton_ref_name), new CCodeConstant ("NULL"));
544 var return_singleton = new CCodeBlock();
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));
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)));
555 var if_singleton_alive = new CCodeIfStatement (check_existance, return_singleton);
556 ccode.add_statement (if_singleton_alive);
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);
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);
570 ccall = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
572 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
573 ccode.add_assignment (new CCodeIdentifier ("self"), ccall);
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
581 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
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));
588 ccode.add_assignment (new CCodeIdentifier (singleton_ref_name), new CCodeIdentifier ("obj"));
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));
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));
600 ccode.add_return (new CCodeIdentifier ("obj"));
603 cfile.add_function (function);
606 } else if (c.binding == MemberBinding.CLASS) {
610 Report.error (c.source_reference, "class constructors are not supported in compact classes");
615 push_context (base_init_context);
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
623 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
627 } else if (c.binding == MemberBinding.STATIC) {
628 // static class constructor
632 Report.error (c.source_reference, "static constructors are not supported in compact classes");
637 push_context (class_init_context);
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
645 ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
650 Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
656 public override string get_dynamic_signal_cname (DynamicSignal node) {
657 return "dynamic_%s%d_".printf (node.name, signal_wrapper_id++);
660 public override void visit_property (Property prop) {
661 base.visit_property (prop);
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))));
668 public override void visit_method_call (MethodCall expr) {
669 if (expr.call is MemberAccess) {
670 push_line (expr.source_reference);
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);
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));
686 expr.target_value = store_temp_value (new GLibValue (expr.value_type, cexpr), expr);
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");
697 var prop = SemanticAnalyzer.symbol_lookup_inherited (current_class, named_argument.name) as Property;
699 Report.error (arg.source_reference, "Property `%s' not found in `%s'", named_argument.name, current_class.get_full_name ());
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);
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 ());
716 base.visit_method_call (expr);