gtk+-2.0: Do not use const with GtkTreePath
[vala-lang.git] / codegen / valagobjectmodule.vala
blob94152996c6e32374b1966bfc41d7699d03c20d3a
1 /* valagobjectmodule.vala
3 * Copyright (C) 2006-2009 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>
25 using Gee;
27 internal class Vala.GObjectModule : GTypeModule {
28 int dynamic_property_id;
29 int signal_wrapper_id;
31 public GObjectModule (CCodeGenerator codegen, CCodeModule? next) {
32 base (codegen, next);
35 public override void visit_class (Class cl) {
36 base.visit_class (cl);
38 if (!cl.is_subtype_of (gobject_type)) {
39 return;
42 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
43 add_get_property_function (cl);
45 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
46 add_set_property_function (cl);
50 public override void generate_class_init (Class cl, CCodeBlock init_block) {
51 if (!cl.is_subtype_of (gobject_type)) {
52 return;
55 /* set property handlers */
56 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
57 ccall.add_argument (new CCodeIdentifier ("klass"));
58 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
59 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("%s_get_property".printf (cl.get_lower_case_cname (null))))));
61 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
62 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("%s_set_property".printf (cl.get_lower_case_cname (null))))));
65 /* set constructor */
66 if (cl.constructor != null) {
67 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
68 ccast.add_argument (new CCodeIdentifier ("klass"));
69 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%s_constructor".printf (cl.get_lower_case_cname (null))))));
72 /* set finalize function */
73 if (cl.get_fields ().size > 0 || cl.destructor != null) {
74 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
75 ccast.add_argument (new CCodeIdentifier ("klass"));
76 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "finalize"), new CCodeIdentifier ("%s_finalize".printf (cl.get_lower_case_cname (null))))));
79 /* create type, dup_func, and destroy_func properties for generic types */
80 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
81 string func_name, enum_value;
82 CCodeConstant func_name_constant;
83 CCodeFunctionCall cinst, cspec;
85 func_name = "%s_type".printf (type_param.name.down ());
86 func_name_constant = new CCodeConstant ("\"%s-type\"".printf (type_param.name.down ()));
87 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).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_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
97 cinst.add_argument (cspec);
98 init_block.add_statement (new CCodeExpressionStatement (cinst));
99 prop_enum.add_value (new CCodeEnumValue (enum_value));
102 func_name = "%s_dup_func".printf (type_param.name.down ());
103 func_name_constant = new CCodeConstant ("\"%s-dup-func\"".printf (type_param.name.down ()));
104 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).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_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
113 cinst.add_argument (cspec);
114 init_block.add_statement (new CCodeExpressionStatement (cinst));
115 prop_enum.add_value (new CCodeEnumValue (enum_value));
118 func_name = "%s_destroy_func".printf (type_param.name.down ());
119 func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
120 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).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_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
129 cinst.add_argument (cspec);
130 init_block.add_statement (new CCodeExpressionStatement (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 continue;
141 if (prop.overrides || prop.base_interface_property != null) {
142 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_override_property"));
143 cinst.add_argument (ccall);
144 cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
145 cinst.add_argument (prop.get_canonical_cconstant ());
147 init_block.add_statement (new CCodeExpressionStatement (cinst));
148 } else {
149 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
150 cinst.add_argument (ccall);
151 cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
152 cinst.add_argument (head.get_param_spec (prop));
154 init_block.add_statement (new CCodeExpressionStatement (cinst));
159 private bool class_has_readable_properties (Class cl) {
160 foreach (Property prop in cl.get_properties ()) {
161 if (prop.get_accessor != null) {
162 return true;
165 return false;
168 private bool class_has_writable_properties (Class cl) {
169 foreach (Property prop in cl.get_properties ()) {
170 if (prop.set_accessor != null) {
171 return true;
174 return false;
177 private void add_get_property_function (Class cl) {
178 var get_prop = new CCodeFunction ("%s_get_property".printf (cl.get_lower_case_cname (null)), "void");
179 get_prop.modifiers = CCodeModifiers.STATIC;
180 get_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
181 get_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
182 get_prop.add_parameter (new CCodeFormalParameter ("value", "GValue *"));
183 get_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
185 var block = new CCodeBlock ();
187 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
188 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
189 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
190 block.add_statement (cdecl);
192 bool boxed_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 string prefix = cl.get_lower_case_cname (null);
206 CCodeExpression cself = new CCodeIdentifier ("self");
207 if (prop.base_property != null) {
208 var base_type = (Class) prop.base_property.parent_symbol;
209 prefix = base_type.get_lower_case_cname (null);
210 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
212 generate_property_accessor_declaration (prop.base_property.get_accessor, source_declarations);
213 } else if (prop.base_interface_property != null) {
214 var base_type = (Interface) prop.base_interface_property.parent_symbol;
215 prefix = base_type.get_lower_case_cname (null);
216 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
218 generate_property_accessor_declaration (prop.base_interface_property.get_accessor, source_declarations);
221 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ())));
222 if (prop.property_type.is_real_struct_type ()) {
223 if (!boxed_declared) {
224 cdecl = new CCodeDeclaration ("gpointer");
225 cdecl.add_declarator (new CCodeVariableDeclarator ("boxed"));
226 block.add_statement (cdecl);
227 boxed_declared = true;
230 var st = prop.property_type.data_type as Struct;
231 var struct_creation = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
232 struct_creation.add_argument (new CCodeIdentifier (st.get_cname ()));
233 struct_creation.add_argument (new CCodeConstant ("1"));
234 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("boxed"), struct_creation)));
235 ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
236 ccall.add_argument (cself);
237 ccall.add_argument (new CCodeIdentifier ("boxed"));
238 cswitch.add_statement (new CCodeExpressionStatement (ccall));
239 var csetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
240 csetcall.add_argument (new CCodeIdentifier ("value"));
241 csetcall.add_argument (new CCodeIdentifier ("boxed"));
242 cswitch.add_statement (new CCodeExpressionStatement (csetcall));
243 } else {
244 ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
245 ccall.add_argument (cself);
246 var csetcall = new CCodeFunctionCall ();
247 csetcall.call = head.get_value_setter_function (prop.property_type);
248 csetcall.add_argument (new CCodeIdentifier ("value"));
249 csetcall.add_argument (ccall);
250 cswitch.add_statement (new CCodeExpressionStatement (csetcall));
252 cswitch.add_statement (new CCodeBreakStatement ());
254 cswitch.add_statement (new CCodeLabel ("default"));
255 cswitch.add_statement (get_invalid_property_id_warn_statement ());
256 cswitch.add_statement (new CCodeBreakStatement ());
258 block.add_statement (cswitch);
260 source_declarations.add_type_member_declaration (get_prop.copy ());
262 get_prop.block = block;
264 source_type_member_definition.append (get_prop);
267 private void add_set_property_function (Class cl) {
268 var set_prop = new CCodeFunction ("%s_set_property".printf (cl.get_lower_case_cname (null)), "void");
269 set_prop.modifiers = CCodeModifiers.STATIC;
270 set_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
271 set_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
272 set_prop.add_parameter (new CCodeFormalParameter ("value", "const GValue *"));
273 set_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
275 var block = new CCodeBlock ();
277 CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
278 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
279 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
280 block.add_statement (cdecl);
282 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
283 var props = cl.get_properties ();
284 foreach (Property prop in props) {
285 if (prop.set_accessor == null || prop.is_abstract) {
286 continue;
288 if (!is_gobject_property (prop)) {
289 continue;
292 string prefix = cl.get_lower_case_cname (null);
293 CCodeExpression cself = new CCodeIdentifier ("self");
294 if (prop.base_property != null) {
295 var base_type = (Class) prop.base_property.parent_symbol;
296 prefix = base_type.get_lower_case_cname (null);
297 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
299 generate_property_accessor_declaration (prop.base_property.set_accessor, source_declarations);
300 } else if (prop.base_interface_property != null) {
301 var base_type = (Interface) prop.base_interface_property.parent_symbol;
302 prefix = base_type.get_lower_case_cname (null);
303 cself = transform_expression (cself, new ObjectType (cl), new ObjectType (base_type));
305 generate_property_accessor_declaration (prop.base_interface_property.set_accessor, source_declarations);
308 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ())));
309 ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_set_%s".printf (prefix, prop.name)));
310 ccall.add_argument (cself);
311 var cgetcall = new CCodeFunctionCall ();
312 if (prop.property_type.data_type != null) {
313 cgetcall.call = new CCodeIdentifier (prop.property_type.data_type.get_get_value_function ());
314 } else {
315 cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
317 cgetcall.add_argument (new CCodeIdentifier ("value"));
318 ccall.add_argument (cgetcall);
319 cswitch.add_statement (new CCodeExpressionStatement (ccall));
320 cswitch.add_statement (new CCodeBreakStatement ());
322 cswitch.add_statement (new CCodeLabel ("default"));
323 cswitch.add_statement (get_invalid_property_id_warn_statement ());
324 cswitch.add_statement (new CCodeBreakStatement ());
326 block.add_statement (cswitch);
328 /* type, dup func, and destroy func properties for generic types */
329 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
330 string func_name, enum_value;
331 CCodeMemberAccess cfield;
332 CCodeFunctionCall cgetcall;
334 func_name = "%s_type".printf (type_param.name.down ());
335 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
336 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
337 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
338 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_gtype"));
339 cgetcall.add_argument (new CCodeIdentifier ("value"));
340 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
341 cswitch.add_statement (new CCodeBreakStatement ());
343 func_name = "%s_dup_func".printf (type_param.name.down ());
344 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
345 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
346 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
347 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
348 cgetcall.add_argument (new CCodeIdentifier ("value"));
349 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
350 cswitch.add_statement (new CCodeBreakStatement ());
352 func_name = "%s_destroy_func".printf (type_param.name.down ());
353 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
354 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value)));
355 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
356 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
357 cgetcall.add_argument (new CCodeIdentifier ("value"));
358 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
359 cswitch.add_statement (new CCodeBreakStatement ());
362 source_declarations.add_type_member_declaration (set_prop.copy ());
364 set_prop.block = block;
366 source_type_member_definition.append (set_prop);
369 private CCodeStatement get_invalid_property_id_warn_statement () {
370 // warn on invalid property id
371 var cwarn = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
372 cwarn.add_argument (new CCodeIdentifier ("object"));
373 cwarn.add_argument (new CCodeIdentifier ("property_id"));
374 cwarn.add_argument (new CCodeIdentifier ("pspec"));
375 return new CCodeExpressionStatement (cwarn);
378 public override CCodeExpression get_construct_property_assignment (CCodeConstant canonical_cconstant, DataType property_type, CCodeExpression value) {
379 // this property is used as a construction parameter
380 var cpointer = new CCodeIdentifier ("__params_it");
382 var ccomma = new CCodeCommaExpression ();
383 // set name in array for current parameter
384 var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
385 var cnameassign = new CCodeAssignment (cnamemember, canonical_cconstant);
386 ccomma.append_expression (cnameassign);
388 var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
390 // initialize GValue in array for current parameter
391 var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
392 cvalueinit.add_argument (gvaluearg);
393 cvalueinit.add_argument (new CCodeIdentifier (property_type.get_type_id ()));
394 ccomma.append_expression (cvalueinit);
396 // set GValue for current parameter
397 var cvalueset = new CCodeFunctionCall (get_value_setter_function (property_type));
398 cvalueset.add_argument (gvaluearg);
399 if (property_type.is_real_struct_type ()) {
400 cvalueset.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, value));
401 } else {
402 cvalueset.add_argument (value);
404 ccomma.append_expression (cvalueset);
406 // move pointer to next parameter in array
407 ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
409 return ccomma;
412 public override void visit_constructor (Constructor c) {
413 bool old_method_inner_error = current_method_inner_error;
414 current_method_inner_error = false;
416 if (c.binding == MemberBinding.CLASS || c.binding == MemberBinding.STATIC) {
417 in_static_or_class_context = true;
418 } else {
419 in_constructor = true;
421 c.accept_children (codegen);
422 in_static_or_class_context = false;
424 in_constructor = false;
426 var cl = (Class) c.parent_symbol;
428 if (c.binding == MemberBinding.INSTANCE) {
429 if (!cl.is_subtype_of (gobject_type)) {
430 Report.error (c.source_reference, "construct blocks require GLib.Object");
431 c.error = true;
432 return;
435 function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
436 function.modifiers = CCodeModifiers.STATIC;
438 function.add_parameter (new CCodeFormalParameter ("type", "GType"));
439 function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint"));
440 function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
442 source_declarations.add_type_member_declaration (function.copy ());
445 var cblock = new CCodeBlock ();
446 var cdecl = new CCodeDeclaration ("GObject *");
447 cdecl.add_declarator (new CCodeVariableDeclarator ("obj"));
448 cblock.add_statement (cdecl);
450 cdecl = new CCodeDeclaration ("GObjectClass *");
451 cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
452 cblock.add_statement (cdecl);
455 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
456 ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (cl.get_lower_case_cname (null))));
457 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
460 var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
461 ccall.add_argument (new CCodeIdentifier ("type"));
462 ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
463 ccall.add_argument (new CCodeIdentifier ("construct_properties"));
464 cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall)));
467 ccall = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
469 cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
470 cdecl.add_declarator (new CCodeVariableDeclarator ("self", ccall));
471 cblock.add_statement (cdecl);
473 if (current_method_inner_error) {
474 /* always separate error parameter and inner_error local variable
475 * as error may be set to NULL but we're always interested in inner errors
477 cdecl = new CCodeDeclaration ("GError *");
478 cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
479 cblock.add_statement (cdecl);
483 cblock.add_statement (c.body.ccodenode);
485 cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
487 function.block = cblock;
489 source_type_member_definition.append (function);
490 } else if (c.binding == MemberBinding.CLASS) {
491 // class constructor
493 if (cl.is_compact) {
494 Report.error (c.source_reference, "class constructors are not supported in compact classes");
495 c.error = true;
496 return;
499 if (current_method_inner_error) {
500 /* always separate error parameter and inner_error local variable
501 * as error may be set to NULL but we're always interested in inner errors
503 var cdecl = new CCodeDeclaration ("GError *");
504 cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
505 base_init_fragment.append (cdecl);
508 base_init_fragment.append (c.body.ccodenode);
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 if (current_method_inner_error) {
520 /* always separate error parameter and inner_error local variable
521 * as error may be set to NULL but we're always interested in inner errors
523 var cdecl = new CCodeDeclaration ("GError *");
524 cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
525 class_init_fragment.append (cdecl);
528 class_init_fragment.append (c.body.ccodenode);
529 } else {
530 Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
533 current_method_inner_error = old_method_inner_error;
536 public override string get_dynamic_property_getter_cname (DynamicProperty prop) {
537 if (prop.dynamic_type.data_type == null
538 || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
539 return base.get_dynamic_property_getter_cname (prop);
542 string getter_cname = "_dynamic_get_%s%d".printf (prop.name, dynamic_property_id++);
544 var func = new CCodeFunction (getter_cname, prop.property_type.get_cname ());
545 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
547 func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
549 var block = new CCodeBlock ();
550 generate_gobject_property_getter_wrapper (prop, block);
552 // append to C source file
553 source_declarations.add_type_member_declaration (func.copy ());
555 func.block = block;
556 source_type_member_definition.append (func);
558 return getter_cname;
561 public override string get_dynamic_property_setter_cname (DynamicProperty prop) {
562 if (prop.dynamic_type.data_type == null
563 || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
564 return base.get_dynamic_property_setter_cname (prop);
567 string setter_cname = "_dynamic_set_%s%d".printf (prop.name, dynamic_property_id++);
569 var func = new CCodeFunction (setter_cname, "void");
570 func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
572 func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
573 func.add_parameter (new CCodeFormalParameter ("value", prop.property_type.get_cname ()));
575 var block = new CCodeBlock ();
576 generate_gobject_property_setter_wrapper (prop, block);
578 // append to C source file
579 source_declarations.add_type_member_declaration (func.copy ());
581 func.block = block;
582 source_type_member_definition.append (func);
584 return setter_cname;
587 void generate_gobject_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
588 var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
589 cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
590 block.add_statement (cdecl);
592 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
593 call.add_argument (new CCodeIdentifier ("obj"));
594 call.add_argument (node.get_canonical_cconstant ());
595 call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
596 call.add_argument (new CCodeConstant ("NULL"));
598 block.add_statement (new CCodeExpressionStatement (call));
600 block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
603 void generate_gobject_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
604 var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
605 call.add_argument (new CCodeIdentifier ("obj"));
606 call.add_argument (node.get_canonical_cconstant ());
607 call.add_argument (new CCodeIdentifier ("value"));
608 call.add_argument (new CCodeConstant ("NULL"));
610 block.add_statement (new CCodeExpressionStatement (call));
613 public override string get_dynamic_signal_cname (DynamicSignal node) {
614 return "dynamic_%s%d_".printf (node.name, signal_wrapper_id++);
617 public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig) {
618 if (sig.dynamic_type.data_type == null
619 || !sig.dynamic_type.data_type.is_subtype_of (gobject_type)) {
620 return base.get_dynamic_signal_connect_wrapper_name (sig);
623 string connect_wrapper_name = "_%sconnect".printf (get_dynamic_signal_cname (sig));
624 var func = new CCodeFunction (connect_wrapper_name, "void");
625 func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
626 func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
627 func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
628 func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
629 var block = new CCodeBlock ();
630 generate_gobject_connect_wrapper (sig, block);
632 // append to C source file
633 source_declarations.add_type_member_declaration (func.copy ());
635 func.block = block;
636 source_type_member_definition.append (func);
638 return connect_wrapper_name;
641 void generate_gobject_connect_wrapper (DynamicSignal sig, CCodeBlock block) {
642 var m = (Method) sig.handler.symbol_reference;
644 sig.accept (codegen);
646 string connect_func = "g_signal_connect_object";
647 if (m.binding != MemberBinding.INSTANCE) {
648 connect_func = "g_signal_connect";
651 var call = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
652 call.add_argument (new CCodeIdentifier ("obj"));
653 call.add_argument (new CCodeIdentifier ("signal_name"));
654 call.add_argument (new CCodeIdentifier ("handler"));
655 call.add_argument (new CCodeIdentifier ("data"));
657 if (m.binding == MemberBinding.INSTANCE) {
658 call.add_argument (new CCodeConstant ("0"));
661 block.add_statement (new CCodeExpressionStatement (call));
664 public override void visit_property (Property prop) {
665 base.visit_property (prop);
667 if (is_gobject_property (prop)) {
668 prop_enum.add_value (new CCodeEnumValue (prop.get_upper_case_cname ()));
672 public override bool is_gobject_property (Property prop) {
673 var cl = prop.parent_symbol as Class;
674 if (cl == null || !cl.is_subtype_of (gobject_type)) {
675 return false;
678 if (prop.binding != MemberBinding.INSTANCE) {
679 return false;
682 if (prop.access == SymbolAccessibility.PRIVATE) {
683 return false;
686 var st = prop.property_type.data_type as Struct;
687 if (st != null && (!st.has_type_id || prop.property_type.nullable)) {
688 return false;
691 if (prop.property_type is ArrayType) {
692 return false;
695 var d = prop.property_type as DelegateType;
696 if (d != null && d.delegate_symbol.has_target) {
697 return false;
700 if (prop.base_interface_property != null) {
701 var iface = (Interface) prop.base_interface_property.parent_symbol;
702 if (!iface.is_subtype_of (gobject_type)) {
703 // implementing non-GObject property
704 return false;
708 if (!prop.name[0].isalpha ()) {
709 // GObject requires properties to start with a letter
710 return false;
713 return true;