codegen: Add get_field_cvalue and load_field
[vala-lang.git] / codegen / valagobjectmodule.vala
blob34db16c86c52cabcc960354cf06be3beef8b327e
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 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
38 add_get_property_function (cl);
40 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
41 add_set_property_function (cl);
45 public override void generate_class_init (Class cl) {
46 if (!cl.is_subtype_of (gobject_type)) {
47 return;
50 /* set property handlers */
51 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
52 ccall.add_argument (new CCodeIdentifier ("klass"));
53 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
54 ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("_vala_%s_get_property".printf (cl.get_lower_case_cname (null))));
56 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
57 ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("_vala_%s_set_property".printf (cl.get_lower_case_cname (null))));
60 /* set constructor */
61 if (cl.constructor != null) {
62 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
63 ccast.add_argument (new CCodeIdentifier ("klass"));
64 ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%s_constructor".printf (cl.get_lower_case_cname (null))));
67 /* set finalize function */
68 if (cl.get_fields ().size > 0 || cl.destructor != null) {
69 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
70 ccast.add_argument (new CCodeIdentifier ("klass"));
71 ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "finalize"), new CCodeIdentifier ("%s_finalize".printf (cl.get_lower_case_cname (null))));
74 /* create type, dup_func, and destroy_func properties for generic types */
75 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
76 string func_name, enum_value;
77 CCodeConstant func_name_constant;
78 CCodeFunctionCall cinst, cspec;
80 func_name = "%s_type".printf (type_param.name.down ());
81 func_name_constant = new CCodeConstant ("\"%s-type\"".printf (type_param.name.down ()));
82 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
83 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
84 cinst.add_argument (ccall);
85 cinst.add_argument (new CCodeConstant (enum_value));
86 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_gtype"));
87 cspec.add_argument (func_name_constant);
88 cspec.add_argument (new CCodeConstant ("\"type\""));
89 cspec.add_argument (new CCodeConstant ("\"type\""));
90 cspec.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
91 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
92 cinst.add_argument (cspec);
93 ccode.add_expression (cinst);
94 prop_enum.add_value (new CCodeEnumValue (enum_value));
97 func_name = "%s_dup_func".printf (type_param.name.down ());
98 func_name_constant = new CCodeConstant ("\"%s-dup-func\"".printf (type_param.name.down ()));
99 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
100 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
101 cinst.add_argument (ccall);
102 cinst.add_argument (new CCodeConstant (enum_value));
103 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
104 cspec.add_argument (func_name_constant);
105 cspec.add_argument (new CCodeConstant ("\"dup func\""));
106 cspec.add_argument (new CCodeConstant ("\"dup func\""));
107 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
108 cinst.add_argument (cspec);
109 ccode.add_expression (cinst);
110 prop_enum.add_value (new CCodeEnumValue (enum_value));
113 func_name = "%s_destroy_func".printf (type_param.name.down ());
114 func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
115 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
116 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
117 cinst.add_argument (ccall);
118 cinst.add_argument (new CCodeConstant (enum_value));
119 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
120 cspec.add_argument (func_name_constant);
121 cspec.add_argument (new CCodeConstant ("\"destroy func\""));
122 cspec.add_argument (new CCodeConstant ("\"destroy func\""));
123 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
124 cinst.add_argument (cspec);
125 ccode.add_expression (cinst);
126 prop_enum.add_value (new CCodeEnumValue (enum_value));
129 /* create properties */
130 var props = cl.get_properties ();
131 foreach (Property prop in props) {
132 if (!is_gobject_property (prop)) {
133 continue;
136 if (prop.comment != null) {
137 ccode.add_statement (new CCodeComment (prop.comment.content));
140 if (prop.overrides || prop.base_interface_property != null) {
141 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_override_property"));
142 cinst.add_argument (ccall);
143 cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
144 cinst.add_argument (prop.get_canonical_cconstant ());
146 ccode.add_expression (cinst);
147 } else {
148 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
149 cinst.add_argument (ccall);
150 cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
151 cinst.add_argument (get_param_spec (prop));
153 ccode.add_expression (cinst);
158 private bool class_has_readable_properties (Class cl) {
159 foreach (Property prop in cl.get_properties ()) {
160 if (prop.get_accessor != null) {
161 return true;
164 return false;
167 private bool class_has_writable_properties (Class cl) {
168 foreach (Property prop in cl.get_properties ()) {
169 if (prop.set_accessor != null) {
170 return true;
173 return false;
176 private void add_get_property_function (Class cl) {
177 var get_prop = new CCodeFunction ("_vala_%s_get_property".printf (cl.get_lower_case_cname (null)), "void");
178 get_prop.modifiers = CCodeModifiers.STATIC;
179 get_prop.add_parameter (new CCodeParameter ("object", "GObject *"));
180 get_prop.add_parameter (new CCodeParameter ("property_id", "guint"));
181 get_prop.add_parameter (new CCodeParameter ("value", "GValue *"));
182 get_prop.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
184 var block = new CCodeBlock ();
186 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
187 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
188 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
189 block.add_statement (cdecl);
191 int boxed_name_id = 0;
192 bool length_declared = false;
194 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
195 var props = cl.get_properties ();
196 foreach (Property prop in props) {
197 if (prop.get_accessor == null || prop.is_abstract) {
198 continue;
200 if (!is_gobject_property (prop)) {
201 // don't register private properties
202 continue;
205 Property base_prop = prop;
206 CCodeExpression cself = new CCodeIdentifier ("self");
207 if (prop.base_property != null) {
208 var base_type = (Class) prop.base_property.parent_symbol;
209 base_prop = prop.base_property;
210 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
212 generate_property_accessor_declaration (prop.base_property.get_accessor, cfile);
213 } else if (prop.base_interface_property != null) {
214 var base_type = (Interface) prop.base_interface_property.parent_symbol;
215 base_prop = prop.base_interface_property;
216 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
218 generate_property_accessor_declaration (prop.base_interface_property.get_accessor, cfile);
221 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ())));
222 if (prop.property_type.is_real_struct_type ()) {
223 var st = prop.property_type.data_type as Struct;
224 var boxed = "boxed%d".printf (boxed_name_id++);
226 cdecl = new CCodeDeclaration (st.get_cname ());
227 cdecl.add_declarator (new CCodeVariableDeclarator (boxed));
228 block.add_statement (cdecl);
230 ccall = new CCodeFunctionCall (new CCodeIdentifier (base_prop.get_accessor.get_cname ()));
231 ccall.add_argument (cself);
232 var boxed_addr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (boxed));
233 ccall.add_argument (boxed_addr);
234 cswitch.add_statement (new CCodeExpressionStatement (ccall));
236 var csetcall = new CCodeFunctionCall ();
237 csetcall.call = get_value_setter_function (prop.property_type);
238 csetcall.add_argument (new CCodeIdentifier ("value"));
239 csetcall.add_argument (boxed_addr);
240 cswitch.add_statement (new CCodeExpressionStatement (csetcall));
242 if (requires_destroy (prop.get_accessor.value_type)) {
243 cswitch.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (boxed), prop.get_accessor.value_type, null)));
245 } else {
246 ccall = new CCodeFunctionCall (new CCodeIdentifier (base_prop.get_accessor.get_cname ()));
247 ccall.add_argument (cself);
248 var array_type = prop.property_type as ArrayType;
249 if (array_type != null && array_type.element_type.data_type == string_type.data_type) {
250 // G_TYPE_STRV
251 if (!length_declared) {
252 cdecl = new CCodeDeclaration ("int");
253 cdecl.add_declarator (new CCodeVariableDeclarator ("length"));
254 block.add_statement (cdecl);
255 length_declared = true;
257 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("length")));
259 var csetcall = new CCodeFunctionCall ();
260 if (prop.get_accessor.value_type.value_owned) {
261 csetcall.call = get_value_taker_function (prop.property_type);
262 } else {
263 csetcall.call = get_value_setter_function (prop.property_type);
265 csetcall.add_argument (new CCodeIdentifier ("value"));
266 csetcall.add_argument (ccall);
267 cswitch.add_statement (new CCodeExpressionStatement (csetcall));
269 cswitch.add_statement (new CCodeBreakStatement ());
271 cswitch.add_statement (new CCodeLabel ("default"));
272 cswitch.add_statement (get_invalid_property_id_warn_statement ());
273 cswitch.add_statement (new CCodeBreakStatement ());
275 block.add_statement (cswitch);
277 cfile.add_function_declaration (get_prop);
279 get_prop.block = block;
281 cfile.add_function (get_prop);
284 private void add_set_property_function (Class cl) {
285 var set_prop = new CCodeFunction ("_vala_%s_set_property".printf (cl.get_lower_case_cname (null)), "void");
286 set_prop.modifiers = CCodeModifiers.STATIC;
287 set_prop.add_parameter (new CCodeParameter ("object", "GObject *"));
288 set_prop.add_parameter (new CCodeParameter ("property_id", "guint"));
289 set_prop.add_parameter (new CCodeParameter ("value", "const GValue *"));
290 set_prop.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
292 var block = new CCodeBlock ();
294 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
295 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
296 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
297 block.add_statement (cdecl);
299 var boxed_declared = false;
301 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
302 var props = cl.get_properties ();
303 foreach (Property prop in props) {
304 if (prop.set_accessor == null || prop.is_abstract) {
305 continue;
307 if (!is_gobject_property (prop)) {
308 continue;
311 Property base_prop = prop;
312 CCodeExpression cself = new CCodeIdentifier ("self");
313 if (prop.base_property != null) {
314 var base_type = (Class) prop.base_property.parent_symbol;
315 base_prop = prop.base_property;
316 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
318 generate_property_accessor_declaration (prop.base_property.set_accessor, cfile);
319 } else if (prop.base_interface_property != null) {
320 var base_type = (Interface) prop.base_interface_property.parent_symbol;
321 base_prop = prop.base_interface_property;
322 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
324 generate_property_accessor_declaration (prop.base_interface_property.set_accessor, cfile);
327 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ())));
328 ccall = new CCodeFunctionCall (new CCodeIdentifier (base_prop.set_accessor.get_cname ()));
329 ccall.add_argument (cself);
330 if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.data_type == string_type.data_type) {
331 if (!boxed_declared) {
332 cdecl = new CCodeDeclaration ("gpointer");
333 cdecl.add_declarator (new CCodeVariableDeclarator ("boxed"));
334 block.add_statement (cdecl);
335 boxed_declared = true;
337 var cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_boxed"));
338 cgetcall.add_argument (new CCodeIdentifier ("value"));
339 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("boxed"), cgetcall)));
340 ccall.add_argument (new CCodeIdentifier ("boxed"));
342 var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
343 cstrvlen.add_argument (new CCodeIdentifier ("boxed"));
344 ccall.add_argument (cstrvlen);
345 } else {
346 var cgetcall = new CCodeFunctionCall ();
347 if (prop.property_type.data_type != null) {
348 cgetcall.call = new CCodeIdentifier (prop.property_type.data_type.get_get_value_function ());
349 } else {
350 cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
352 cgetcall.add_argument (new CCodeIdentifier ("value"));
353 ccall.add_argument (cgetcall);
355 cswitch.add_statement (new CCodeExpressionStatement (ccall));
356 cswitch.add_statement (new CCodeBreakStatement ());
358 cswitch.add_statement (new CCodeLabel ("default"));
359 cswitch.add_statement (get_invalid_property_id_warn_statement ());
360 cswitch.add_statement (new CCodeBreakStatement ());
362 block.add_statement (cswitch);
364 /* type, dup func, and destroy func properties for generic types */
365 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
366 string func_name, enum_value;
367 CCodeMemberAccess cfield;
368 CCodeFunctionCall cgetcall;
370 func_name = "%s_type".printf (type_param.name.down ());
371 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
372 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
373 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
374 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_gtype"));
375 cgetcall.add_argument (new CCodeIdentifier ("value"));
376 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
377 cswitch.add_statement (new CCodeBreakStatement ());
379 func_name = "%s_dup_func".printf (type_param.name.down ());
380 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
381 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
382 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
383 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
384 cgetcall.add_argument (new CCodeIdentifier ("value"));
385 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
386 cswitch.add_statement (new CCodeBreakStatement ());
388 func_name = "%s_destroy_func".printf (type_param.name.down ());
389 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
390 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
391 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
392 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
393 cgetcall.add_argument (new CCodeIdentifier ("value"));
394 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
395 cswitch.add_statement (new CCodeBreakStatement ());
398 cfile.add_function_declaration (set_prop);
400 set_prop.block = block;
402 cfile.add_function (set_prop);
405 private CCodeStatement get_invalid_property_id_warn_statement () {
406 // warn on invalid property id
407 var cwarn = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
408 cwarn.add_argument (new CCodeIdentifier ("object"));
409 cwarn.add_argument (new CCodeIdentifier ("property_id"));
410 cwarn.add_argument (new CCodeIdentifier ("pspec"));
411 return new CCodeExpressionStatement (cwarn);
414 public override void visit_constructor (Constructor c) {
415 if (c.binding == MemberBinding.CLASS || c.binding == MemberBinding.STATIC) {
416 in_static_or_class_context = true;
417 } else {
418 in_constructor = true;
421 var cl = (Class) c.parent_symbol;
423 if (c.binding == MemberBinding.INSTANCE) {
424 if (!cl.is_subtype_of (gobject_type)) {
425 Report.error (c.source_reference, "construct blocks require GLib.Object");
426 c.error = true;
427 return;
430 push_context (new EmitContext (c));
432 var function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
433 function.modifiers = CCodeModifiers.STATIC;
435 function.add_parameter (new CCodeParameter ("type", "GType"));
436 function.add_parameter (new CCodeParameter ("n_construct_properties", "guint"));
437 function.add_parameter (new CCodeParameter ("construct_properties", "GObjectConstructParam *"));
439 cfile.add_function_declaration (function);
441 push_function (function);
443 ccode.add_declaration ("GObject *", new CCodeVariableDeclarator ("obj"));
444 ccode.add_declaration ("GObjectClass *", new CCodeVariableDeclarator ("parent_class"));
446 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
447 ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (cl.get_lower_case_cname (null))));
448 ccode.add_assignment (new CCodeIdentifier ("parent_class"), ccast);
450 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
451 ccall.add_argument (new CCodeIdentifier ("type"));
452 ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
453 ccall.add_argument (new CCodeIdentifier ("construct_properties"));
454 ccode.add_assignment (new CCodeIdentifier ("obj"), ccall);
457 ccall = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
459 ccode.add_declaration ("%s *".printf (cl.get_cname ()), new CCodeVariableDeclarator ("self"));
460 ccode.add_assignment (new CCodeIdentifier ("self"), ccall);
462 c.body.emit (this);
464 if (current_method_inner_error) {
465 /* always separate error parameter and inner_error local variable
466 * as error may be set to NULL but we're always interested in inner errors
468 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
471 ccode.add_return (new CCodeIdentifier ("obj"));
473 pop_function ();
474 cfile.add_function (function);
476 pop_context ();
477 } else if (c.binding == MemberBinding.CLASS) {
478 // class constructor
480 if (cl.is_compact) {
481 Report.error (c.source_reference, "class constructors are not supported in compact classes");
482 c.error = true;
483 return;
486 push_context (base_init_context);
488 c.body.emit (this);
490 if (current_method_inner_error) {
491 /* always separate error parameter and inner_error local variable
492 * as error may be set to NULL but we're always interested in inner errors
494 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
497 pop_context ();
498 } else if (c.binding == MemberBinding.STATIC) {
499 // static class constructor
500 // add to class_init
502 if (cl.is_compact) {
503 Report.error (c.source_reference, "static constructors are not supported in compact classes");
504 c.error = true;
505 return;
508 push_context (class_init_context);
510 c.body.emit (this);
512 if (current_method_inner_error) {
513 /* always separate error parameter and inner_error local variable
514 * as error may be set to NULL but we're always interested in inner errors
516 ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("_inner_error_", new CCodeConstant ("NULL")));
519 pop_context ();
520 } else {
521 Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
524 in_static_or_class_context = false;
526 in_constructor = false;
529 public override string get_dynamic_property_getter_cname (DynamicProperty prop) {
530 if (prop.dynamic_type.data_type == null
531 || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
532 return base.get_dynamic_property_getter_cname (prop);
535 string getter_cname = "_dynamic_get_%s%d".printf (prop.name, dynamic_property_id++);
537 var func = new CCodeFunction (getter_cname, prop.property_type.get_cname ());
538 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
540 func.add_parameter (new CCodeParameter ("obj", prop.dynamic_type.get_cname ()));
542 var block = new CCodeBlock ();
543 generate_gobject_property_getter_wrapper (prop, block);
545 // append to C source file
546 cfile.add_function_declaration (func);
548 func.block = block;
549 cfile.add_function (func);
551 return getter_cname;
554 public override string get_dynamic_property_setter_cname (DynamicProperty prop) {
555 if (prop.dynamic_type.data_type == null
556 || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
557 return base.get_dynamic_property_setter_cname (prop);
560 string setter_cname = "_dynamic_set_%s%d".printf (prop.name, dynamic_property_id++);
562 var func = new CCodeFunction (setter_cname, "void");
563 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
565 func.add_parameter (new CCodeParameter ("obj", prop.dynamic_type.get_cname ()));
566 func.add_parameter (new CCodeParameter ("value", prop.property_type.get_cname ()));
568 var block = new CCodeBlock ();
569 generate_gobject_property_setter_wrapper (prop, block);
571 // append to C source file
572 cfile.add_function_declaration (func);
574 func.block = block;
575 cfile.add_function (func);
577 return setter_cname;
580 void generate_gobject_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
581 var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
582 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
583 block.add_statement (cdecl);
585 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
586 call.add_argument (new CCodeIdentifier ("obj"));
587 call.add_argument (node.get_canonical_cconstant ());
588 call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
589 call.add_argument (new CCodeConstant ("NULL"));
591 block.add_statement (new CCodeExpressionStatement (call));
593 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
596 void generate_gobject_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
597 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
598 call.add_argument (new CCodeIdentifier ("obj"));
599 call.add_argument (node.get_canonical_cconstant ());
600 call.add_argument (new CCodeIdentifier ("value"));
601 call.add_argument (new CCodeConstant ("NULL"));
603 block.add_statement (new CCodeExpressionStatement (call));
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, "void");
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 var block = new CCodeBlock ();
623 generate_gobject_connect_wrapper (sig, block, false);
625 // append to C source file
626 cfile.add_function_declaration (func);
628 func.block = block;
629 cfile.add_function (func);
631 return connect_wrapper_name;
634 public override string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal sig) {
635 if (sig.dynamic_type.data_type == null
636 || !sig.dynamic_type.data_type.is_subtype_of (gobject_type)) {
637 return base.get_dynamic_signal_connect_wrapper_name (sig);
640 string connect_wrapper_name = "_%sconnect_after".printf (get_dynamic_signal_cname (sig));
641 var func = new CCodeFunction (connect_wrapper_name, "void");
642 func.add_parameter (new CCodeParameter ("obj", "gpointer"));
643 func.add_parameter (new CCodeParameter ("signal_name", "const char *"));
644 func.add_parameter (new CCodeParameter ("handler", "GCallback"));
645 func.add_parameter (new CCodeParameter ("data", "gpointer"));
646 var block = new CCodeBlock ();
647 generate_gobject_connect_wrapper (sig, block, true);
649 // append to C source file
650 cfile.add_function_declaration (func);
652 func.block = block;
653 cfile.add_function (func);
655 return connect_wrapper_name;
658 void generate_gobject_connect_wrapper (DynamicSignal sig, CCodeBlock block, bool after) {
659 var m = (Method) sig.handler.symbol_reference;
661 sig.accept (this);
663 string connect_func = "g_signal_connect_object";
664 if (m.binding != MemberBinding.INSTANCE) {
665 if (!after)
666 connect_func = "g_signal_connect";
667 else
668 connect_func = "g_signal_connect_after";
671 var call = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
672 call.add_argument (new CCodeIdentifier ("obj"));
673 call.add_argument (new CCodeIdentifier ("signal_name"));
674 call.add_argument (new CCodeIdentifier ("handler"));
675 call.add_argument (new CCodeIdentifier ("data"));
677 if (m.binding == MemberBinding.INSTANCE) {
678 if (!after)
679 call.add_argument (new CCodeConstant ("0"));
680 else
681 call.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
684 block.add_statement (new CCodeExpressionStatement (call));
687 public override void visit_property (Property prop) {
688 base.visit_property (prop);
690 if (is_gobject_property (prop) && prop.parent_symbol is Class) {
691 prop_enum.add_value (new CCodeEnumValue (prop.get_upper_case_cname ()));
695 public override bool is_gobject_property (Property prop) {
696 var type_sym = prop.parent_symbol as ObjectTypeSymbol;
697 if (type_sym == null || !type_sym.is_subtype_of (gobject_type)) {
698 return false;
701 if (prop.binding != MemberBinding.INSTANCE) {
702 return false;
705 if (prop.access == SymbolAccessibility.PRIVATE) {
706 return false;
709 var st = prop.property_type.data_type as Struct;
710 if (st != null && (!st.has_type_id || prop.property_type.nullable)) {
711 return false;
714 if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.data_type != string_type.data_type) {
715 return false;
718 var d = prop.property_type as DelegateType;
719 if (d != null && d.delegate_symbol.has_target) {
720 return false;
723 if (type_sym is Class && prop.base_interface_property != null &&
724 !is_gobject_property (prop.base_interface_property)) {
725 return false;
728 if (!prop.name[0].isalpha ()) {
729 // GObject requires properties to start with a letter
730 return false;
733 if (type_sym is Interface && type_sym.get_attribute ("DBus") != null) {
734 // GObject properties not currently supported in D-Bus interfaces
735 return false;
738 return true;
741 public override void visit_method_call (MethodCall expr) {
742 if (expr.call is MemberAccess) {
743 var ma = expr.call as MemberAccess;
744 if (ma.inner != null && ma.inner.symbol_reference == gobject_type &&
745 (ma.member_name == "new" || ma.member_name == "newv")) {
746 // Object.new (...) creation
747 // runtime check to ref_sink the instance if it's a floating type
748 base.visit_method_call (expr);
750 var ccomma = new CCodeCommaExpression ();
751 var temp_var = get_temp_variable (expr.value_type, false, expr, false);
752 emit_temp_var (temp_var);
753 ccomma.append_expression (new CCodeAssignment (get_variable_cexpression (temp_var.name), get_cvalue (expr)));
755 var initiallyunowned_ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_INITIALLY_UNOWNED"));
756 initiallyunowned_ccall.add_argument (get_variable_cexpression (temp_var.name));
757 var sink_ref_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
758 sink_ref_ccall.add_argument (get_variable_cexpression (temp_var.name));
759 ccomma.append_expression (new CCodeConditionalExpression (initiallyunowned_ccall, sink_ref_ccall, get_variable_cexpression (temp_var.name)));
761 set_cvalue (expr, ccomma);
762 return;
763 } else if (ma.symbol_reference == gobject_type) {
764 // Object (...) chain up
765 // check it's only used with valid properties
766 foreach (var arg in expr.get_argument_list ()) {
767 var named_argument = arg as NamedArgument;
768 if (named_argument == null) {
769 Report.error (arg.source_reference, "Named argument expected");
770 break;
772 var prop = SemanticAnalyzer.symbol_lookup_inherited (current_class, named_argument.name) as Property;
773 if (prop == null) {
774 Report.error (arg.source_reference, "Property `%s' not found in `%s'".printf (named_argument.name, current_class.get_full_name ()));
775 break;
777 if (!is_gobject_property (prop)) {
778 Report.error (arg.source_reference, "Property `%s' not supported in Object (property: value) constructor chain up".printf (named_argument.name));
779 break;
781 if (!arg.value_type.compatible (prop.property_type)) {
782 Report.error (arg.source_reference, "Cannot convert from `%s' to `%s'".printf (arg.value_type.to_string (), prop.property_type.to_string ()));
783 break;
789 base.visit_method_call (expr);