Release 0.41.92
[vala-gnome.git] / codegen / valagobjectmodule.vala
blobad808a138fff4c850f09acb0963bc2e3b4ad3bc1
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 public class Vala.GObjectModule : GTypeModule {
27 int dynamic_property_id;
28 int signal_wrapper_id;
30 public override void visit_class (Class cl) {
31 base.visit_class (cl);
33 if (!cl.is_subtype_of (gobject_type)) {
34 return;
37 push_line (cl.source_reference);
38 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
39 add_get_property_function (cl);
41 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
42 add_set_property_function (cl);
44 pop_line ();
47 public override void generate_class_init (Class cl) {
48 if (!cl.is_subtype_of (gobject_type)) {
49 return;
52 /* set property handlers */
53 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
54 ccall.add_argument (new CCodeIdentifier ("klass"));
55 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
56 ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("_vala_%s_get_property".printf (get_ccode_lower_case_name (cl, null))));
58 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
59 ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("_vala_%s_set_property".printf (get_ccode_lower_case_name (cl, null))));
62 /* set constructor */
63 if (cl.constructor != null) {
64 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
65 ccast.add_argument (new CCodeIdentifier ("klass"));
66 ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%s_constructor".printf (get_ccode_lower_case_name (cl, null))));
69 /* set finalize function */
70 if (cl.get_fields ().size > 0 || cl.destructor != null) {
71 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
72 ccast.add_argument (new CCodeIdentifier ("klass"));
73 ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "finalize"), new CCodeIdentifier ("%s_finalize".printf (get_ccode_lower_case_name (cl, null))));
76 /* create type, dup_func, and destroy_func properties for generic types */
77 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
78 string func_name, enum_value;
79 CCodeConstant func_name_constant;
80 CCodeFunctionCall cinst, cspec;
82 var name_prefix = type_param.name.down ();
83 var canonical_prefix = name_prefix.replace ("_", "-");
85 func_name = "%s_type".printf (name_prefix);
86 func_name_constant = new CCodeConstant ("\"%s-type\"".printf (canonical_prefix));
87 enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
88 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
89 cinst.add_argument (ccall);
90 cinst.add_argument (new CCodeConstant (enum_value));
91 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_gtype"));
92 cspec.add_argument (func_name_constant);
93 cspec.add_argument (new CCodeConstant ("\"type\""));
94 cspec.add_argument (new CCodeConstant ("\"type\""));
95 cspec.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
96 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
97 cinst.add_argument (cspec);
98 ccode.add_expression (cinst);
99 prop_enum.add_value (new CCodeEnumValue (enum_value));
102 func_name = "%s_dup_func".printf (name_prefix);
103 func_name_constant = new CCodeConstant ("\"%s-dup-func\"".printf (canonical_prefix));
104 enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
105 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
106 cinst.add_argument (ccall);
107 cinst.add_argument (new CCodeConstant (enum_value));
108 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
109 cspec.add_argument (func_name_constant);
110 cspec.add_argument (new CCodeConstant ("\"dup func\""));
111 cspec.add_argument (new CCodeConstant ("\"dup func\""));
112 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
113 cinst.add_argument (cspec);
114 ccode.add_expression (cinst);
115 prop_enum.add_value (new CCodeEnumValue (enum_value));
118 func_name = "%s_destroy_func".printf (name_prefix);
119 func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (canonical_prefix));
120 enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
121 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
122 cinst.add_argument (ccall);
123 cinst.add_argument (new CCodeConstant (enum_value));
124 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
125 cspec.add_argument (func_name_constant);
126 cspec.add_argument (new CCodeConstant ("\"destroy func\""));
127 cspec.add_argument (new CCodeConstant ("\"destroy func\""));
128 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
129 cinst.add_argument (cspec);
130 ccode.add_expression (cinst);
131 prop_enum.add_value (new CCodeEnumValue (enum_value));
134 /* create properties */
135 var props = cl.get_properties ();
136 foreach (Property prop in props) {
137 if (!is_gobject_property (prop)) {
138 if (!has_valid_gobject_property_type (prop)) {
139 Report.warning (prop.source_reference, "Type `%s' can not be used for a GLib.Object property".printf (prop.property_type.to_qualified_string ()));
141 continue;
144 if (prop.comment != null) {
145 ccode.add_statement (new CCodeComment (prop.comment.content));
148 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
149 cinst.add_argument (ccall);
150 cinst.add_argument (new CCodeConstant ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
151 cinst.add_argument (get_param_spec (prop));
153 ccode.add_expression (cinst);
157 private bool class_has_readable_properties (Class cl) {
158 foreach (Property prop in cl.get_properties ()) {
159 if (prop.get_accessor != null) {
160 return true;
163 return false;
166 private bool class_has_writable_properties (Class cl) {
167 foreach (Property prop in cl.get_properties ()) {
168 if (prop.set_accessor != null) {
169 return true;
172 return false;
175 private void add_guarded_expression (Symbol sym, CCodeExpression expression) {
176 // prevent deprecation warnings
177 if (sym.version.deprecated) {
178 var guard = new CCodeGGnucSection (GGnucSectionType.IGNORE_DEPRECATIONS);
179 ccode.add_statement (guard);
180 guard.append (new CCodeExpressionStatement (expression));
181 } else {
182 ccode.add_expression (expression);
186 private void add_get_property_function (Class cl) {
187 var get_prop = new CCodeFunction ("_vala_%s_get_property".printf (get_ccode_lower_case_name (cl, null)), "void");
188 get_prop.modifiers = CCodeModifiers.STATIC;
189 get_prop.add_parameter (new CCodeParameter ("object", "GObject *"));
190 get_prop.add_parameter (new CCodeParameter ("property_id", "guint"));
191 get_prop.add_parameter (new CCodeParameter ("value", "GValue *"));
192 get_prop.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
194 push_function (get_prop);
196 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
197 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", ccall));
199 ccode.open_switch (new CCodeIdentifier ("property_id"));
200 var props = cl.get_properties ();
201 foreach (Property prop in props) {
202 if (prop.get_accessor == null || prop.is_abstract) {
203 continue;
205 if (!is_gobject_property (prop)) {
206 // don't register private properties
207 continue;
210 Property base_prop = prop;
211 CCodeExpression cself = new CCodeIdentifier ("self");
212 if (prop.base_property != null) {
213 var base_type = (Class) prop.base_property.parent_symbol;
214 base_prop = prop.base_property;
215 cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
217 generate_property_accessor_declaration (prop.base_property.get_accessor, cfile);
218 } else if (prop.base_interface_property != null) {
219 var base_type = (Interface) prop.base_interface_property.parent_symbol;
220 base_prop = prop.base_interface_property;
221 cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
223 generate_property_accessor_declaration (prop.base_interface_property.get_accessor, cfile);
226 CCodeExpression cfunc;
227 if (!get_ccode_no_accessor_method (base_prop) && !get_ccode_concrete_accessor (base_prop)) {
228 cfunc = new CCodeIdentifier (get_ccode_name (base_prop.get_accessor));
229 } else {
230 // use the static real function as helper
231 cfunc = new CCodeIdentifier (get_ccode_real_name (prop.get_accessor));
234 ccode.add_case (new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
235 if (prop.property_type.is_real_struct_type ()) {
236 var st = prop.property_type.data_type as Struct;
238 ccode.open_block ();
239 ccode.add_declaration (get_ccode_name (st), new CCodeVariableDeclarator ("boxed"));
241 ccall = new CCodeFunctionCall (cfunc);
242 ccall.add_argument (cself);
243 var boxed_addr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed"));
244 ccall.add_argument (boxed_addr);
245 ccode.add_expression (ccall);
247 var csetcall = new CCodeFunctionCall ();
248 csetcall.call = get_value_setter_function (prop.property_type);
249 csetcall.add_argument (new CCodeIdentifier ("value"));
250 csetcall.add_argument (boxed_addr);
251 add_guarded_expression (prop, csetcall);
253 if (requires_destroy (prop.get_accessor.value_type)) {
254 ccode.add_expression (destroy_value (new GLibValue (prop.get_accessor.value_type, new CCodeIdentifier ("boxed"), true)));
256 ccode.close ();
257 } else {
258 ccall = new CCodeFunctionCall (cfunc);
259 ccall.add_argument (cself);
260 var array_type = prop.property_type as ArrayType;
261 if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
262 // G_TYPE_STRV
263 ccode.open_block ();
264 ccode.add_declaration ("int", new CCodeVariableDeclarator ("length"));
265 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("length")));
267 var csetcall = new CCodeFunctionCall ();
268 if (prop.get_accessor.value_type.value_owned) {
269 csetcall.call = get_value_taker_function (prop.property_type);
270 } else {
271 csetcall.call = get_value_setter_function (prop.property_type);
273 csetcall.add_argument (new CCodeIdentifier ("value"));
274 csetcall.add_argument (ccall);
275 add_guarded_expression (prop, csetcall);
276 if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
277 ccode.close ();
280 ccode.add_break ();
282 ccode.add_default ();
283 emit_invalid_property_id_warn ();
284 ccode.add_break ();
286 ccode.close ();
288 pop_function ();
290 cfile.add_function_declaration (get_prop);
291 cfile.add_function (get_prop);
294 private void add_set_property_function (Class cl) {
295 var set_prop = new CCodeFunction ("_vala_%s_set_property".printf (get_ccode_lower_case_name (cl, null)), "void");
296 set_prop.modifiers = CCodeModifiers.STATIC;
297 set_prop.add_parameter (new CCodeParameter ("object", "GObject *"));
298 set_prop.add_parameter (new CCodeParameter ("property_id", "guint"));
299 set_prop.add_parameter (new CCodeParameter ("value", "const GValue *"));
300 set_prop.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
302 push_function (set_prop);
304 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
305 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", ccall));
307 ccode.open_switch (new CCodeIdentifier ("property_id"));
308 var props = cl.get_properties ();
309 foreach (Property prop in props) {
310 if (prop.set_accessor == null || prop.is_abstract) {
311 continue;
313 if (!is_gobject_property (prop)) {
314 continue;
317 Property base_prop = prop;
318 CCodeExpression cself = new CCodeIdentifier ("self");
319 if (prop.base_property != null) {
320 var base_type = (Class) prop.base_property.parent_symbol;
321 base_prop = prop.base_property;
322 cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
324 generate_property_accessor_declaration (prop.base_property.set_accessor, cfile);
325 } else if (prop.base_interface_property != null) {
326 var base_type = (Interface) prop.base_interface_property.parent_symbol;
327 base_prop = prop.base_interface_property;
328 cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
330 generate_property_accessor_declaration (prop.base_interface_property.set_accessor, cfile);
333 CCodeExpression cfunc;
334 if (!get_ccode_no_accessor_method (base_prop) && !get_ccode_concrete_accessor (base_prop)) {
335 cfunc = new CCodeIdentifier (get_ccode_name (base_prop.set_accessor));
336 } else {
337 // use the static real function as helper
338 cfunc = new CCodeIdentifier (get_ccode_real_name (prop.set_accessor));
341 ccode.add_case (new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
342 ccall = new CCodeFunctionCall (cfunc);
343 ccall.add_argument (cself);
344 if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.data_type == string_type.data_type) {
345 ccode.open_block ();
346 ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("boxed"));
348 var cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_boxed"));
349 cgetcall.add_argument (new CCodeIdentifier ("value"));
350 ccode.add_assignment (new CCodeIdentifier ("boxed"), cgetcall);
351 ccall.add_argument (new CCodeIdentifier ("boxed"));
353 var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("boxed"), new CCodeConstant ("NULL"));
354 var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
355 cstrvlen.add_argument (new CCodeIdentifier ("boxed"));
356 var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cstrvlen);
358 ccall.add_argument (ccond);
359 add_guarded_expression (prop, ccall);
360 ccode.close ();
361 } else {
362 var cgetcall = new CCodeFunctionCall ();
363 if (prop.property_type.data_type != null) {
364 cgetcall.call = new CCodeIdentifier (get_ccode_get_value_function (prop.property_type.data_type));
365 } else {
366 cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
368 cgetcall.add_argument (new CCodeIdentifier ("value"));
369 ccall.add_argument (cgetcall);
370 add_guarded_expression (prop, ccall);
372 ccode.add_break ();
375 /* type, dup func, and destroy func properties for generic types */
376 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
377 string func_name, enum_value;
378 CCodeMemberAccess cfield;
379 CCodeFunctionCall cgetcall;
381 func_name = "%s_type".printf (type_param.name.ascii_down ());
382 enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
383 ccode.add_case (new CCodeIdentifier (enum_value));
384 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
385 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_gtype"));
386 cgetcall.add_argument (new CCodeIdentifier ("value"));
387 ccode.add_assignment (cfield, cgetcall);
388 ccode.add_break ();
390 func_name = "%s_dup_func".printf (type_param.name.ascii_down ());
391 enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
392 ccode.add_case (new CCodeIdentifier (enum_value));
393 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
394 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
395 cgetcall.add_argument (new CCodeIdentifier ("value"));
396 ccode.add_assignment (cfield, cgetcall);
397 ccode.add_break ();
399 func_name = "%s_destroy_func".printf (type_param.name.ascii_down ());
400 enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
401 ccode.add_case (new CCodeIdentifier (enum_value));
402 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
403 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
404 cgetcall.add_argument (new CCodeIdentifier ("value"));
405 ccode.add_assignment (cfield, cgetcall);
406 ccode.add_break ();
408 ccode.add_default ();
409 emit_invalid_property_id_warn ();
410 ccode.add_break ();
412 ccode.close ();
414 pop_function ();
416 cfile.add_function_declaration (set_prop);
417 cfile.add_function (set_prop);
420 private void emit_invalid_property_id_warn () {
421 // warn on invalid property id
422 var cwarn = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
423 cwarn.add_argument (new CCodeIdentifier ("object"));
424 cwarn.add_argument (new CCodeIdentifier ("property_id"));
425 cwarn.add_argument (new CCodeIdentifier ("pspec"));
426 ccode.add_expression (cwarn);
429 public override void visit_constructor (Constructor c) {
430 push_line (c.source_reference);
432 var cl = (Class) c.parent_symbol;
434 if (c.binding == MemberBinding.INSTANCE) {
435 if (!cl.is_subtype_of (gobject_type)) {
436 Report.error (c.source_reference, "construct blocks require GLib.Object");
437 c.error = true;
438 return;
441 push_context (new EmitContext (c));
443 var function = new CCodeFunction ("%s_constructor".printf (get_ccode_lower_case_name (cl, null)), "GObject *");
444 function.modifiers = CCodeModifiers.STATIC;
446 function.add_parameter (new CCodeParameter ("type", "GType"));
447 function.add_parameter (new CCodeParameter ("n_construct_properties", "guint"));
448 function.add_parameter (new CCodeParameter ("construct_properties", "GObjectConstructParam *"));
450 cfile.add_function_declaration (function);
452 push_function (function);
454 ccode.add_declaration ("GObject *", new CCodeVariableDeclarator ("obj"));
455 ccode.add_declaration ("GObjectClass *", new CCodeVariableDeclarator ("parent_class"));
457 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
458 ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (cl, null))));
459 ccode.add_assignment (new CCodeIdentifier ("parent_class"), ccast);
461 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
462 ccall.add_argument (new CCodeIdentifier ("type"));
463 ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
464 ccall.add_argument (new CCodeIdentifier ("construct_properties"));
465 ccode.add_assignment (new CCodeIdentifier ("obj"), ccall);
468 ccall = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
470 ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
471 ccode.add_assignment (new CCodeIdentifier ("self"), ccall);
473 c.body.emit (this);
475 if (current_method_inner_error) {
476 /* always separate error parameter and inner_error local variable
477 * as error may be set to NULL but we're always interested in inner errors
479 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
482 ccode.add_return (new CCodeIdentifier ("obj"));
484 pop_function ();
485 cfile.add_function (function);
487 pop_context ();
488 } else if (c.binding == MemberBinding.CLASS) {
489 // class constructor
491 if (cl.is_compact) {
492 Report.error (c.source_reference, "class constructors are not supported in compact classes");
493 c.error = true;
494 return;
497 push_context (base_init_context);
499 c.body.emit (this);
501 if (current_method_inner_error) {
502 /* always separate error parameter and inner_error local variable
503 * as error may be set to NULL but we're always interested in inner errors
505 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
508 pop_context ();
509 } else if (c.binding == MemberBinding.STATIC) {
510 // static class constructor
511 // add to class_init
513 if (cl.is_compact) {
514 Report.error (c.source_reference, "static constructors are not supported in compact classes");
515 c.error = true;
516 return;
519 push_context (class_init_context);
521 c.body.emit (this);
523 if (current_method_inner_error) {
524 /* always separate error parameter and inner_error local variable
525 * as error may be set to NULL but we're always interested in inner errors
527 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
530 pop_context ();
531 } else {
532 Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
535 pop_line ();
538 public override string get_dynamic_property_getter_cname (DynamicProperty prop) {
539 if (prop.dynamic_type.data_type == null
540 || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
541 return base.get_dynamic_property_getter_cname (prop);
544 string getter_cname = "_dynamic_get_%s%d".printf (prop.name, dynamic_property_id++);
546 var func = new CCodeFunction (getter_cname, get_ccode_name (prop.property_type));
547 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
549 func.add_parameter (new CCodeParameter ("obj", get_ccode_name (prop.dynamic_type)));
551 push_function (func);
553 ccode.add_declaration (get_ccode_name (prop.property_type), new CCodeVariableDeclarator ("result"));
555 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
556 call.add_argument (new CCodeIdentifier ("obj"));
557 call.add_argument (get_property_canonical_cconstant (prop));
558 call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
559 call.add_argument (new CCodeConstant ("NULL"));
561 ccode.add_expression (call);
563 ccode.add_return (new CCodeIdentifier ("result"));
565 pop_function ();
567 // append to C source file
568 cfile.add_function_declaration (func);
569 cfile.add_function (func);
571 return getter_cname;
574 public override string get_dynamic_property_setter_cname (DynamicProperty prop) {
575 if (prop.dynamic_type.data_type == null
576 || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
577 return base.get_dynamic_property_setter_cname (prop);
580 string setter_cname = "_dynamic_set_%s%d".printf (prop.name, dynamic_property_id++);
582 var func = new CCodeFunction (setter_cname, "void");
583 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
584 func.add_parameter (new CCodeParameter ("obj", get_ccode_name (prop.dynamic_type)));
585 func.add_parameter (new CCodeParameter ("value", get_ccode_name (prop.property_type)));
587 push_function (func);
589 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
590 call.add_argument (new CCodeIdentifier ("obj"));
591 call.add_argument (get_property_canonical_cconstant (prop));
592 call.add_argument (new CCodeIdentifier ("value"));
593 call.add_argument (new CCodeConstant ("NULL"));
595 ccode.add_expression (call);
597 pop_function ();
599 // append to C source file
600 cfile.add_function_declaration (func);
601 cfile.add_function (func);
603 return setter_cname;
606 public override string get_dynamic_signal_cname (DynamicSignal node) {
607 return "dynamic_%s%d_".printf (node.name, signal_wrapper_id++);
610 public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig) {
611 if (sig.dynamic_type.data_type == null
612 || !sig.dynamic_type.data_type.is_subtype_of (gobject_type)) {
613 return base.get_dynamic_signal_connect_wrapper_name (sig);
616 string connect_wrapper_name = "_%sconnect".printf (get_dynamic_signal_cname (sig));
617 var func = new CCodeFunction (connect_wrapper_name, "gulong");
618 func.add_parameter (new CCodeParameter ("obj", "gpointer"));
619 func.add_parameter (new CCodeParameter ("signal_name", "const char *"));
620 func.add_parameter (new CCodeParameter ("handler", "GCallback"));
621 func.add_parameter (new CCodeParameter ("data", "gpointer"));
622 push_function (func);
623 generate_gobject_connect_wrapper (sig, false);
624 pop_function ();
626 // append to C source file
627 cfile.add_function_declaration (func);
628 cfile.add_function (func);
630 return connect_wrapper_name;
633 public override string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal sig) {
634 if (sig.dynamic_type.data_type == null
635 || !sig.dynamic_type.data_type.is_subtype_of (gobject_type)) {
636 return base.get_dynamic_signal_connect_wrapper_name (sig);
639 string connect_wrapper_name = "_%sconnect_after".printf (get_dynamic_signal_cname (sig));
640 var func = new CCodeFunction (connect_wrapper_name, "gulong");
641 func.add_parameter (new CCodeParameter ("obj", "gpointer"));
642 func.add_parameter (new CCodeParameter ("signal_name", "const char *"));
643 func.add_parameter (new CCodeParameter ("handler", "GCallback"));
644 func.add_parameter (new CCodeParameter ("data", "gpointer"));
645 push_function (func);
646 generate_gobject_connect_wrapper (sig, true);
647 pop_function ();
649 // append to C source file
650 cfile.add_function_declaration (func);
651 cfile.add_function (func);
653 return connect_wrapper_name;
656 void generate_gobject_connect_wrapper (DynamicSignal sig, bool after) {
657 var m = (Method) sig.handler.symbol_reference;
659 sig.accept (this);
661 string connect_func = "g_signal_connect_object";
662 if (m.binding != MemberBinding.INSTANCE) {
663 if (!after)
664 connect_func = "g_signal_connect";
665 else
666 connect_func = "g_signal_connect_after";
669 var call = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
670 call.add_argument (new CCodeIdentifier ("obj"));
671 call.add_argument (new CCodeIdentifier ("signal_name"));
672 call.add_argument (new CCodeIdentifier ("handler"));
673 call.add_argument (new CCodeIdentifier ("data"));
675 if (m.binding == MemberBinding.INSTANCE) {
676 if (!after) {
677 call.add_argument (new CCodeConstant ("0"));
678 } else {
679 call.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
683 ccode.add_return (call);
686 public override void visit_property (Property prop) {
687 base.visit_property (prop);
689 if (is_gobject_property (prop) && prop.parent_symbol is Class) {
690 prop_enum.add_value (new CCodeEnumValue ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
694 public override bool is_gobject_property (Property prop) {
695 var type_sym = prop.parent_symbol as ObjectTypeSymbol;
696 if (type_sym == null || !type_sym.is_subtype_of (gobject_type)) {
697 return false;
700 if (prop.binding != MemberBinding.INSTANCE) {
701 return false;
704 if (prop.access == SymbolAccessibility.PRIVATE) {
705 return false;
708 if (!has_valid_gobject_property_type (prop)) {
709 return false;
712 if (type_sym is Class && prop.base_interface_property != null &&
713 !is_gobject_property (prop.base_interface_property)) {
714 return false;
717 if (!prop.name[0].isalpha ()) {
718 // GObject requires properties to start with a letter
719 return false;
722 if (type_sym is Interface && !prop.is_abstract && !prop.external && !prop.external_package) {
723 // GObject does not support non-abstract interface properties,
724 // however we assume external properties always are GObject properties
725 return false;
728 if (type_sym is Interface && type_sym.get_attribute ("DBus") != null) {
729 // GObject properties not currently supported in D-Bus interfaces
730 return false;
733 return true;
736 bool has_valid_gobject_property_type (Property prop) {
737 var st = prop.property_type.data_type as Struct;
738 if (st != null && (!get_ccode_has_type_id (st) || prop.property_type.nullable)) {
739 return false;
742 if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.data_type != string_type.data_type) {
743 return false;
746 var d = prop.property_type as DelegateType;
747 if (d != null && d.delegate_symbol.has_target) {
748 return false;
751 return true;
754 public override void visit_method_call (MethodCall expr) {
755 if (expr.call is MemberAccess) {
756 push_line (expr.source_reference);
758 var ma = expr.call as MemberAccess;
759 if (ma.inner != null && ma.inner.symbol_reference == gobject_type &&
760 (ma.member_name == "new" || ma.member_name == "newv"
761 || ma.member_name == "new_valist" || ma.member_name == "new_with_properties")) {
762 // Object.new (...) creation
763 // runtime check to ref_sink the instance if it's a floating type
764 base.visit_method_call (expr);
766 var initiallyunowned_ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_INITIALLY_UNOWNED"));
767 initiallyunowned_ccall.add_argument (get_cvalue (expr));
768 var sink_ref_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
769 sink_ref_ccall.add_argument (get_cvalue (expr));
770 var cexpr = new CCodeConditionalExpression (initiallyunowned_ccall, sink_ref_ccall, get_cvalue (expr));
772 expr.target_value = store_temp_value (new GLibValue (expr.value_type, cexpr), expr);
773 return;
774 } else if (ma.symbol_reference == gobject_type) {
775 // Object (...) chain up
776 // check it's only used with valid properties
777 foreach (var arg in expr.get_argument_list ()) {
778 var named_argument = arg as NamedArgument;
779 if (named_argument == null) {
780 Report.error (arg.source_reference, "Named argument expected");
781 break;
783 var prop = SemanticAnalyzer.symbol_lookup_inherited (current_class, named_argument.name) as Property;
784 if (prop == null) {
785 Report.error (arg.source_reference, "Property `%s' not found in `%s'".printf (named_argument.name, current_class.get_full_name ()));
786 break;
788 if (!is_gobject_property (prop)) {
789 Report.error (arg.source_reference, "Property `%s' not supported in Object (property: value) constructor chain up".printf (named_argument.name));
790 break;
792 if (!arg.value_type.compatible (prop.property_type)) {
793 Report.error (arg.source_reference, "Cannot convert from `%s' to `%s'".printf (arg.value_type.to_string (), prop.property_type.to_string ()));
794 break;
799 pop_line ();
802 base.visit_method_call (expr);