1 /* valagobjectmodule.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
27 internal class Vala
.GObjectModule
: GTypeModule
{
28 int dynamic_property_id
;
29 int signal_wrapper_id
;
31 public GObjectModule (CCodeGenerator codegen
, CCodeModule? next
) {
35 public override void visit_class (Class cl
) {
36 base.visit_class (cl
);
38 if (!cl
.is_subtype_of (gobject_type
)) {
42 if (class_has_readable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
43 add_get_property_function (cl
);
45 if (class_has_writable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
46 add_set_property_function (cl
);
50 public override void generate_class_init (Class cl
, CCodeBlock init_block
) {
51 if (!cl
.is_subtype_of (gobject_type
)) {
55 /* set property handlers */
56 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
57 ccall
.add_argument (new
CCodeIdentifier ("klass"));
58 if (class_has_readable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
59 init_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (ccall
, "get_property"), new
CCodeIdentifier ("%s_get_property".printf (cl
.get_lower_case_cname (null))))));
61 if (class_has_writable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
62 init_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (ccall
, "set_property"), new
CCodeIdentifier ("%s_set_property".printf (cl
.get_lower_case_cname (null))))));
66 if (cl
.constructor
!= null) {
67 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
68 ccast
.add_argument (new
CCodeIdentifier ("klass"));
69 init_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (ccast
, "constructor"), new
CCodeIdentifier ("%s_constructor".printf (cl
.get_lower_case_cname (null))))));
72 /* set finalize function */
73 if (cl
.get_fields ().size
> 0 || cl
.destructor
!= null) {
74 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
75 ccast
.add_argument (new
CCodeIdentifier ("klass"));
76 init_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new CCodeMemberAccess
.pointer (ccast
, "finalize"), new
CCodeIdentifier ("%s_finalize".printf (cl
.get_lower_case_cname (null))))));
79 /* create type, dup_func, and destroy_func properties for generic types */
80 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
81 string func_name
, enum_value
;
82 CCodeConstant func_name_constant
;
83 CCodeFunctionCall cinst
, cspec
;
85 func_name
= "%s_type".printf (type_param
.name
.down ());
86 func_name_constant
= new
CCodeConstant ("\"%s-type\"".printf (type_param
.name
.down ()));
87 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
88 cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
89 cinst
.add_argument (ccall
);
90 cinst
.add_argument (new
CCodeConstant (enum_value
));
91 cspec
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_param_spec_gtype"));
92 cspec
.add_argument (func_name_constant
);
93 cspec
.add_argument (new
CCodeConstant ("\"type\""));
94 cspec
.add_argument (new
CCodeConstant ("\"type\""));
95 cspec
.add_argument (new
CCodeIdentifier ("G_TYPE_NONE"));
96 cspec
.add_argument (new
CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
97 cinst
.add_argument (cspec
);
98 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
99 prop_enum
.add_value (new
CCodeEnumValue (enum_value
));
102 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
103 func_name_constant
= new
CCodeConstant ("\"%s-dup-func\"".printf (type_param
.name
.down ()));
104 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
105 cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
106 cinst
.add_argument (ccall
);
107 cinst
.add_argument (new
CCodeConstant (enum_value
));
108 cspec
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_param_spec_pointer"));
109 cspec
.add_argument (func_name_constant
);
110 cspec
.add_argument (new
CCodeConstant ("\"dup func\""));
111 cspec
.add_argument (new
CCodeConstant ("\"dup func\""));
112 cspec
.add_argument (new
CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
113 cinst
.add_argument (cspec
);
114 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
115 prop_enum
.add_value (new
CCodeEnumValue (enum_value
));
118 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
119 func_name_constant
= new
CCodeConstant ("\"%s-destroy-func\"".printf (type_param
.name
.down ()));
120 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
121 cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
122 cinst
.add_argument (ccall
);
123 cinst
.add_argument (new
CCodeConstant (enum_value
));
124 cspec
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_param_spec_pointer"));
125 cspec
.add_argument (func_name_constant
);
126 cspec
.add_argument (new
CCodeConstant ("\"destroy func\""));
127 cspec
.add_argument (new
CCodeConstant ("\"destroy func\""));
128 cspec
.add_argument (new
CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
129 cinst
.add_argument (cspec
);
130 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
131 prop_enum
.add_value (new
CCodeEnumValue (enum_value
));
134 /* create properties */
135 var props
= cl
.get_properties ();
136 foreach (Property prop
in props
) {
137 if (!is_gobject_property (prop
)) {
141 if (prop
.overrides
|| prop
.base_interface_property
!= null) {
142 var cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_override_property"));
143 cinst
.add_argument (ccall
);
144 cinst
.add_argument (new
CCodeConstant (prop
.get_upper_case_cname ()));
145 cinst
.add_argument (prop
.get_canonical_cconstant ());
147 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
149 var cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
150 cinst
.add_argument (ccall
);
151 cinst
.add_argument (new
CCodeConstant (prop
.get_upper_case_cname ()));
152 cinst
.add_argument (head
.get_param_spec (prop
));
154 init_block
.add_statement (new
CCodeExpressionStatement (cinst
));
159 private bool class_has_readable_properties (Class cl
) {
160 foreach (Property prop
in cl
.get_properties ()) {
161 if (prop
.get_accessor
!= null) {
168 private bool class_has_writable_properties (Class cl
) {
169 foreach (Property prop
in cl
.get_properties ()) {
170 if (prop
.set_accessor
!= null) {
177 private void add_get_property_function (Class cl
) {
178 var get_prop
= new
CCodeFunction ("%s_get_property".printf (cl
.get_lower_case_cname (null)), "void");
179 get_prop
.modifiers
= CCodeModifiers
.STATIC
;
180 get_prop
.add_parameter (new
CCodeFormalParameter ("object", "GObject *"));
181 get_prop
.add_parameter (new
CCodeFormalParameter ("property_id", "guint"));
182 get_prop
.add_parameter (new
CCodeFormalParameter ("value", "GValue *"));
183 get_prop
.add_parameter (new
CCodeFormalParameter ("pspec", "GParamSpec *"));
185 var block
= new
CCodeBlock ();
187 CCodeFunctionCall ccall
= generate_instance_cast (new
CCodeIdentifier ("object"), cl
);
188 var cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
189 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", ccall
));
190 block
.add_statement (cdecl
);
192 bool boxed_declared
= false;
194 var cswitch
= new
CCodeSwitchStatement (new
CCodeIdentifier ("property_id"));
195 var props
= cl
.get_properties ();
196 foreach (Property prop
in props
) {
197 if (prop
.get_accessor
== null || prop
.is_abstract
) {
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 if (!boxed_declared
) {
224 cdecl
= new
CCodeDeclaration ("gpointer");
225 cdecl
.add_declarator (new
CCodeVariableDeclarator ("boxed"));
226 block
.add_statement (cdecl
);
227 boxed_declared
= true;
230 var st
= prop
.property_type
.data_type as Struct
;
231 var struct_creation
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_new0"));
232 struct_creation
.add_argument (new
CCodeIdentifier (st
.get_cname ()));
233 struct_creation
.add_argument (new
CCodeConstant ("1"));
234 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("boxed"), struct_creation
)));
235 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_get_%s".printf (prefix
, prop
.name
)));
236 ccall
.add_argument (cself
);
237 ccall
.add_argument (new
CCodeIdentifier ("boxed"));
238 cswitch
.add_statement (new
CCodeExpressionStatement (ccall
));
239 var csetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
240 csetcall
.add_argument (new
CCodeIdentifier ("value"));
241 csetcall
.add_argument (new
CCodeIdentifier ("boxed"));
242 cswitch
.add_statement (new
CCodeExpressionStatement (csetcall
));
244 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_get_%s".printf (prefix
, prop
.name
)));
245 ccall
.add_argument (cself
);
246 var csetcall
= new
CCodeFunctionCall ();
247 csetcall
.call
= head
.get_value_setter_function (prop
.property_type
);
248 csetcall
.add_argument (new
CCodeIdentifier ("value"));
249 csetcall
.add_argument (ccall
);
250 cswitch
.add_statement (new
CCodeExpressionStatement (csetcall
));
252 cswitch
.add_statement (new
CCodeBreakStatement ());
254 cswitch
.add_statement (new
CCodeLabel ("default"));
255 cswitch
.add_statement (get_invalid_property_id_warn_statement ());
256 cswitch
.add_statement (new
CCodeBreakStatement ());
258 block
.add_statement (cswitch
);
260 source_declarations
.add_type_member_declaration (get_prop
.copy ());
262 get_prop
.block
= block
;
264 source_type_member_definition
.append (get_prop
);
267 private void add_set_property_function (Class cl
) {
268 var set_prop
= new
CCodeFunction ("%s_set_property".printf (cl
.get_lower_case_cname (null)), "void");
269 set_prop
.modifiers
= CCodeModifiers
.STATIC
;
270 set_prop
.add_parameter (new
CCodeFormalParameter ("object", "GObject *"));
271 set_prop
.add_parameter (new
CCodeFormalParameter ("property_id", "guint"));
272 set_prop
.add_parameter (new
CCodeFormalParameter ("value", "const GValue *"));
273 set_prop
.add_parameter (new
CCodeFormalParameter ("pspec", "GParamSpec *"));
275 var block
= new
CCodeBlock ();
277 CCodeFunctionCall ccall
= generate_instance_cast (new
CCodeIdentifier ("object"), cl
);
278 var cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
279 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", ccall
));
280 block
.add_statement (cdecl
);
282 var cswitch
= new
CCodeSwitchStatement (new
CCodeIdentifier ("property_id"));
283 var props
= cl
.get_properties ();
284 foreach (Property prop
in props
) {
285 if (prop
.set_accessor
== null || prop
.is_abstract
) {
288 if (!is_gobject_property (prop
)) {
292 string prefix
= cl
.get_lower_case_cname (null);
293 CCodeExpression cself
= new
CCodeIdentifier ("self");
294 if (prop
.base_property
!= null) {
295 var base_type
= (Class
) prop
.base_property
.parent_symbol
;
296 prefix
= base_type
.get_lower_case_cname (null);
297 cself
= transform_expression (cself
, new
ObjectType (cl
), new
ObjectType (base_type
));
299 generate_property_accessor_declaration (prop
.base_property
.set_accessor
, source_declarations
);
300 } else if (prop
.base_interface_property
!= null) {
301 var base_type
= (Interface
) prop
.base_interface_property
.parent_symbol
;
302 prefix
= base_type
.get_lower_case_cname (null);
303 cself
= transform_expression (cself
, new
ObjectType (cl
), new
ObjectType (base_type
));
305 generate_property_accessor_declaration (prop
.base_interface_property
.set_accessor
, source_declarations
);
308 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (prop
.get_upper_case_cname ())));
309 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_set_%s".printf (prefix
, prop
.name
)));
310 ccall
.add_argument (cself
);
311 var cgetcall
= new
CCodeFunctionCall ();
312 if (prop
.property_type
.data_type
!= null) {
313 cgetcall
.call
= new
CCodeIdentifier (prop
.property_type
.data_type
.get_get_value_function ());
315 cgetcall
.call
= new
CCodeIdentifier ("g_value_get_pointer");
317 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
318 ccall
.add_argument (cgetcall
);
319 cswitch
.add_statement (new
CCodeExpressionStatement (ccall
));
320 cswitch
.add_statement (new
CCodeBreakStatement ());
322 cswitch
.add_statement (new
CCodeLabel ("default"));
323 cswitch
.add_statement (get_invalid_property_id_warn_statement ());
324 cswitch
.add_statement (new
CCodeBreakStatement ());
326 block
.add_statement (cswitch
);
328 /* type, dup func, and destroy func properties for generic types */
329 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
330 string func_name
, enum_value
;
331 CCodeMemberAccess cfield
;
332 CCodeFunctionCall cgetcall
;
334 func_name
= "%s_type".printf (type_param
.name
.down ());
335 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
336 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (enum_value
)));
337 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
338 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_gtype"));
339 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
340 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (cfield
, cgetcall
)));
341 cswitch
.add_statement (new
CCodeBreakStatement ());
343 func_name
= "%s_dup_func".printf (type_param
.name
.down ());
344 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
345 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (enum_value
)));
346 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
347 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_pointer"));
348 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
349 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (cfield
, cgetcall
)));
350 cswitch
.add_statement (new
CCodeBreakStatement ());
352 func_name
= "%s_destroy_func".printf (type_param
.name
.down ());
353 enum_value
= "%s_%s".printf (cl
.get_lower_case_cname (null), func_name
).up ();
354 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (enum_value
)));
355 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
356 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_pointer"));
357 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
358 cswitch
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (cfield
, cgetcall
)));
359 cswitch
.add_statement (new
CCodeBreakStatement ());
362 source_declarations
.add_type_member_declaration (set_prop
.copy ());
364 set_prop
.block
= block
;
366 source_type_member_definition
.append (set_prop
);
369 private CCodeStatement
get_invalid_property_id_warn_statement () {
370 // warn on invalid property id
371 var cwarn
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
372 cwarn
.add_argument (new
CCodeIdentifier ("object"));
373 cwarn
.add_argument (new
CCodeIdentifier ("property_id"));
374 cwarn
.add_argument (new
CCodeIdentifier ("pspec"));
375 return new
CCodeExpressionStatement (cwarn
);
378 public override CCodeExpression
get_construct_property_assignment (CCodeConstant canonical_cconstant
, DataType property_type
, CCodeExpression value
) {
379 // this property is used as a construction parameter
380 var cpointer
= new
CCodeIdentifier ("__params_it");
382 var ccomma
= new
CCodeCommaExpression ();
383 // set name in array for current parameter
384 var cnamemember
= new CCodeMemberAccess
.pointer (cpointer
, "name");
385 var cnameassign
= new
CCodeAssignment (cnamemember
, canonical_cconstant
);
386 ccomma
.append_expression (cnameassign
);
388 var gvaluearg
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new CCodeMemberAccess
.pointer (cpointer
, "value"));
390 // initialize GValue in array for current parameter
391 var cvalueinit
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_init"));
392 cvalueinit
.add_argument (gvaluearg
);
393 cvalueinit
.add_argument (new
CCodeIdentifier (property_type
.get_type_id ()));
394 ccomma
.append_expression (cvalueinit
);
396 // set GValue for current parameter
397 var cvalueset
= new
CCodeFunctionCall (get_value_setter_function (property_type
));
398 cvalueset
.add_argument (gvaluearg
);
399 if (property_type
.is_real_struct_type ()) {
400 cvalueset
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, value
));
402 cvalueset
.add_argument (value
);
404 ccomma
.append_expression (cvalueset
);
406 // move pointer to next parameter in array
407 ccomma
.append_expression (new
CCodeUnaryExpression (CCodeUnaryOperator
.POSTFIX_INCREMENT
, cpointer
));
412 public override void visit_constructor (Constructor c
) {
413 bool old_method_inner_error
= current_method_inner_error
;
414 current_method_inner_error
= false;
416 if (c
.binding
== MemberBinding
.CLASS
|| c
.binding
== MemberBinding
.STATIC
) {
417 in_static_or_class_context
= true;
419 in_constructor
= true;
421 c
.accept_children (codegen
);
422 in_static_or_class_context
= false;
424 in_constructor
= false;
426 var cl
= (Class
) c
.parent_symbol
;
428 if (c
.binding
== MemberBinding
.INSTANCE
) {
429 if (!cl
.is_subtype_of (gobject_type
)) {
430 Report
.error (c
.source_reference
, "construct blocks require GLib.Object");
435 function
= new
CCodeFunction ("%s_constructor".printf (cl
.get_lower_case_cname (null)), "GObject *");
436 function
.modifiers
= CCodeModifiers
.STATIC
;
438 function
.add_parameter (new
CCodeFormalParameter ("type", "GType"));
439 function
.add_parameter (new
CCodeFormalParameter ("n_construct_properties", "guint"));
440 function
.add_parameter (new
CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
442 source_declarations
.add_type_member_declaration (function
.copy ());
445 var cblock
= new
CCodeBlock ();
446 var cdecl
= new
CCodeDeclaration ("GObject *");
447 cdecl
.add_declarator (new
CCodeVariableDeclarator ("obj"));
448 cblock
.add_statement (cdecl
);
450 cdecl
= new
CCodeDeclaration ("GObjectClass *");
451 cdecl
.add_declarator (new
CCodeVariableDeclarator ("parent_class"));
452 cblock
.add_statement (cdecl
);
455 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
456 ccast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (cl
.get_lower_case_cname (null))));
457 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("parent_class"), ccast
)));
460 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("parent_class"), "constructor"));
461 ccall
.add_argument (new
CCodeIdentifier ("type"));
462 ccall
.add_argument (new
CCodeIdentifier ("n_construct_properties"));
463 ccall
.add_argument (new
CCodeIdentifier ("construct_properties"));
464 cblock
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("obj"), ccall
)));
467 ccall
= generate_instance_cast (new
CCodeIdentifier ("obj"), cl
);
469 cdecl
= new
CCodeDeclaration ("%s *".printf (cl
.get_cname ()));
470 cdecl
.add_declarator (new
CCodeVariableDeclarator ("self", ccall
));
471 cblock
.add_statement (cdecl
);
473 if (current_method_inner_error
) {
474 /* always separate error parameter and inner_error local variable
475 * as error may be set to NULL but we're always interested in inner errors
477 cdecl
= new
CCodeDeclaration ("GError *");
478 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_inner_error_", new
CCodeConstant ("NULL")));
479 cblock
.add_statement (cdecl
);
483 cblock
.add_statement (c
.body
.ccodenode
);
485 cblock
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("obj")));
487 function
.block
= cblock
;
489 source_type_member_definition
.append (function
);
490 } else if (c
.binding
== MemberBinding
.CLASS
) {
494 Report
.error (c
.source_reference
, "class constructors are not supported in compact classes");
499 if (current_method_inner_error
) {
500 /* always separate error parameter and inner_error local variable
501 * as error may be set to NULL but we're always interested in inner errors
503 var cdecl
= new
CCodeDeclaration ("GError *");
504 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_inner_error_", new
CCodeConstant ("NULL")));
505 base_init_fragment
.append (cdecl
);
508 base_init_fragment
.append (c
.body
.ccodenode
);
509 } else if (c
.binding
== MemberBinding
.STATIC
) {
510 // static class constructor
514 Report
.error (c
.source_reference
, "static constructors are not supported in compact classes");
519 if (current_method_inner_error
) {
520 /* always separate error parameter and inner_error local variable
521 * as error may be set to NULL but we're always interested in inner errors
523 var cdecl
= new
CCodeDeclaration ("GError *");
524 cdecl
.add_declarator (new
CCodeVariableDeclarator ("_inner_error_", new
CCodeConstant ("NULL")));
525 class_init_fragment
.append (cdecl
);
528 class_init_fragment
.append (c
.body
.ccodenode
);
530 Report
.error (c
.source_reference
, "internal error: constructors must have instance, class, or static binding");
533 current_method_inner_error
= old_method_inner_error
;
536 public override string get_dynamic_property_getter_cname (DynamicProperty prop
) {
537 if (prop
.dynamic_type
.data_type
== null
538 || !prop
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
539 return base.get_dynamic_property_getter_cname (prop
);
542 string getter_cname
= "_dynamic_get_%s%d".printf (prop
.name
, dynamic_property_id
++);
544 var func
= new
CCodeFunction (getter_cname
, prop
.property_type
.get_cname ());
545 func
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
547 func
.add_parameter (new
CCodeFormalParameter ("obj", prop
.dynamic_type
.get_cname ()));
549 var block
= new
CCodeBlock ();
550 generate_gobject_property_getter_wrapper (prop
, block
);
552 // append to C source file
553 source_declarations
.add_type_member_declaration (func
.copy ());
556 source_type_member_definition
.append (func
);
561 public override string get_dynamic_property_setter_cname (DynamicProperty prop
) {
562 if (prop
.dynamic_type
.data_type
== null
563 || !prop
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
564 return base.get_dynamic_property_setter_cname (prop
);
567 string setter_cname
= "_dynamic_set_%s%d".printf (prop
.name
, dynamic_property_id
++);
569 var func
= new
CCodeFunction (setter_cname
, "void");
570 func
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
572 func
.add_parameter (new
CCodeFormalParameter ("obj", prop
.dynamic_type
.get_cname ()));
573 func
.add_parameter (new
CCodeFormalParameter ("value", prop
.property_type
.get_cname ()));
575 var block
= new
CCodeBlock ();
576 generate_gobject_property_setter_wrapper (prop
, block
);
578 // append to C source file
579 source_declarations
.add_type_member_declaration (func
.copy ());
582 source_type_member_definition
.append (func
);
587 void generate_gobject_property_getter_wrapper (DynamicProperty node
, CCodeBlock block
) {
588 var cdecl
= new
CCodeDeclaration (node
.property_type
.get_cname ());
589 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result"));
590 block
.add_statement (cdecl
);
592 var call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_get"));
593 call
.add_argument (new
CCodeIdentifier ("obj"));
594 call
.add_argument (node
.get_canonical_cconstant ());
595 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("result")));
596 call
.add_argument (new
CCodeConstant ("NULL"));
598 block
.add_statement (new
CCodeExpressionStatement (call
));
600 block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("result")));
603 void generate_gobject_property_setter_wrapper (DynamicProperty node
, CCodeBlock block
) {
604 var call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_set"));
605 call
.add_argument (new
CCodeIdentifier ("obj"));
606 call
.add_argument (node
.get_canonical_cconstant ());
607 call
.add_argument (new
CCodeIdentifier ("value"));
608 call
.add_argument (new
CCodeConstant ("NULL"));
610 block
.add_statement (new
CCodeExpressionStatement (call
));
613 public override string get_dynamic_signal_cname (DynamicSignal node
) {
614 return "dynamic_%s%d_".printf (node
.name
, signal_wrapper_id
++);
617 public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig
) {
618 if (sig
.dynamic_type
.data_type
== null
619 || !sig
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
620 return base.get_dynamic_signal_connect_wrapper_name (sig
);
623 string connect_wrapper_name
= "_%sconnect".printf (get_dynamic_signal_cname (sig
));
624 var func
= new
CCodeFunction (connect_wrapper_name
, "void");
625 func
.add_parameter (new
CCodeFormalParameter ("obj", "gpointer"));
626 func
.add_parameter (new
CCodeFormalParameter ("signal_name", "const char *"));
627 func
.add_parameter (new
CCodeFormalParameter ("handler", "GCallback"));
628 func
.add_parameter (new
CCodeFormalParameter ("data", "gpointer"));
629 var block
= new
CCodeBlock ();
630 generate_gobject_connect_wrapper (sig
, block
);
632 // append to C source file
633 source_declarations
.add_type_member_declaration (func
.copy ());
636 source_type_member_definition
.append (func
);
638 return connect_wrapper_name
;
641 void generate_gobject_connect_wrapper (DynamicSignal sig
, CCodeBlock block
) {
642 var m
= (Method
) sig
.handler
.symbol_reference
;
644 sig
.accept (codegen
);
646 string connect_func
= "g_signal_connect_object";
647 if (m
.binding
!= MemberBinding
.INSTANCE
) {
648 connect_func
= "g_signal_connect";
651 var call
= new
CCodeFunctionCall (new
CCodeIdentifier (connect_func
));
652 call
.add_argument (new
CCodeIdentifier ("obj"));
653 call
.add_argument (new
CCodeIdentifier ("signal_name"));
654 call
.add_argument (new
CCodeIdentifier ("handler"));
655 call
.add_argument (new
CCodeIdentifier ("data"));
657 if (m
.binding
== MemberBinding
.INSTANCE
) {
658 call
.add_argument (new
CCodeConstant ("0"));
661 block
.add_statement (new
CCodeExpressionStatement (call
));
664 public override void visit_property (Property prop
) {
665 base.visit_property (prop
);
667 if (is_gobject_property (prop
)) {
668 prop_enum
.add_value (new
CCodeEnumValue (prop
.get_upper_case_cname ()));
672 public override bool is_gobject_property (Property prop
) {
673 var cl
= prop
.parent_symbol as Class
;
674 if (cl
== null || !cl
.is_subtype_of (gobject_type
)) {
678 if (prop
.binding
!= MemberBinding
.INSTANCE
) {
682 if (prop
.access
== SymbolAccessibility
.PRIVATE
) {
686 var st
= prop
.property_type
.data_type as Struct
;
687 if (st
!= null && (!st
.has_type_id
|| prop
.property_type
.nullable
)) {
691 if (prop
.property_type is ArrayType
) {
695 var d
= prop
.property_type as DelegateType
;
696 if (d
!= null && d
.delegate_symbol
.has_target
) {
700 if (prop
.base_interface_property
!= null) {
701 var iface
= (Interface
) prop
.base_interface_property
.parent_symbol
;
702 if (!iface
.is_subtype_of (gobject_type
)) {
703 // implementing non-GObject property
708 if (!prop
.name
[0].isalpha ()) {
709 // GObject requires properties to start with a letter