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
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
26 public class Vala
.CCodeClassBinding
: CCodeObjectTypeSymbolBinding
{
27 public Class cl
{ get; set; }
29 public CCodeClassBinding (CCodeGenerator codegen
, Class 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) {
55 Report
.error (cl
.source_reference
, "Class name `%s' is too short".printf (cl
.get_cname ()));
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
;
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 ()));
130 codegen
.type_struct
.add_field ("%sClass".printf (cl
.base_class
.get_cname ()), "parent_class");
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
);
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 ());
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 ());
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 ());
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) {
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 ()) {
434 if (prop
.access
== SymbolAccessibility
.PRIVATE
) {
435 // don't register private properties
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
));
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
));
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 ()) {
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) {
510 var base_type
= m
.base_interface_method
.parent_symbol
;
511 if (base_type
!= iface
) {
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) {
592 private bool class_has_writable_properties (Class cl
) {
593 foreach (Property prop
in cl
.get_properties ()) {
594 if (prop
.set_accessor
!= null) {
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 ()) {
623 if (prop
.access
== SymbolAccessibility
.PRIVATE
) {
624 // don't register private properties
628 bool is_virtual
= prop
.base_property
!= null || prop
.base_interface_property
!= null;
630 string prefix
= cl
.get_lower_case_cname (null);
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 ()) {
678 if (prop
.access
== SymbolAccessibility
.PRIVATE
) {
679 // don't register private properties
683 bool is_virtual
= prop
.base_property
!= null || prop
.base_interface_property
!= null;
685 string prefix
= cl
.get_lower_case_cname (null);
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 ());
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
);