1 /* valagobjectmodule.vala
3 * Copyright (C) 2006-2011 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
) {
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 ccode
.add_assignment (new CCodeMemberAccess
.pointer (ccall
, "get_property"), new
CCodeIdentifier ("_vala_%s_get_property".printf (cl
.get_lower_case_cname (null))));
56 if (class_has_writable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
57 ccode
.add_assignment (new CCodeMemberAccess
.pointer (ccall
, "set_property"), new
CCodeIdentifier ("_vala_%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 ccode
.add_assignment (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 ccode
.add_assignment (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 ccode
.add_expression (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 ccode
.add_expression (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 ccode
.add_expression (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 ccode
.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 ccode
.add_expression (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 ccode
.add_expression (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 ("_vala_%s_get_property".printf (cl
.get_lower_case_cname (null)), "void");
178 get_prop
.modifiers
= CCodeModifiers
.STATIC
;
179 get_prop
.add_parameter (new
CCodeParameter ("object", "GObject *"));
180 get_prop
.add_parameter (new
CCodeParameter ("property_id", "guint"));
181 get_prop
.add_parameter (new
CCodeParameter ("value", "GValue *"));
182 get_prop
.add_parameter (new
CCodeParameter ("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 Property base_prop
= prop
;
206 CCodeExpression cself
= new
CCodeIdentifier ("self");
207 if (prop
.base_property
!= null) {
208 var base_type
= (Class
) prop
.base_property
.parent_symbol
;
209 base_prop
= prop
.base_property
;
210 cself
= transform_expression (cself
, new
ObjectType (cl
), new
ObjectType (base_type
));
212 generate_property_accessor_declaration (prop
.base_property
.get_accessor
, cfile
);
213 } else if (prop
.base_interface_property
!= null) {
214 var base_type
= (Interface
) prop
.base_interface_property
.parent_symbol
;
215 base_prop
= prop
.base_interface_property
;
216 cself
= transform_expression (cself
, new
ObjectType (cl
), new
ObjectType (base_type
));
218 generate_property_accessor_declaration (prop
.base_interface_property
.get_accessor
, cfile
);
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 (base_prop
.get_accessor
.get_cname ()));
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 (base_prop
.get_accessor
.get_cname ()));
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 cfile
.add_function_declaration (get_prop
);
279 get_prop
.block
= block
;
281 cfile
.add_function (get_prop
);
284 private void add_set_property_function (Class cl
) {
285 var set_prop
= new
CCodeFunction ("_vala_%s_set_property".printf (cl
.get_lower_case_cname (null)), "void");
286 set_prop
.modifiers
= CCodeModifiers
.STATIC
;
287 set_prop
.add_parameter (new
CCodeParameter ("object", "GObject *"));
288 set_prop
.add_parameter (new
CCodeParameter ("property_id", "guint"));
289 set_prop
.add_parameter (new
CCodeParameter ("value", "const GValue *"));
290 set_prop
.add_parameter (new
CCodeParameter ("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 Property base_prop
= prop
;
312 CCodeExpression cself
= new
CCodeIdentifier ("self");
313 if (prop
.base_property
!= null) {
314 var base_type
= (Class
) prop
.base_property
.parent_symbol
;
315 base_prop
= prop
.base_property
;
316 cself
= transform_expression (cself
, new
ObjectType (cl
), new
ObjectType (base_type
));
318 generate_property_accessor_declaration (prop
.base_property
.set_accessor
, cfile
);
319 } else if (prop
.base_interface_property
!= null) {
320 var base_type
= (Interface
) prop
.base_interface_property
.parent_symbol
;
321 base_prop
= prop
.base_interface_property
;
322 cself
= transform_expression (cself
, new
ObjectType (cl
), new
ObjectType (base_type
));
324 generate_property_accessor_declaration (prop
.base_interface_property
.set_accessor
, cfile
);
327 cswitch
.add_statement (new
CCodeCaseStatement (new
CCodeIdentifier (prop
.get_upper_case_cname ())));
328 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (base_prop
.set_accessor
.get_cname ()));
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 cfile
.add_function_declaration (set_prop
);
400 set_prop
.block
= block
;
402 cfile
.add_function (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 void visit_constructor (Constructor c
) {
415 if (c
.binding
== MemberBinding
.CLASS
|| c
.binding
== MemberBinding
.STATIC
) {
416 in_static_or_class_context
= true;
418 in_constructor
= true;
421 var cl
= (Class
) c
.parent_symbol
;
423 if (c
.binding
== MemberBinding
.INSTANCE
) {
424 if (!cl
.is_subtype_of (gobject_type
)) {
425 Report
.error (c
.source_reference
, "construct blocks require GLib.Object");
430 push_context (new
EmitContext (c
));
432 var function
= new
CCodeFunction ("%s_constructor".printf (cl
.get_lower_case_cname (null)), "GObject *");
433 function
.modifiers
= CCodeModifiers
.STATIC
;
435 function
.add_parameter (new
CCodeParameter ("type", "GType"));
436 function
.add_parameter (new
CCodeParameter ("n_construct_properties", "guint"));
437 function
.add_parameter (new
CCodeParameter ("construct_properties", "GObjectConstructParam *"));
439 cfile
.add_function_declaration (function
);
441 push_function (function
);
443 ccode
.add_declaration ("GObject *", new
CCodeVariableDeclarator ("obj"));
444 ccode
.add_declaration ("GObjectClass *", new
CCodeVariableDeclarator ("parent_class"));
446 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
447 ccast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (cl
.get_lower_case_cname (null))));
448 ccode
.add_assignment (new
CCodeIdentifier ("parent_class"), ccast
);
450 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("parent_class"), "constructor"));
451 ccall
.add_argument (new
CCodeIdentifier ("type"));
452 ccall
.add_argument (new
CCodeIdentifier ("n_construct_properties"));
453 ccall
.add_argument (new
CCodeIdentifier ("construct_properties"));
454 ccode
.add_assignment (new
CCodeIdentifier ("obj"), ccall
);
457 ccall
= generate_instance_cast (new
CCodeIdentifier ("obj"), cl
);
459 ccode
.add_declaration ("%s *".printf (cl
.get_cname ()), new
CCodeVariableDeclarator ("self"));
460 ccode
.add_assignment (new
CCodeIdentifier ("self"), ccall
);
464 if (current_method_inner_error
) {
465 /* always separate error parameter and inner_error local variable
466 * as error may be set to NULL but we're always interested in inner errors
468 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
471 ccode
.add_return (new
CCodeIdentifier ("obj"));
474 cfile
.add_function (function
);
477 } else if (c
.binding
== MemberBinding
.CLASS
) {
481 Report
.error (c
.source_reference
, "class constructors are not supported in compact classes");
486 push_context (base_init_context
);
490 if (current_method_inner_error
) {
491 /* always separate error parameter and inner_error local variable
492 * as error may be set to NULL but we're always interested in inner errors
494 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
498 } else if (c
.binding
== MemberBinding
.STATIC
) {
499 // static class constructor
503 Report
.error (c
.source_reference
, "static constructors are not supported in compact classes");
508 push_context (class_init_context
);
512 if (current_method_inner_error
) {
513 /* always separate error parameter and inner_error local variable
514 * as error may be set to NULL but we're always interested in inner errors
516 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
521 Report
.error (c
.source_reference
, "internal error: constructors must have instance, class, or static binding");
524 in_static_or_class_context
= false;
526 in_constructor
= false;
529 public override string get_dynamic_property_getter_cname (DynamicProperty prop
) {
530 if (prop
.dynamic_type
.data_type
== null
531 || !prop
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
532 return base.get_dynamic_property_getter_cname (prop
);
535 string getter_cname
= "_dynamic_get_%s%d".printf (prop
.name
, dynamic_property_id
++);
537 var func
= new
CCodeFunction (getter_cname
, prop
.property_type
.get_cname ());
538 func
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
540 func
.add_parameter (new
CCodeParameter ("obj", prop
.dynamic_type
.get_cname ()));
542 var block
= new
CCodeBlock ();
543 generate_gobject_property_getter_wrapper (prop
, block
);
545 // append to C source file
546 cfile
.add_function_declaration (func
);
549 cfile
.add_function (func
);
554 public override string get_dynamic_property_setter_cname (DynamicProperty prop
) {
555 if (prop
.dynamic_type
.data_type
== null
556 || !prop
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
557 return base.get_dynamic_property_setter_cname (prop
);
560 string setter_cname
= "_dynamic_set_%s%d".printf (prop
.name
, dynamic_property_id
++);
562 var func
= new
CCodeFunction (setter_cname
, "void");
563 func
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
565 func
.add_parameter (new
CCodeParameter ("obj", prop
.dynamic_type
.get_cname ()));
566 func
.add_parameter (new
CCodeParameter ("value", prop
.property_type
.get_cname ()));
568 var block
= new
CCodeBlock ();
569 generate_gobject_property_setter_wrapper (prop
, block
);
571 // append to C source file
572 cfile
.add_function_declaration (func
);
575 cfile
.add_function (func
);
580 void generate_gobject_property_getter_wrapper (DynamicProperty node
, CCodeBlock block
) {
581 var cdecl
= new
CCodeDeclaration (node
.property_type
.get_cname ());
582 cdecl
.add_declarator (new
CCodeVariableDeclarator ("result"));
583 block
.add_statement (cdecl
);
585 var call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_get"));
586 call
.add_argument (new
CCodeIdentifier ("obj"));
587 call
.add_argument (node
.get_canonical_cconstant ());
588 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("result")));
589 call
.add_argument (new
CCodeConstant ("NULL"));
591 block
.add_statement (new
CCodeExpressionStatement (call
));
593 block
.add_statement (new
CCodeReturnStatement (new
CCodeIdentifier ("result")));
596 void generate_gobject_property_setter_wrapper (DynamicProperty node
, CCodeBlock block
) {
597 var call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_set"));
598 call
.add_argument (new
CCodeIdentifier ("obj"));
599 call
.add_argument (node
.get_canonical_cconstant ());
600 call
.add_argument (new
CCodeIdentifier ("value"));
601 call
.add_argument (new
CCodeConstant ("NULL"));
603 block
.add_statement (new
CCodeExpressionStatement (call
));
606 public override string get_dynamic_signal_cname (DynamicSignal node
) {
607 return "dynamic_%s%d_".printf (node
.name
, signal_wrapper_id
++);
610 public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig
) {
611 if (sig
.dynamic_type
.data_type
== null
612 || !sig
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
613 return base.get_dynamic_signal_connect_wrapper_name (sig
);
616 string connect_wrapper_name
= "_%sconnect".printf (get_dynamic_signal_cname (sig
));
617 var func
= new
CCodeFunction (connect_wrapper_name
, "void");
618 func
.add_parameter (new
CCodeParameter ("obj", "gpointer"));
619 func
.add_parameter (new
CCodeParameter ("signal_name", "const char *"));
620 func
.add_parameter (new
CCodeParameter ("handler", "GCallback"));
621 func
.add_parameter (new
CCodeParameter ("data", "gpointer"));
622 var block
= new
CCodeBlock ();
623 generate_gobject_connect_wrapper (sig
, block
, false);
625 // append to C source file
626 cfile
.add_function_declaration (func
);
629 cfile
.add_function (func
);
631 return connect_wrapper_name
;
634 public override string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal sig
) {
635 if (sig
.dynamic_type
.data_type
== null
636 || !sig
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
637 return base.get_dynamic_signal_connect_wrapper_name (sig
);
640 string connect_wrapper_name
= "_%sconnect_after".printf (get_dynamic_signal_cname (sig
));
641 var func
= new
CCodeFunction (connect_wrapper_name
, "void");
642 func
.add_parameter (new
CCodeParameter ("obj", "gpointer"));
643 func
.add_parameter (new
CCodeParameter ("signal_name", "const char *"));
644 func
.add_parameter (new
CCodeParameter ("handler", "GCallback"));
645 func
.add_parameter (new
CCodeParameter ("data", "gpointer"));
646 var block
= new
CCodeBlock ();
647 generate_gobject_connect_wrapper (sig
, block
, true);
649 // append to C source file
650 cfile
.add_function_declaration (func
);
653 cfile
.add_function (func
);
655 return connect_wrapper_name
;
658 void generate_gobject_connect_wrapper (DynamicSignal sig
, CCodeBlock block
, bool after
) {
659 var m
= (Method
) sig
.handler
.symbol_reference
;
663 string connect_func
= "g_signal_connect_object";
664 if (m
.binding
!= MemberBinding
.INSTANCE
) {
666 connect_func
= "g_signal_connect";
668 connect_func
= "g_signal_connect_after";
671 var call
= new
CCodeFunctionCall (new
CCodeIdentifier (connect_func
));
672 call
.add_argument (new
CCodeIdentifier ("obj"));
673 call
.add_argument (new
CCodeIdentifier ("signal_name"));
674 call
.add_argument (new
CCodeIdentifier ("handler"));
675 call
.add_argument (new
CCodeIdentifier ("data"));
677 if (m
.binding
== MemberBinding
.INSTANCE
) {
679 call
.add_argument (new
CCodeConstant ("0"));
681 call
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
684 block
.add_statement (new
CCodeExpressionStatement (call
));
687 public override void visit_property (Property prop
) {
688 base.visit_property (prop
);
690 if (is_gobject_property (prop
) && prop
.parent_symbol is Class
) {
691 prop_enum
.add_value (new
CCodeEnumValue (prop
.get_upper_case_cname ()));
695 public override bool is_gobject_property (Property prop
) {
696 var type_sym
= prop
.parent_symbol as ObjectTypeSymbol
;
697 if (type_sym
== null || !type_sym
.is_subtype_of (gobject_type
)) {
701 if (prop
.binding
!= MemberBinding
.INSTANCE
) {
705 if (prop
.access
== SymbolAccessibility
.PRIVATE
) {
709 var st
= prop
.property_type
.data_type as Struct
;
710 if (st
!= null && (!st
.has_type_id
|| prop
.property_type
.nullable
)) {
714 if (prop
.property_type is ArrayType
&& ((ArrayType
)prop
.property_type
).element_type
.data_type
!= string_type
.data_type
) {
718 var d
= prop
.property_type as DelegateType
;
719 if (d
!= null && d
.delegate_symbol
.has_target
) {
723 if (type_sym is Class
&& prop
.base_interface_property
!= null &&
724 !is_gobject_property (prop
.base_interface_property
)) {
728 if (!prop
.name
[0].isalpha ()) {
729 // GObject requires properties to start with a letter
733 if (type_sym is Interface
&& type_sym
.get_attribute ("DBus") != null) {
734 // GObject properties not currently supported in D-Bus interfaces
741 public override void visit_method_call (MethodCall expr
) {
742 if (expr
.call is MemberAccess
) {
743 var ma
= expr
.call as MemberAccess
;
744 if (ma
.inner
!= null && ma
.inner
.symbol_reference
== gobject_type
&&
745 (ma
.member_name
== "new" || ma
.member_name
== "newv")) {
746 // Object.new (...) creation
747 // runtime check to ref_sink the instance if it's a floating type
748 base.visit_method_call (expr
);
750 var ccomma
= new
CCodeCommaExpression ();
751 var temp_var
= get_temp_variable (expr
.value_type
, false, expr
, false);
752 emit_temp_var (temp_var
);
753 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (temp_var
.name
), get_cvalue (expr
)));
755 var initiallyunowned_ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_INITIALLY_UNOWNED"));
756 initiallyunowned_ccall
.add_argument (get_variable_cexpression (temp_var
.name
));
757 var sink_ref_ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref_sink"));
758 sink_ref_ccall
.add_argument (get_variable_cexpression (temp_var
.name
));
759 ccomma
.append_expression (new
CCodeConditionalExpression (initiallyunowned_ccall
, sink_ref_ccall
, get_variable_cexpression (temp_var
.name
)));
761 set_cvalue (expr
, ccomma
);
763 } else if (ma
.symbol_reference
== gobject_type
) {
764 // Object (...) chain up
765 // check it's only used with valid properties
766 foreach (var arg
in expr
.get_argument_list ()) {
767 var named_argument
= arg as NamedArgument
;
768 if (named_argument
== null) {
769 Report
.error (arg
.source_reference
, "Named argument expected");
772 var prop
= SemanticAnalyzer
.symbol_lookup_inherited (current_class
, named_argument
.name
) as Property
;
774 Report
.error (arg
.source_reference
, "Property `%s' not found in `%s'".printf (named_argument
.name
, current_class
.get_full_name ()));
777 if (!is_gobject_property (prop
)) {
778 Report
.error (arg
.source_reference
, "Property `%s' not supported in Object (property: value) constructor chain up".printf (named_argument
.name
));
781 if (!arg
.value_type
.compatible (prop
.property_type
)) {
782 Report
.error (arg
.source_reference
, "Cannot convert from `%s' to `%s'".printf (arg
.value_type
.to_string (), prop
.property_type
.to_string ()));
789 base.visit_method_call (expr
);