update for 0.3.3 release
[vala-lang.git] / gobject / valaccodeclassbinding.vala
blob29d5a8297b6e98b9548162ed8d88f699759675e3
1 /* valaccodeclassbinding.vala
3 * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using GLib;
26 public class Vala.CCodeClassBinding : CCodeObjectTypeSymbolBinding {
27 public Class cl { get; set; }
29 public CCodeClassBinding (CCodeGenerator codegen, Class cl) {
30 this.cl = cl;
31 this.codegen = codegen;
34 public override void emit () {
35 var old_symbol = codegen.current_symbol;
36 var old_type_symbol = codegen.current_type_symbol;
37 var old_class = codegen.current_class;
38 var old_instance_struct = codegen.instance_struct;
39 var old_type_struct = codegen.type_struct;
40 var old_instance_priv_struct = codegen.instance_priv_struct;
41 var old_prop_enum = codegen.prop_enum;
42 var old_class_init_fragment = codegen.class_init_fragment;
43 var old_instance_init_fragment = codegen.instance_init_fragment;
44 var old_instance_dispose_fragment = codegen.instance_dispose_fragment;
45 codegen.current_symbol = cl;
46 codegen.current_type_symbol = cl;
47 codegen.current_class = cl;
49 bool is_gtypeinstance = !cl.is_compact && !cl.is_static;
50 bool is_gobject = cl.is_subtype_of (codegen.gobject_type);
51 bool is_fundamental = is_gtypeinstance && cl.base_class == null;
53 if (cl.get_cname().len () < 3) {
54 cl.error = true;
55 Report.error (cl.source_reference, "Class name `%s' is too short".printf (cl.get_cname ()));
56 return;
59 if (!cl.is_static) {
60 codegen.instance_struct = new CCodeStruct ("_%s".printf (cl.get_cname ()));
61 codegen.type_struct = new CCodeStruct ("_%sClass".printf (cl.get_cname ()));
62 codegen.instance_priv_struct = new CCodeStruct ("_%sPrivate".printf (cl.get_cname ()));
63 codegen.prop_enum = new CCodeEnum ();
64 codegen.prop_enum.add_value (new CCodeEnumValue ("%s_DUMMY_PROPERTY".printf (cl.get_upper_case_cname (null))));
65 codegen.class_init_fragment = new CCodeFragment ();
66 codegen.instance_init_fragment = new CCodeFragment ();
67 codegen.instance_dispose_fragment = new CCodeFragment ();
70 CCodeFragment decl_frag;
71 CCodeFragment def_frag;
72 if (cl.access != SymbolAccessibility.PRIVATE) {
73 decl_frag = codegen.header_type_declaration;
74 def_frag = codegen.header_type_definition;
75 } else {
76 decl_frag = codegen.source_type_declaration;
77 def_frag = codegen.source_type_definition;
80 if (is_gtypeinstance) {
81 decl_frag.append (new CCodeNewline ());
82 var macro = "(%s_get_type ())".printf (cl.get_lower_case_cname (null));
83 decl_frag.append (new CCodeMacroReplacement (cl.get_upper_case_cname ("TYPE_"), macro));
85 macro = "(G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, %s))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
86 decl_frag.append (new CCodeMacroReplacement ("%s(obj)".printf (cl.get_upper_case_cname (null)), macro));
88 macro = "(G_TYPE_CHECK_CLASS_CAST ((klass), %s, %sClass))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
89 decl_frag.append (new CCodeMacroReplacement ("%s_CLASS(klass)".printf (cl.get_upper_case_cname (null)), macro));
91 macro = "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))".printf (cl.get_upper_case_cname ("TYPE_"));
92 decl_frag.append (new CCodeMacroReplacement ("%s(obj)".printf (cl.get_upper_case_cname ("IS_")), macro));
94 macro = "(G_TYPE_CHECK_CLASS_TYPE ((klass), %s))".printf (cl.get_upper_case_cname ("TYPE_"));
95 decl_frag.append (new CCodeMacroReplacement ("%s_CLASS(klass)".printf (cl.get_upper_case_cname ("IS_")), macro));
97 macro = "(G_TYPE_INSTANCE_GET_CLASS ((obj), %s, %sClass))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
98 decl_frag.append (new CCodeMacroReplacement ("%s_GET_CLASS(obj)".printf (cl.get_upper_case_cname (null)), macro));
99 decl_frag.append (new CCodeNewline ());
103 if (!cl.is_static && cl.source_reference.file.cycle == null) {
104 decl_frag.append (new CCodeTypeDefinition ("struct %s".printf (codegen.instance_struct.name), new CCodeVariableDeclarator (cl.get_cname ())));
107 if (cl.base_class != null) {
108 codegen.instance_struct.add_field (cl.base_class.get_cname (), "parent_instance");
109 } else if (is_fundamental) {
110 codegen.instance_struct.add_field ("GTypeInstance", "parent_instance");
111 codegen.instance_struct.add_field ("volatile int", "ref_count");
114 if (cl.is_compact && cl.base_class == null && cl.get_fields ().size == 0) {
115 // add dummy member, C doesn't allow empty structs
116 codegen.instance_struct.add_field ("int", "dummy");
119 if (is_gtypeinstance) {
120 if (cl.source_reference.file.cycle == null) {
121 decl_frag.append (new CCodeTypeDefinition ("struct %s".printf (codegen.type_struct.name), new CCodeVariableDeclarator ("%sClass".printf (cl.get_cname ()))));
123 decl_frag.append (new CCodeTypeDefinition ("struct %s".printf (codegen.instance_priv_struct.name), new CCodeVariableDeclarator ("%sPrivate".printf (cl.get_cname ()))));
125 codegen.instance_struct.add_field ("%sPrivate *".printf (cl.get_cname ()), "priv");
126 if (is_fundamental) {
127 codegen.type_struct.add_field ("GTypeClass", "parent_class");
128 codegen.type_struct.add_field ("void", "(*finalize) (%s *self)".printf (cl.get_cname ()));
129 } else {
130 codegen.type_struct.add_field ("%sClass".printf (cl.base_class.get_cname ()), "parent_class");
134 if (!cl.is_static) {
135 if (cl.source_reference.comment != null) {
136 def_frag.append (new CCodeComment (cl.source_reference.comment));
138 def_frag.append (codegen.instance_struct);
141 if (is_gtypeinstance) {
142 def_frag.append (codegen.type_struct);
143 /* only add the *Private struct if it is not empty, i.e. we actually have private data */
144 if (cl.has_private_fields || cl.get_type_parameters ().size > 0) {
145 codegen.source_type_member_declaration.append (codegen.instance_priv_struct);
146 var macro = "(G_TYPE_INSTANCE_GET_PRIVATE ((o), %s, %sPrivate))".printf (cl.get_upper_case_cname ("TYPE_"), cl.get_cname ());
147 codegen.source_type_member_declaration.append (new CCodeMacroReplacement ("%s_GET_PRIVATE(o)".printf (cl.get_upper_case_cname (null)), macro));
149 codegen.source_type_member_declaration.append (codegen.prop_enum);
152 cl.accept_children (codegen);
154 if (is_gtypeinstance) {
155 if (is_fundamental) {
156 var ref_count = new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "ref_count"), new CCodeConstant ("1"));
157 codegen.instance_init_fragment.append (new CCodeExpressionStatement (ref_count));
158 } else if (is_gobject) {
159 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
160 add_get_property_function (cl);
162 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
163 add_set_property_function (cl);
166 add_class_init_function (cl);
168 foreach (DataType base_type in cl.get_base_types ()) {
169 if (base_type.data_type is Interface) {
170 add_interface_init_function (cl, (Interface) base_type.data_type);
174 add_instance_init_function (cl);
176 if (is_gobject) {
177 if (cl.get_fields ().size > 0 || cl.destructor != null) {
178 add_dispose_function (cl);
182 var type_fun = new ClassRegisterFunction (cl);
183 type_fun.init_from_type (codegen.in_plugin);
184 if (cl.access != SymbolAccessibility.PRIVATE) {
185 codegen.header_type_member_declaration.append (type_fun.get_declaration ());
186 } else {
187 codegen.source_type_member_declaration.append (type_fun.get_declaration ());
189 codegen.source_type_member_definition.append (type_fun.get_definition ());
191 if (codegen.in_plugin) {
192 // FIXME resolve potential dependency issues, i.e. base types have to be registered before derived types
193 var register_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_register_type".printf (cl.get_lower_case_cname (null))));
194 register_call.add_argument (new CCodeIdentifier (codegen.module_init_param_name));
195 codegen.module_init_fragment.append (new CCodeExpressionStatement (register_call));
198 if (is_fundamental) {
199 var ref_fun = new CCodeFunction (cl.get_lower_case_cprefix () + "ref", "gpointer");
200 var unref_fun = new CCodeFunction (cl.get_lower_case_cprefix () + "unref", "void");
201 if (cl.access == SymbolAccessibility.PRIVATE) {
202 ref_fun.modifiers = CCodeModifiers.STATIC;
203 unref_fun.modifiers = CCodeModifiers.STATIC;
206 ref_fun.add_parameter (new CCodeFormalParameter ("instance", "gpointer"));
207 unref_fun.add_parameter (new CCodeFormalParameter ("instance", "gpointer"));
209 if (cl.access != SymbolAccessibility.PRIVATE) {
210 codegen.header_type_member_declaration.append (ref_fun.copy ());
211 codegen.header_type_member_declaration.append (unref_fun.copy ());
212 } else {
213 codegen.source_type_member_declaration.append (ref_fun.copy ());
214 codegen.source_type_member_declaration.append (unref_fun.copy ());
217 var ref_block = new CCodeBlock ();
218 var unref_block = new CCodeBlock ();
220 var cdecl = new CCodeDeclaration (cl.get_cname () + "*");
221 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", new CCodeIdentifier ("instance")));
222 ref_block.add_statement (cdecl);
223 unref_block.add_statement (cdecl);
225 var ref_count = new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "ref_count");
227 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_inc"));
228 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ref_count));
229 ref_block.add_statement (new CCodeExpressionStatement (ccall));
231 ref_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("instance")));
233 var destroy_block = new CCodeBlock ();
234 var get_class = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS".printf (cl.get_upper_case_cname (null))));
235 get_class.add_argument (new CCodeIdentifier ("self"));
236 var finalize = new CCodeMemberAccess.pointer (get_class, "finalize");
237 var finalize_call = new CCodeFunctionCall (finalize);
238 finalize_call.add_argument (new CCodeIdentifier ("self"));
239 //destroy_block.add_statement (new CCodeExpressionStatement (finalize_call));
240 var free = new CCodeFunctionCall (new CCodeIdentifier ("g_type_free_instance"));
241 free.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GTypeInstance *"));
242 destroy_block.add_statement (new CCodeExpressionStatement (free));
244 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_atomic_int_dec_and_test"));
245 ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, ref_count));
246 unref_block.add_statement (new CCodeIfStatement (ccall, destroy_block));
248 ref_fun.block = ref_block;
249 unref_fun.block = unref_block;
251 codegen.source_type_member_definition.append (ref_fun);
252 codegen.source_type_member_definition.append (unref_fun);
254 } else if (!cl.is_static) {
255 var function = new CCodeFunction (cl.get_lower_case_cprefix () + "free", "void");
256 if (cl.access == SymbolAccessibility.PRIVATE) {
257 function.modifiers = CCodeModifiers.STATIC;
260 function.add_parameter (new CCodeFormalParameter ("self", cl.get_cname () + "*"));
262 if (cl.access != SymbolAccessibility.PRIVATE) {
263 codegen.header_type_member_declaration.append (function.copy ());
264 } else {
265 codegen.source_type_member_declaration.append (function.copy ());
268 var cblock = new CCodeBlock ();
270 cblock.add_statement (codegen.instance_dispose_fragment);
272 if (cl.destructor != null) {
273 cblock.add_statement (cl.destructor.body.ccodenode);
276 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_slice_free"));
277 ccall.add_argument (new CCodeIdentifier (cl.get_cname ()));
278 ccall.add_argument (new CCodeIdentifier ("self"));
279 cblock.add_statement (new CCodeExpressionStatement (ccall));
281 function.block = cblock;
283 codegen.source_type_member_definition.append (function);
286 codegen.current_type_symbol = old_type_symbol;
287 codegen.current_class = old_class;
288 codegen.instance_struct = old_instance_struct;
289 codegen.type_struct = old_type_struct;
290 codegen.instance_priv_struct = old_instance_priv_struct;
291 codegen.prop_enum = old_prop_enum;
292 codegen.class_init_fragment = old_class_init_fragment;
293 codegen.instance_init_fragment = old_instance_init_fragment;
294 codegen.instance_dispose_fragment = old_instance_dispose_fragment;
297 private void add_class_init_function (Class cl) {
298 var class_init = new CCodeFunction ("%s_class_init".printf (cl.get_lower_case_cname (null)), "void");
299 class_init.add_parameter (new CCodeFormalParameter ("klass", "%sClass *".printf (cl.get_cname ())));
300 class_init.modifiers = CCodeModifiers.STATIC;
302 var init_block = new CCodeBlock ();
303 class_init.block = init_block;
305 CCodeFunctionCall ccall;
307 /* save pointer to parent class */
308 var parent_decl = new CCodeDeclaration ("gpointer");
309 var parent_var_decl = new CCodeVariableDeclarator ("%s_parent_class".printf (cl.get_lower_case_cname (null)));
310 parent_var_decl.initializer = new CCodeConstant ("NULL");
311 parent_decl.add_declarator (parent_var_decl);
312 parent_decl.modifiers = CCodeModifiers.STATIC;
313 codegen.source_type_member_declaration.append (parent_decl);
314 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
315 ccall.add_argument (new CCodeIdentifier ("klass"));
316 var parent_assignment = new CCodeAssignment (new CCodeIdentifier ("%s_parent_class".printf (cl.get_lower_case_cname (null))), ccall);
317 init_block.add_statement (new CCodeExpressionStatement (parent_assignment));
319 /* add struct for private fields */
320 if (cl.has_private_fields || cl.get_type_parameters ().size > 0) {
321 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_add_private"));
322 ccall.add_argument (new CCodeIdentifier ("klass"));
323 ccall.add_argument (new CCodeConstant ("sizeof (%sPrivate)".printf (cl.get_cname ())));
324 init_block.add_statement (new CCodeExpressionStatement (ccall));
327 if (cl.is_subtype_of (codegen.gobject_type)) {
328 /* set property handlers */
329 ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
330 ccall.add_argument (new CCodeIdentifier ("klass"));
331 if (class_has_readable_properties (cl) || cl.get_type_parameters ().size > 0) {
332 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))))));
334 if (class_has_writable_properties (cl) || cl.get_type_parameters ().size > 0) {
335 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))))));
338 /* set constructor */
339 if (cl.constructor != null) {
340 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
341 ccast.add_argument (new CCodeIdentifier ("klass"));
342 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%s_constructor".printf (cl.get_lower_case_cname (null))))));
345 /* set dispose function */
346 if (cl.get_fields ().size > 0 || cl.destructor != null) {
347 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
348 ccast.add_argument (new CCodeIdentifier ("klass"));
349 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, "dispose"), new CCodeIdentifier ("%s_dispose".printf (cl.get_lower_case_cname (null))))));
353 /* connect overridden methods */
354 foreach (Method m in cl.get_methods ()) {
355 if (m.base_method == null) {
356 continue;
358 var base_type = m.base_method.parent_symbol;
360 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (((Class) base_type).get_upper_case_cname (null))));
361 ccast.add_argument (new CCodeIdentifier ("klass"));
362 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.base_method.vfunc_name), new CCodeIdentifier (m.get_real_cname ()))));
365 if (cl.is_subtype_of (codegen.gobject_type)) {
366 /* create type, dup_func, and destroy_func properties for generic types */
367 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
368 string func_name, enum_value;
369 CCodeConstant func_name_constant;
370 CCodeFunctionCall cinst, cspec;
372 func_name = "%s_type".printf (type_param.name.down ());
373 func_name_constant = new CCodeConstant ("\"%s-type\"".printf (type_param.name.down ()));
374 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
375 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
376 cinst.add_argument (ccall);
377 cinst.add_argument (new CCodeConstant (enum_value));
378 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_gtype"));
379 cspec.add_argument (func_name_constant);
380 cspec.add_argument (new CCodeConstant ("\"type\""));
381 cspec.add_argument (new CCodeConstant ("\"type\""));
382 cspec.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
383 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
384 cinst.add_argument (cspec);
385 init_block.add_statement (new CCodeExpressionStatement (cinst));
386 codegen.prop_enum.add_value (new CCodeEnumValue (enum_value));
388 codegen.instance_priv_struct.add_field ("GType", func_name);
391 func_name = "%s_dup_func".printf (type_param.name.down ());
392 func_name_constant = new CCodeConstant ("\"%s-dup-func\"".printf (type_param.name.down ()));
393 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
394 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
395 cinst.add_argument (ccall);
396 cinst.add_argument (new CCodeConstant (enum_value));
397 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
398 cspec.add_argument (func_name_constant);
399 cspec.add_argument (new CCodeConstant ("\"dup func\""));
400 cspec.add_argument (new CCodeConstant ("\"dup func\""));
401 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
402 cinst.add_argument (cspec);
403 init_block.add_statement (new CCodeExpressionStatement (cinst));
404 codegen.prop_enum.add_value (new CCodeEnumValue (enum_value));
406 codegen.instance_priv_struct.add_field ("GBoxedCopyFunc", func_name);
409 func_name = "%s_destroy_func".printf (type_param.name.down ());
410 func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
411 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
412 cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
413 cinst.add_argument (ccall);
414 cinst.add_argument (new CCodeConstant (enum_value));
415 cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
416 cspec.add_argument (func_name_constant);
417 cspec.add_argument (new CCodeConstant ("\"destroy func\""));
418 cspec.add_argument (new CCodeConstant ("\"destroy func\""));
419 cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
420 cinst.add_argument (cspec);
421 init_block.add_statement (new CCodeExpressionStatement (cinst));
422 codegen.prop_enum.add_value (new CCodeEnumValue (enum_value));
424 codegen.instance_priv_struct.add_field ("GDestroyNotify", func_name);
427 /* create properties */
428 var props = cl.get_properties ();
429 foreach (Property prop in props) {
430 // FIXME: omit real struct types for now since they cannot be expressed as gobject property yet
431 if (prop.property_type.is_real_struct_type ()) {
432 continue;
434 if (prop.access == SymbolAccessibility.PRIVATE) {
435 // don't register private properties
436 continue;
439 if (prop.overrides || prop.base_interface_property != null) {
440 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_override_property"));
441 cinst.add_argument (ccall);
442 cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
443 cinst.add_argument (prop.get_canonical_cconstant ());
445 init_block.add_statement (new CCodeExpressionStatement (cinst));
446 } else {
447 var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
448 cinst.add_argument (ccall);
449 cinst.add_argument (new CCodeConstant (prop.get_upper_case_cname ()));
450 cinst.add_argument (get_param_spec (prop));
452 init_block.add_statement (new CCodeExpressionStatement (cinst));
456 /* create signals */
457 foreach (Signal sig in cl.get_signals ()) {
458 init_block.add_statement (new CCodeExpressionStatement (get_signal_creation (sig, cl)));
460 } else if (!cl.is_compact) {
461 /* create type, dup_func, and destroy_func fields for generic types */
462 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
463 string func_name;
465 func_name = "%s_type".printf (type_param.name.down ());
466 codegen.instance_priv_struct.add_field ("GType", func_name);
468 func_name = "%s_dup_func".printf (type_param.name.down ());
469 codegen.instance_priv_struct.add_field ("GBoxedCopyFunc", func_name);
471 func_name = "%s_destroy_func".printf (type_param.name.down ());
472 codegen.instance_priv_struct.add_field ("GDestroyNotify", func_name);
476 init_block.add_statement (register_dbus_info (cl));
477 init_block.add_statement (codegen.class_init_fragment);
479 codegen.source_type_member_definition.append (class_init);
482 private void add_interface_init_function (Class cl, Interface iface) {
483 var iface_init = new CCodeFunction ("%s_%s_interface_init".printf (cl.get_lower_case_cname (null), iface.get_lower_case_cname (null)), "void");
484 iface_init.add_parameter (new CCodeFormalParameter ("iface", "%s *".printf (iface.get_type_cname ())));
485 iface_init.modifiers = CCodeModifiers.STATIC;
487 var init_block = new CCodeBlock ();
488 iface_init.block = init_block;
490 CCodeFunctionCall ccall;
492 /* save pointer to parent vtable */
493 string parent_iface_var = "%s_%s_parent_iface".printf (cl.get_lower_case_cname (null), iface.get_lower_case_cname (null));
494 var parent_decl = new CCodeDeclaration (iface.get_type_cname () + "*");
495 var parent_var_decl = new CCodeVariableDeclarator (parent_iface_var);
496 parent_var_decl.initializer = new CCodeConstant ("NULL");
497 parent_decl.add_declarator (parent_var_decl);
498 parent_decl.modifiers = CCodeModifiers.STATIC;
499 codegen.source_type_member_declaration.append (parent_decl);
500 ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_interface_peek_parent"));
501 ccall.add_argument (new CCodeIdentifier ("iface"));
502 var parent_assignment = new CCodeAssignment (new CCodeIdentifier (parent_iface_var), ccall);
503 init_block.add_statement (new CCodeExpressionStatement (parent_assignment));
505 foreach (Method m in cl.get_methods ()) {
506 if (m.base_interface_method == null) {
507 continue;
510 var base_type = m.base_interface_method.parent_symbol;
511 if (base_type != iface) {
512 continue;
515 var ciface = new CCodeIdentifier ("iface");
516 var cname = m.get_real_cname ();
517 if (m.is_abstract || m.is_virtual) {
518 // FIXME results in C compiler warning
519 cname = m.get_cname ();
521 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ciface, m.base_interface_method.vfunc_name), new CCodeIdentifier (cname))));
524 codegen.source_type_member_definition.append (iface_init);
527 private void add_instance_init_function (Class cl) {
528 var instance_init = new CCodeFunction ("%s_instance_init".printf (cl.get_lower_case_cname (null)), "void");
529 instance_init.add_parameter (new CCodeFormalParameter ("self", "%s *".printf (cl.get_cname ())));
530 instance_init.modifiers = CCodeModifiers.STATIC;
532 var init_block = new CCodeBlock ();
533 instance_init.block = init_block;
535 if (cl.has_private_fields || cl.get_type_parameters ().size > 0) {
536 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_PRIVATE".printf (cl.get_upper_case_cname (null))));
537 ccall.add_argument (new CCodeIdentifier ("self"));
538 init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), ccall)));
541 init_block.add_statement (codegen.instance_init_fragment);
543 codegen.source_type_member_definition.append (instance_init);
546 private void add_dispose_function (Class cl) {
547 var function = new CCodeFunction ("%s_dispose".printf (cl.get_lower_case_cname (null)), "void");
548 function.modifiers = CCodeModifiers.STATIC;
550 function.add_parameter (new CCodeFormalParameter ("obj", "GObject *"));
552 codegen.source_type_member_declaration.append (function.copy ());
555 var cblock = new CCodeBlock ();
557 CCodeFunctionCall ccall = new InstanceCast (new CCodeIdentifier ("obj"), cl);
559 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
560 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
562 cblock.add_statement (cdecl);
564 if (cl.destructor != null) {
565 cblock.add_statement ((CCodeBlock) cl.destructor.body.ccodenode);
568 cblock.add_statement (codegen.instance_dispose_fragment);
570 // chain up to dispose function of the base class
571 var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
572 ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (cl.get_lower_case_cname (null))));
573 ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (ccast, "dispose"));
574 ccall.add_argument (new CCodeIdentifier ("obj"));
575 cblock.add_statement (new CCodeExpressionStatement (ccall));
578 function.block = cblock;
580 codegen.source_type_member_definition.append (function);
583 private bool class_has_readable_properties (Class cl) {
584 foreach (Property prop in cl.get_properties ()) {
585 if (prop.get_accessor != null) {
586 return true;
589 return false;
592 private bool class_has_writable_properties (Class cl) {
593 foreach (Property prop in cl.get_properties ()) {
594 if (prop.set_accessor != null) {
595 return true;
598 return false;
601 private void add_get_property_function (Class cl) {
602 var get_prop = new CCodeFunction ("%s_get_property".printf (cl.get_lower_case_cname (null)), "void");
603 get_prop.modifiers = CCodeModifiers.STATIC;
604 get_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
605 get_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
606 get_prop.add_parameter (new CCodeFormalParameter ("value", "GValue *"));
607 get_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
609 var block = new CCodeBlock ();
611 var ccall = new InstanceCast (new CCodeIdentifier ("object"), cl);
612 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
613 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
614 block.add_statement (cdecl);
616 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
617 var props = cl.get_properties ();
618 foreach (Property prop in props) {
619 // FIXME: omit real struct types for now since they cannot be expressed as gobject property yet
620 if (prop.get_accessor == null || prop.is_abstract || prop.property_type.is_real_struct_type ()) {
621 continue;
623 if (prop.access == SymbolAccessibility.PRIVATE) {
624 // don't register private properties
625 continue;
628 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
630 string prefix = cl.get_lower_case_cname (null);
631 if (is_virtual) {
632 prefix += "_real";
635 var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
636 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_get_%s".printf (prefix, prop.name)));
637 ccall.add_argument (new CCodeIdentifier ("self"));
638 var csetcall = new CCodeFunctionCall ();
639 csetcall.call = get_value_setter_function (prop.property_type);
640 csetcall.add_argument (new CCodeIdentifier ("value"));
641 csetcall.add_argument (ccall);
642 ccase.add_statement (new CCodeExpressionStatement (csetcall));
643 ccase.add_statement (new CCodeBreakStatement ());
644 cswitch.add_case (ccase);
646 cswitch.add_default_statement (get_invalid_property_id_warn_statement ());
647 cswitch.add_default_statement (new CCodeBreakStatement ());
649 block.add_statement (cswitch);
651 get_prop.block = block;
653 codegen.source_type_member_definition.append (get_prop);
656 private void add_set_property_function (Class cl) {
657 var set_prop = new CCodeFunction ("%s_set_property".printf (cl.get_lower_case_cname (null)), "void");
658 set_prop.modifiers = CCodeModifiers.STATIC;
659 set_prop.add_parameter (new CCodeFormalParameter ("object", "GObject *"));
660 set_prop.add_parameter (new CCodeFormalParameter ("property_id", "guint"));
661 set_prop.add_parameter (new CCodeFormalParameter ("value", "const GValue *"));
662 set_prop.add_parameter (new CCodeFormalParameter ("pspec", "GParamSpec *"));
664 var block = new CCodeBlock ();
666 var ccall = new InstanceCast (new CCodeIdentifier ("object"), cl);
667 var cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
668 cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
669 block.add_statement (cdecl);
671 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("property_id"));
672 var props = cl.get_properties ();
673 foreach (Property prop in props) {
674 // FIXME: omit real struct types for now since they cannot be expressed as gobject property yet
675 if (prop.set_accessor == null || prop.is_abstract || prop.property_type.is_real_struct_type ()) {
676 continue;
678 if (prop.access == SymbolAccessibility.PRIVATE) {
679 // don't register private properties
680 continue;
683 bool is_virtual = prop.base_property != null || prop.base_interface_property != null;
685 string prefix = cl.get_lower_case_cname (null);
686 if (is_virtual) {
687 prefix += "_real";
690 var ccase = new CCodeCaseStatement (new CCodeIdentifier (prop.get_upper_case_cname ()));
691 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_set_%s".printf (prefix, prop.name)));
692 ccall.add_argument (new CCodeIdentifier ("self"));
693 var cgetcall = new CCodeFunctionCall ();
694 if (prop.property_type.data_type != null) {
695 cgetcall.call = new CCodeIdentifier (prop.property_type.data_type.get_get_value_function ());
696 } else {
697 cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
699 cgetcall.add_argument (new CCodeIdentifier ("value"));
700 ccall.add_argument (cgetcall);
701 ccase.add_statement (new CCodeExpressionStatement (ccall));
702 ccase.add_statement (new CCodeBreakStatement ());
703 cswitch.add_case (ccase);
705 cswitch.add_default_statement (get_invalid_property_id_warn_statement ());
706 cswitch.add_default_statement (new CCodeBreakStatement ());
708 block.add_statement (cswitch);
710 /* type, dup func, and destroy func properties for generic types */
711 foreach (TypeParameter type_param in cl.get_type_parameters ()) {
712 string func_name, enum_value;
713 CCodeCaseStatement ccase;
714 CCodeMemberAccess cfield;
715 CCodeFunctionCall cgetcall;
717 func_name = "%s_type".printf (type_param.name.down ());
718 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
719 ccase = new CCodeCaseStatement (new CCodeIdentifier (enum_value));
720 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
721 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_gtype"));
722 cgetcall.add_argument (new CCodeIdentifier ("value"));
723 ccase.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
724 ccase.add_statement (new CCodeBreakStatement ());
725 cswitch.add_case (ccase);
727 func_name = "%s_dup_func".printf (type_param.name.down ());
728 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
729 ccase = new CCodeCaseStatement (new CCodeIdentifier (enum_value));
730 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
731 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
732 cgetcall.add_argument (new CCodeIdentifier ("value"));
733 ccase.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
734 ccase.add_statement (new CCodeBreakStatement ());
735 cswitch.add_case (ccase);
737 func_name = "%s_destroy_func".printf (type_param.name.down ());
738 enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
739 ccase = new CCodeCaseStatement (new CCodeIdentifier (enum_value));
740 cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
741 cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
742 cgetcall.add_argument (new CCodeIdentifier ("value"));
743 ccase.add_statement (new CCodeExpressionStatement (new CCodeAssignment (cfield, cgetcall)));
744 ccase.add_statement (new CCodeBreakStatement ());
745 cswitch.add_case (ccase);
748 set_prop.block = block;
750 codegen.source_type_member_definition.append (set_prop);
753 private CCodeStatement get_invalid_property_id_warn_statement () {
754 // warn on invalid property id
755 var cwarn = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
756 cwarn.add_argument (new CCodeIdentifier ("object"));
757 cwarn.add_argument (new CCodeIdentifier ("property_id"));
758 cwarn.add_argument (new CCodeIdentifier ("pspec"));
759 return new CCodeExpressionStatement (cwarn);