1 /* valagobjectmodule.vala
3 * Copyright (C) 2006-2010 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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 public class Vala
.GObjectModule
: GTypeModule
{
27 int dynamic_property_id
;
28 int signal_wrapper_id
;
30 public override void visit_class (Class cl
) {
31 base.visit_class (cl
);
33 if (!cl
.is_subtype_of (gobject_type
)) {
37 if (class_has_readable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
38 add_get_property_function (cl
);
40 if (class_has_writable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
41 add_set_property_function (cl
);
45 public override void generate_class_init (Class cl
, CCodeBlock init_block
) {
46 if (!cl
.is_subtype_of (gobject_type
)) {
50 /* set property handlers */
51 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
52 ccall
.add_argument (new
CCodeIdentifier ("klass"));
53 if (class_has_readable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
54 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))))));
56 if (class_has_writable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
57 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))))));
61 if (cl
.constructor
!= null) {
62 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
63 ccast
.add_argument (new
CCodeIdentifier ("klass"));
64 init_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (ccast
, "constructor"), new
CCodeIdentifier ("%s_constructor".printf (cl
.get_lower_case_cname (null))))));
67 /* set finalize function */
68 if (cl
.get_fields ().size
> 0 || cl
.destructor
!= null) {
69 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
70 ccast
.add_argument (new
CCodeIdentifier ("klass"));
71 init_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (ccast
, "finalize"), new
CCodeIdentifier ("%s_finalize".printf (cl
.get_lower_case_cname (null))))));
74 /* create type, dup_func, and destroy_func properties for generic types */
75 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
76 string func_name
, enum_value
;
77 CCodeConstant func_name_constant
;
78 CCodeFunctionCall cinst
, cspec
;
80 func_name
= "%s_type".printf (type_param
.name
.down ());
81 func_name_constant
= new
CCodeConstant ("\"%s-type\"".printf (type_param
.name
.down ()));
82 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
83 cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
84 cinst
.add_argument (ccall
);
85 cinst
.add_argument (new
CCodeConstant (enum_value
));
86 cspec
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_param_spec_gtype"));
87 cspec
.add_argument (func_name_constant
);
88 cspec
.add_argument (new
CCodeConstant ("\"type\""));
89 cspec
.add_argument (new
CCodeConstant ("\"type\""));
90 cspec
.add_argument (new
CCodeIdentifier ("G_TYPE_NONE"));
91 cspec
.add_argument (new
CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
92 cinst
.add_argument (cspec
);
93 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
94 prop_enum
.add_value (new
CCodeEnumValue (enum_value
));
97 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
98 func_name_constant
= new
CCodeConstant ("\"%s-dup-func\"".printf (type_param
.name
.down ()));
99 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
100 cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
101 cinst
.add_argument (ccall
);
102 cinst
.add_argument (new
CCodeConstant (enum_value
));
103 cspec
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_param_spec_pointer"));
104 cspec
.add_argument (func_name_constant
);
105 cspec
.add_argument (new
CCodeConstant ("\"dup func\""));
106 cspec
.add_argument (new
CCodeConstant ("\"dup func\""));
107 cspec
.add_argument (new
CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
108 cinst
.add_argument (cspec
);
109 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
110 prop_enum
.add_value (new
CCodeEnumValue (enum_value
));
113 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
114 func_name_constant
= new
CCodeConstant ("\"%s-destroy-func\"".printf (type_param
.name
.down ()));
115 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
116 cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
117 cinst
.add_argument (ccall
);
118 cinst
.add_argument (new
CCodeConstant (enum_value
));
119 cspec
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_param_spec_pointer"));
120 cspec
.add_argument (func_name_constant
);
121 cspec
.add_argument (new
CCodeConstant ("\"destroy func\""));
122 cspec
.add_argument (new
CCodeConstant ("\"destroy func\""));
123 cspec
.add_argument (new
CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
124 cinst
.add_argument (cspec
);
125 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
126 prop_enum
.add_value (new
CCodeEnumValue (enum_value
));
129 /* create properties */
130 var props
= cl
.get_properties ();
131 foreach (Property prop
in props
) {
132 if (!is_gobject_property (prop
)) {
136 if (prop
.comment
!= null) {
137 init_block
.add_statement (new
CCodeComment (prop
.comment
.content
));
140 if (prop
.overrides
|| prop
.base_interface_property
!= null) {
141 var cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_override_property"));
142 cinst
.add_argument (ccall
);
143 cinst
.add_argument (new
CCodeConstant (prop
.get_upper_case_cname ()));
144 cinst
.add_argument (prop
.get_canonical_cconstant ());
146 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
148 var cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
149 cinst
.add_argument (ccall
);
150 cinst
.add_argument (new
CCodeConstant (prop
.get_upper_case_cname ()));
151 cinst
.add_argument (get_param_spec (prop
));
153 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
158 private bool class_has_readable_properties (Class cl
) {
159 foreach (Property prop
in cl
.get_properties ()) {
160 if (prop
.get_accessor
!= null) {
167 private bool class_has_writable_properties (Class cl
) {
168 foreach (Property prop
in cl
.get_properties ()) {
169 if (prop
.set_accessor
!= null) {
176 private void add_get_property_function (Class cl
) {
177 var get_prop
= new
CCodeFunction ("%s_get_property".printf (cl
.get_lower_case_cname (null)), "void");
178 get_prop
.modifiers
= CCodeModifiers
.STATIC
;
179 get_prop
.add_parameter (new
CCodeFormalParameter ("object", "GObject *"));
180 get_prop
.add_parameter (new
CCodeFormalParameter ("property_id", "guint"));
181 get_prop
.add_parameter (new
CCodeFormalParameter ("value", "GValue *"));
182 get_prop
.add_parameter (new
CCodeFormalParameter ("pspec", "GParamSpec *"));
184 var block
= new
CCodeBlock ();
186 CCodeFunctionCall ccall
= generate_instance_cast (new
CCodeIdentifier ("object"), cl
);
187 var cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
188 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", ccall
));
189 block
.add_statement (cdecl
);
191 int boxed_name_id
= 0;
192 bool length_declared
= false;
194 var cswitch
= new
CCodeSwitchStatement (new
CCodeIdentifier ("property_id"));
195 var props
= cl
.get_properties ();
196 foreach (Property prop
in props
) {
197 if (prop
.get_accessor
== null || prop
.is_abstract
) {
200 if (!is_gobject_property (prop
)) {
201 // don't register private properties
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 var st
= prop
.property_type
.data_type as Struct
;
224 var boxed
= "boxed%d".printf (boxed_name_id
++);
226 cdecl
= new
CCodeDeclaration (st
.get_cname ());
227 cdecl
.add_declarator (new
CCodeVariableDeclarator (boxed
));
228 block
.add_statement (cdecl
);
230 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_get_%s".printf (prefix
, prop
.name
)));
231 ccall
.add_argument (cself
);
232 var boxed_addr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (boxed
));
233 ccall
.add_argument (boxed_addr
);
234 cswitch
.add_statement (new
CCodeExpressionStatement (ccall
));
236 var csetcall
= new
CCodeFunctionCall ();
237 csetcall
.call
= get_value_setter_function (prop
.property_type
);
238 csetcall
.add_argument (new
CCodeIdentifier ("value"));
239 csetcall
.add_argument (boxed_addr
);
240 cswitch
.add_statement (new
CCodeExpressionStatement (csetcall
));
242 if (requires_destroy (prop
.get_accessor
.value_type
)) {
243 cswitch
.add_statement (new
CCodeExpressionStatement (get_unref_expression (new
CCodeIdentifier (boxed
), prop
.get_accessor
.value_type
, null)));
246 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_get_%s".printf (prefix
, prop
.name
)));
247 ccall
.add_argument (cself
);
248 var array_type
= prop
.property_type as ArrayType
;
249 if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
251 if (!length_declared
) {
252 cdecl
= new
CCodeDeclaration ("int");
253 cdecl
.add_declarator (new
CCodeVariableDeclarator ("length"));
254 block
.add_statement (cdecl
);
255 length_declared
= true;
257 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("length")));
259 var csetcall
= new
CCodeFunctionCall ();
260 if (prop
.get_accessor
.value_type
.value_owned
) {
261 csetcall
.call
= get_value_taker_function (prop
.property_type
);
263 csetcall
.call
= get_value_setter_function (prop
.property_type
);
265 csetcall
.add_argument (new
CCodeIdentifier ("value"));
266 csetcall
.add_argument (ccall
);
267 cswitch
.add_statement (new
CCodeExpressionStatement (csetcall
));
269 cswitch
.add_statement (new
CCodeBreakStatement ());
271 cswitch
.add_statement (new
CCodeLabel ("default"));
272 cswitch
.add_statement (get_invalid_property_id_warn_statement ());
273 cswitch
.add_statement (new
CCodeBreakStatement ());
275 block
.add_statement (cswitch
);
277 source_declarations
.add_type_member_declaration (get_prop
.copy ());
279 get_prop
.block
= block
;
281 source_type_member_definition
.append (get_prop
);
284 private void add_set_property_function (Class cl
) {
285 var set_prop
= new
CCodeFunction ("%s_set_property".printf (cl
.get_lower_case_cname (null)), "void");
286 set_prop
.modifiers
= CCodeModifiers
.STATIC
;
287 set_prop
.add_parameter (new
CCodeFormalParameter ("object", "GObject *"));
288 set_prop
.add_parameter (new
CCodeFormalParameter ("property_id", "guint"));
289 set_prop
.add_parameter (new
CCodeFormalParameter ("value", "const GValue *"));
290 set_prop
.add_parameter (new
CCodeFormalParameter ("pspec", "GParamSpec *"));
292 var block
= new
CCodeBlock ();
294 CCodeFunctionCall ccall
= generate_instance_cast (new
CCodeIdentifier ("object"), cl
);
295 var cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
296 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", ccall
));
297 block
.add_statement (cdecl
);
299 var boxed_declared
= false;
301 var cswitch
= new
CCodeSwitchStatement (new
CCodeIdentifier ("property_id"));
302 var props
= cl
.get_properties ();
303 foreach (Property prop
in props
) {
304 if (prop
.set_accessor
== null || prop
.is_abstract
) {
307 if (!is_gobject_property (prop
)) {
311 string prefix
= cl
.get_lower_case_cname (null);
312 CCodeExpression cself
= new
CCodeIdentifier ("self");
313 if (prop
.base_property
!= null) {
314 var base_type
= (Class
) prop
.base_property
.parent_symbol
;
315 prefix
= base_type
.get_lower_case_cname (null);
316 cself
= transform_expression (cself
, new
ObjectType (cl
), new
ObjectType (base_type
));
318 generate_property_accessor_declaration (prop
.base_property
.set_accessor
, source_declarations
);
319 } else if (prop
.base_interface_property
!= null) {
320 var base_type
= (Interface
) prop
.base_interface_property
.parent_symbol
;
321 prefix
= base_type
.get_lower_case_cname (null);
322 cself
= transform_expression (cself
, new
ObjectType (cl
), new
ObjectType (base_type
));
324 generate_property_accessor_declaration (prop
.base_interface_property
.set_accessor
, source_declarations
);
327 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (prop
.get_upper_case_cname ())));
328 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_set_%s".printf (prefix
, prop
.name
)));
329 ccall
.add_argument (cself
);
330 if (prop
.property_type is ArrayType
&& ((ArrayType
)prop
.property_type
).element_type
.data_type
== string_type
.data_type
) {
331 if (!boxed_declared
) {
332 cdecl
= new
CCodeDeclaration ("gpointer");
333 cdecl
.add_declarator (new
CCodeVariableDeclarator ("boxed"));
334 block
.add_statement (cdecl
);
335 boxed_declared
= true;
337 var cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_boxed"));
338 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
339 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("boxed"), cgetcall
)));
340 ccall
.add_argument (new
CCodeIdentifier ("boxed"));
342 var cstrvlen
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strv_length"));
343 cstrvlen
.add_argument (new
CCodeIdentifier ("boxed"));
344 ccall
.add_argument (cstrvlen
);
346 var cgetcall
= new
CCodeFunctionCall ();
347 if (prop
.property_type
.data_type
!= null) {
348 cgetcall
.call
= new
CCodeIdentifier (prop
.property_type
.data_type
.get_get_value_function ());
350 cgetcall
.call
= new
CCodeIdentifier ("g_value_get_pointer");
352 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
353 ccall
.add_argument (cgetcall
);
355 cswitch
.add_statement (new
CCodeExpressionStatement (ccall
));
356 cswitch
.add_statement (new
CCodeBreakStatement ());
358 cswitch
.add_statement (new
CCodeLabel ("default"));
359 cswitch
.add_statement (get_invalid_property_id_warn_statement ());
360 cswitch
.add_statement (new
CCodeBreakStatement ());
362 block
.add_statement (cswitch
);
364 /* type, dup func, and destroy func properties for generic types */
365 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
366 string func_name
, enum_value
;
367 CCodeMemberAccess cfield
;
368 CCodeFunctionCall cgetcall
;
370 func_name
= "%s_type".printf (type_param
.name
.down ());
371 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
372 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (enum_value
)));
373 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
374 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_gtype"));
375 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
376 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (cfield
, cgetcall
)));
377 cswitch
.add_statement (new
CCodeBreakStatement ());
379 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
380 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
381 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (enum_value
)));
382 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
383 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_pointer"));
384 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
385 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (cfield
, cgetcall
)));
386 cswitch
.add_statement (new
CCodeBreakStatement ());
388 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
389 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
390 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (enum_value
)));
391 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
392 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_pointer"));
393 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
394 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (cfield
, cgetcall
)));
395 cswitch
.add_statement (new
CCodeBreakStatement ());
398 source_declarations
.add_type_member_declaration (set_prop
.copy ());
400 set_prop
.block
= block
;
402 source_type_member_definition
.append (set_prop
);
405 private CCodeStatement
get_invalid_property_id_warn_statement () {
406 // warn on invalid property id
407 var cwarn
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
408 cwarn
.add_argument (new
CCodeIdentifier ("object"));
409 cwarn
.add_argument (new
CCodeIdentifier ("property_id"));
410 cwarn
.add_argument (new
CCodeIdentifier ("pspec"));
411 return new
CCodeExpressionStatement (cwarn
);
414 public override CCodeExpression
get_construct_property_assignment (CCodeConstant canonical_cconstant
, DataType property_type
, CCodeExpression value
) {
415 // this property is used as a construction parameter
416 var cpointer
= new
CCodeIdentifier ("__params_it");
418 var ccomma
= new
CCodeCommaExpression ();
419 // set name in array for current parameter
420 var cnamemember
= new CCodeMemberAccess
.pointer (cpointer
, "name");
421 var cnameassign
= new
CCodeAssignment (cnamemember
, canonical_cconstant
);
422 ccomma
.append_expression (cnameassign
);
424 var gvaluearg
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (cpointer
, "value"));
426 // initialize GValue in array for current parameter
427 var cvalueinit
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
428 cvalueinit
.add_argument (gvaluearg
);
429 cvalueinit
.add_argument (new
CCodeIdentifier (property_type
.get_type_id ()));
430 ccomma
.append_expression (cvalueinit
);
432 // set GValue for current parameter
433 var cvalueset
= new
CCodeFunctionCall (get_value_setter_function (property_type
));
434 cvalueset
.add_argument (gvaluearg
);
435 if (property_type
.is_real_struct_type ()) {
436 cvalueset
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, value
));
438 cvalueset
.add_argument (value
);
440 ccomma
.append_expression (cvalueset
);
442 // move pointer to next parameter in array
443 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, cpointer
));
448 public override void visit_constructor (Constructor c
) {
449 bool old_method_inner_error
= current_method_inner_error
;
450 current_method_inner_error
= false;
452 if (c
.binding
== MemberBinding
.CLASS
|| c
.binding
== MemberBinding
.STATIC
) {
453 in_static_or_class_context
= true;
455 in_constructor
= true;
458 in_static_or_class_context
= false;
460 in_constructor
= false;
462 var cl
= (Class
) c
.parent_symbol
;
464 if (c
.binding
== MemberBinding
.INSTANCE
) {
465 if (!cl
.is_subtype_of (gobject_type
)) {
466 Report
.error (c
.source_reference
, "construct blocks require GLib.Object");
471 function
= new
CCodeFunction ("%s_constructor".printf (cl
.get_lower_case_cname (null)), "GObject *");
472 function
.modifiers
= CCodeModifiers
.STATIC
;
474 function
.add_parameter (new
CCodeFormalParameter ("type", "GType"));
475 function
.add_parameter (new
CCodeFormalParameter ("n_construct_properties", "guint"));
476 function
.add_parameter (new
CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
478 source_declarations
.add_type_member_declaration (function
.copy ());
481 var cblock
= new
CCodeBlock ();
482 var cdecl
= new
CCodeDeclaration ("GObject *");
483 cdecl
.add_declarator (new
CCodeVariableDeclarator ("obj"));
484 cblock
.add_statement (cdecl
);
486 cdecl
= new
CCodeDeclaration ("GObjectClass *");
487 cdecl
.add_declarator (new
CCodeVariableDeclarator ("parent_class"));
488 cblock
.add_statement (cdecl
);
491 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
492 ccast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (cl
.get_lower_case_cname (null))));
493 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("parent_class"), ccast
)));
496 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("parent_class"), "constructor"));
497 ccall
.add_argument (new
CCodeIdentifier ("type"));
498 ccall
.add_argument (new
CCodeIdentifier ("n_construct_properties"));
499 ccall
.add_argument (new
CCodeIdentifier ("construct_properties"));
500 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("obj"), ccall
)));
503 ccall
= generate_instance_cast (new
CCodeIdentifier ("obj"), cl
);
505 cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
506 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", ccall
));
507 cblock
.add_statement (cdecl
);
509 if (current_method_inner_error
) {
510 /* always separate error parameter and inner_error local variable
511 * as error may be set to NULL but we're always interested in inner errors
513 cdecl
= new
CCodeDeclaration ("GError *");
514 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_inner_error_", new
CCodeConstant ("NULL")));
515 cblock
.add_statement (cdecl
);
519 cblock
.add_statement (c
.body
.ccodenode
);
521 cblock
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("obj")));
523 function
.block
= cblock
;
525 source_type_member_definition
.append (function
);
526 } else if (c
.binding
== MemberBinding
.CLASS
) {
530 Report
.error (c
.source_reference
, "class constructors are not supported in compact classes");
535 if (current_method_inner_error
) {
536 /* always separate error parameter and inner_error local variable
537 * as error may be set to NULL but we're always interested in inner errors
539 var cdecl
= new
CCodeDeclaration ("GError *");
540 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_inner_error_", new
CCodeConstant ("NULL")));
541 base_init_fragment
.append (cdecl
);
544 base_init_fragment
.append (c
.body
.ccodenode
);
545 } else if (c
.binding
== MemberBinding
.STATIC
) {
546 // static class constructor
550 Report
.error (c
.source_reference
, "static constructors are not supported in compact classes");
555 if (current_method_inner_error
) {
556 /* always separate error parameter and inner_error local variable
557 * as error may be set to NULL but we're always interested in inner errors
559 var cdecl
= new
CCodeDeclaration ("GError *");
560 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_inner_error_", new
CCodeConstant ("NULL")));
561 class_init_fragment
.append (cdecl
);
564 class_init_fragment
.append (c
.body
.ccodenode
);
566 Report
.error (c
.source_reference
, "internal error: constructors must have instance, class, or static binding");
569 current_method_inner_error
= old_method_inner_error
;
572 public override string get_dynamic_property_getter_cname (DynamicProperty prop
) {
573 if (prop
.dynamic_type
.data_type
== null
574 || !prop
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
575 return base.get_dynamic_property_getter_cname (prop
);
578 string getter_cname
= "_dynamic_get_%s%d".printf (prop
.name
, dynamic_property_id
++);
580 var func
= new
CCodeFunction (getter_cname
, prop
.property_type
.get_cname ());
581 func
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
583 func
.add_parameter (new
CCodeFormalParameter ("obj", prop
.dynamic_type
.get_cname ()));
585 var block
= new
CCodeBlock ();
586 generate_gobject_property_getter_wrapper (prop
, block
);
588 // append to C source file
589 source_declarations
.add_type_member_declaration (func
.copy ());
592 source_type_member_definition
.append (func
);
597 public override string get_dynamic_property_setter_cname (DynamicProperty prop
) {
598 if (prop
.dynamic_type
.data_type
== null
599 || !prop
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
600 return base.get_dynamic_property_setter_cname (prop
);
603 string setter_cname
= "_dynamic_set_%s%d".printf (prop
.name
, dynamic_property_id
++);
605 var func
= new
CCodeFunction (setter_cname
, "void");
606 func
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
608 func
.add_parameter (new
CCodeFormalParameter ("obj", prop
.dynamic_type
.get_cname ()));
609 func
.add_parameter (new
CCodeFormalParameter ("value", prop
.property_type
.get_cname ()));
611 var block
= new
CCodeBlock ();
612 generate_gobject_property_setter_wrapper (prop
, block
);
614 // append to C source file
615 source_declarations
.add_type_member_declaration (func
.copy ());
618 source_type_member_definition
.append (func
);
623 void generate_gobject_property_getter_wrapper (DynamicProperty node
, CCodeBlock block
) {
624 var cdecl
= new
CCodeDeclaration (node
.property_type
.get_cname ());
625 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result"));
626 block
.add_statement (cdecl
);
628 var call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_get"));
629 call
.add_argument (new
CCodeIdentifier ("obj"));
630 call
.add_argument (node
.get_canonical_cconstant ());
631 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("result")));
632 call
.add_argument (new
CCodeConstant ("NULL"));
634 block
.add_statement (new
CCodeExpressionStatement (call
));
636 block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("result")));
639 void generate_gobject_property_setter_wrapper (DynamicProperty node
, CCodeBlock block
) {
640 var call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_set"));
641 call
.add_argument (new
CCodeIdentifier ("obj"));
642 call
.add_argument (node
.get_canonical_cconstant ());
643 call
.add_argument (new
CCodeIdentifier ("value"));
644 call
.add_argument (new
CCodeConstant ("NULL"));
646 block
.add_statement (new
CCodeExpressionStatement (call
));
649 public override string get_dynamic_signal_cname (DynamicSignal node
) {
650 return "dynamic_%s%d_".printf (node
.name
, signal_wrapper_id
++);
653 public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig
) {
654 if (sig
.dynamic_type
.data_type
== null
655 || !sig
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
656 return base.get_dynamic_signal_connect_wrapper_name (sig
);
659 string connect_wrapper_name
= "_%sconnect".printf (get_dynamic_signal_cname (sig
));
660 var func
= new
CCodeFunction (connect_wrapper_name
, "void");
661 func
.add_parameter (new
CCodeFormalParameter ("obj", "gpointer"));
662 func
.add_parameter (new
CCodeFormalParameter ("signal_name", "const char *"));
663 func
.add_parameter (new
CCodeFormalParameter ("handler", "GCallback"));
664 func
.add_parameter (new
CCodeFormalParameter ("data", "gpointer"));
665 var block
= new
CCodeBlock ();
666 generate_gobject_connect_wrapper (sig
, block
, false);
668 // append to C source file
669 source_declarations
.add_type_member_declaration (func
.copy ());
672 source_type_member_definition
.append (func
);
674 return connect_wrapper_name
;
677 public override string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal sig
) {
678 if (sig
.dynamic_type
.data_type
== null
679 || !sig
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
680 return base.get_dynamic_signal_connect_wrapper_name (sig
);
683 string connect_wrapper_name
= "_%sconnect_after".printf (get_dynamic_signal_cname (sig
));
684 var func
= new
CCodeFunction (connect_wrapper_name
, "void");
685 func
.add_parameter (new
CCodeFormalParameter ("obj", "gpointer"));
686 func
.add_parameter (new
CCodeFormalParameter ("signal_name", "const char *"));
687 func
.add_parameter (new
CCodeFormalParameter ("handler", "GCallback"));
688 func
.add_parameter (new
CCodeFormalParameter ("data", "gpointer"));
689 var block
= new
CCodeBlock ();
690 generate_gobject_connect_wrapper (sig
, block
, true);
692 // append to C source file
693 source_declarations
.add_type_member_declaration (func
.copy ());
696 source_type_member_definition
.append (func
);
698 return connect_wrapper_name
;
701 void generate_gobject_connect_wrapper (DynamicSignal sig
, CCodeBlock block
, bool after
) {
702 var m
= (Method
) sig
.handler
.symbol_reference
;
706 string connect_func
= "g_signal_connect_object";
707 if (m
.binding
!= MemberBinding
.INSTANCE
) {
709 connect_func
= "g_signal_connect";
711 connect_func
= "g_signal_connect_after";
714 var call
= new
CCodeFunctionCall (new
CCodeIdentifier (connect_func
));
715 call
.add_argument (new
CCodeIdentifier ("obj"));
716 call
.add_argument (new
CCodeIdentifier ("signal_name"));
717 call
.add_argument (new
CCodeIdentifier ("handler"));
718 call
.add_argument (new
CCodeIdentifier ("data"));
720 if (m
.binding
== MemberBinding
.INSTANCE
) {
722 call
.add_argument (new
CCodeConstant ("0"));
724 call
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
727 block
.add_statement (new
CCodeExpressionStatement (call
));
730 public override void visit_property (Property prop
) {
731 base.visit_property (prop
);
733 if (is_gobject_property (prop
) && prop
.parent_symbol is Class
) {
734 prop_enum
.add_value (new
CCodeEnumValue (prop
.get_upper_case_cname ()));
738 public override bool is_gobject_property (Property prop
) {
739 var type_sym
= prop
.parent_symbol as ObjectTypeSymbol
;
740 if (type_sym
== null || !type_sym
.is_subtype_of (gobject_type
)) {
744 if (prop
.binding
!= MemberBinding
.INSTANCE
) {
748 if (prop
.access
== SymbolAccessibility
.PRIVATE
) {
752 var st
= prop
.property_type
.data_type as Struct
;
753 if (st
!= null && (!st
.has_type_id
|| prop
.property_type
.nullable
)) {
757 if (prop
.property_type is ArrayType
&& ((ArrayType
)prop
.property_type
).element_type
.data_type
!= string_type
.data_type
) {
761 var d
= prop
.property_type as DelegateType
;
762 if (d
!= null && d
.delegate_symbol
.has_target
) {
766 if (prop
.base_interface_property
!= null) {
767 var iface
= (Interface
) prop
.base_interface_property
.parent_symbol
;
768 if (!iface
.is_subtype_of (gobject_type
)) {
769 // implementing non-GObject property
774 if (!prop
.name
[0].isalpha ()) {
775 // GObject requires properties to start with a letter
782 public override void visit_method_call (MethodCall expr
) {
783 if (expr
.call is MemberAccess
) {
784 var ma
= expr
.call as MemberAccess
;
785 if (ma
.inner
!= null && ma
.inner
.symbol_reference
== gobject_type
&&
786 (ma
.member_name
== "new" || ma
.member_name
== "newv")) {
787 // Object.new (...) creation
788 // runtime check to ref_sink the instance if it's a floating type
789 base.visit_method_call (expr
);
791 var ccomma
= new
CCodeCommaExpression ();
792 var temp_var
= get_temp_variable (expr
.value_type
, false, expr
, false);
793 temp_vars
.add (temp_var
);
794 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), (CCodeExpression
) expr
.ccodenode
));
796 var initiallyunowned_ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_INITIALLY_UNOWNED"));
797 initiallyunowned_ccall
.add_argument (get_variable_cexpression (temp_var
.name
));
798 var sink_ref_ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref_sink"));
799 sink_ref_ccall
.add_argument (get_variable_cexpression (temp_var
.name
));
800 ccomma
.append_expression (new
CCodeConditionalExpression (initiallyunowned_ccall
, sink_ref_ccall
, get_variable_cexpression (temp_var
.name
)));
802 expr
.ccodenode
= ccomma
;
804 } else if (ma
.symbol_reference
== gobject_type
) {
805 // Object (...) chain up
806 // check it's only used with valid properties
807 foreach (var arg
in expr
.get_argument_list ()) {
808 var named_argument
= arg as NamedArgument
;
809 if (named_argument
== null) {
810 Report
.error (arg
.source_reference
, "Named argument expected");
813 var prop
= SemanticAnalyzer
.symbol_lookup_inherited (current_class
, named_argument
.name
) as Property
;
815 Report
.error (arg
.source_reference
, "Property `%s' not found in `%s'".printf (named_argument
.name
, current_class
.get_full_name ()));
818 if (!arg
.value_type
.compatible (prop
.property_type
)) {
819 Report
.error (arg
.source_reference
, "Cannot convert from `%s' to `%s'".printf (arg
.value_type
.to_string (), prop
.property_type
.to_string ()));
826 base.visit_method_call (expr
);