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 push_line (cl
.source_reference
);
38 if (class_has_readable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
39 add_get_property_function (cl
);
41 if (class_has_writable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
42 add_set_property_function (cl
);
47 public override void generate_class_init (Class cl
) {
48 if (!cl
.is_subtype_of (gobject_type
)) {
52 /* set property handlers */
53 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
54 ccall
.add_argument (new
CCodeIdentifier ("klass"));
55 if (class_has_readable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
56 ccode
.add_assignment (new CCodeMemberAccess
.pointer (ccall
, "get_property"), new
CCodeIdentifier ("_vala_%s_get_property".printf (get_ccode_lower_case_name (cl
, null))));
58 if (class_has_writable_properties (cl
) || cl
.get_type_parameters ().size
> 0) {
59 ccode
.add_assignment (new CCodeMemberAccess
.pointer (ccall
, "set_property"), new
CCodeIdentifier ("_vala_%s_set_property".printf (get_ccode_lower_case_name (cl
, null))));
63 if (cl
.constructor
!= null) {
64 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
65 ccast
.add_argument (new
CCodeIdentifier ("klass"));
66 ccode
.add_assignment (new CCodeMemberAccess
.pointer (ccast
, "constructor"), new
CCodeIdentifier ("%s_constructor".printf (get_ccode_lower_case_name (cl
, null))));
69 /* set finalize function */
70 if (cl
.get_fields ().size
> 0 || cl
.destructor
!= null) {
71 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
72 ccast
.add_argument (new
CCodeIdentifier ("klass"));
73 ccode
.add_assignment (new CCodeMemberAccess
.pointer (ccast
, "finalize"), new
CCodeIdentifier ("%s_finalize".printf (get_ccode_lower_case_name (cl
, null))));
76 /* create type, dup_func, and destroy_func properties for generic types */
77 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
78 string func_name
, enum_value
;
79 CCodeConstant func_name_constant
;
80 CCodeFunctionCall cinst
, cspec
;
82 var name_prefix
= type_param
.name
.down ();
83 var canonical_prefix
= name_prefix
.replace ("_", "-");
85 func_name
= "%s_type".printf (name_prefix
);
86 func_name_constant
= new
CCodeConstant ("\"%s-type\"".printf (canonical_prefix
));
87 enum_value
= "%s_%s".printf (get_ccode_lower_case_name (cl
, null), func_name
).ascii_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_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
97 cinst
.add_argument (cspec
);
98 ccode
.add_expression (cinst
);
99 prop_enum
.add_value (new
CCodeEnumValue (enum_value
));
102 func_name
= "%s_dup_func".printf (name_prefix
);
103 func_name_constant
= new
CCodeConstant ("\"%s-dup-func\"".printf (canonical_prefix
));
104 enum_value
= "%s_%s".printf (get_ccode_lower_case_name (cl
, null), func_name
).ascii_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_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
113 cinst
.add_argument (cspec
);
114 ccode
.add_expression (cinst
);
115 prop_enum
.add_value (new
CCodeEnumValue (enum_value
));
118 func_name
= "%s_destroy_func".printf (name_prefix
);
119 func_name_constant
= new
CCodeConstant ("\"%s-destroy-func\"".printf (canonical_prefix
));
120 enum_value
= "%s_%s".printf (get_ccode_lower_case_name (cl
, null), func_name
).ascii_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_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY"));
129 cinst
.add_argument (cspec
);
130 ccode
.add_expression (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
)) {
138 if (!has_valid_gobject_property_type (prop
)) {
139 Report
.warning (prop
.source_reference
, "Type `%s' can not be used for a GLib.Object property".printf (prop
.property_type
.to_qualified_string ()));
144 if (prop
.comment
!= null) {
145 ccode
.add_statement (new
CCodeComment (prop
.comment
.content
));
148 var cinst
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_class_install_property"));
149 cinst
.add_argument (ccall
);
150 cinst
.add_argument (new
CCodeConstant ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop
))));
151 cinst
.add_argument (get_param_spec (prop
));
153 ccode
.add_expression (cinst
);
157 private bool class_has_readable_properties (Class cl
) {
158 foreach (Property prop
in cl
.get_properties ()) {
159 if (prop
.get_accessor
!= null) {
166 private bool class_has_writable_properties (Class cl
) {
167 foreach (Property prop
in cl
.get_properties ()) {
168 if (prop
.set_accessor
!= null) {
175 private void add_guarded_expression (Symbol sym
, CCodeExpression expression
) {
176 // prevent deprecation warnings
177 if (sym
.version
.deprecated
) {
178 var guard
= new
CCodeGGnucSection (GGnucSectionType
.IGNORE_DEPRECATIONS
);
179 ccode
.add_statement (guard
);
180 guard
.append (new
CCodeExpressionStatement (expression
));
182 ccode
.add_expression (expression
);
186 private void add_get_property_function (Class cl
) {
187 var get_prop
= new
CCodeFunction ("_vala_%s_get_property".printf (get_ccode_lower_case_name (cl
, null)), "void");
188 get_prop
.modifiers
= CCodeModifiers
.STATIC
;
189 get_prop
.add_parameter (new
CCodeParameter ("object", "GObject *"));
190 get_prop
.add_parameter (new
CCodeParameter ("property_id", "guint"));
191 get_prop
.add_parameter (new
CCodeParameter ("value", "GValue *"));
192 get_prop
.add_parameter (new
CCodeParameter ("pspec", "GParamSpec *"));
194 push_function (get_prop
);
196 CCodeFunctionCall ccall
= generate_instance_cast (new
CCodeIdentifier ("object"), cl
);
197 ccode
.add_declaration ("%s *".printf (get_ccode_name (cl
)), new
CCodeVariableDeclarator ("self", ccall
));
199 ccode
.open_switch (new
CCodeIdentifier ("property_id"));
200 var props
= cl
.get_properties ();
201 foreach (Property prop
in props
) {
202 if (prop
.get_accessor
== null || prop
.is_abstract
) {
205 if (!is_gobject_property (prop
)) {
206 // don't register private properties
210 Property base_prop
= prop
;
211 CCodeExpression cself
= new
CCodeIdentifier ("self");
212 if (prop
.base_property
!= null) {
213 var base_type
= (Class
) prop
.base_property
.parent_symbol
;
214 base_prop
= prop
.base_property
;
215 cself
= get_cvalue_ (transform_value (new
GLibValue (new
ObjectType (cl
), cself
, true), new
ObjectType (base_type
), prop
));
217 generate_property_accessor_declaration (prop
.base_property
.get_accessor
, cfile
);
218 } else if (prop
.base_interface_property
!= null) {
219 var base_type
= (Interface
) prop
.base_interface_property
.parent_symbol
;
220 base_prop
= prop
.base_interface_property
;
221 cself
= get_cvalue_ (transform_value (new
GLibValue (new
ObjectType (cl
), cself
, true), new
ObjectType (base_type
), prop
));
223 generate_property_accessor_declaration (prop
.base_interface_property
.get_accessor
, cfile
);
226 CCodeExpression cfunc
;
227 if (!get_ccode_no_accessor_method (base_prop
) && !get_ccode_concrete_accessor (base_prop
)) {
228 cfunc
= new
CCodeIdentifier (get_ccode_name (base_prop
.get_accessor
));
230 // use the static real function as helper
231 cfunc
= new
CCodeIdentifier (get_ccode_real_name (prop
.get_accessor
));
234 ccode
.add_case (new
CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop
))));
235 if (prop
.property_type
.is_real_struct_type ()) {
236 var st
= prop
.property_type
.data_type as Struct
;
239 ccode
.add_declaration (get_ccode_name (st
), new
CCodeVariableDeclarator ("boxed"));
241 ccall
= new
CCodeFunctionCall (cfunc
);
242 ccall
.add_argument (cself
);
243 var boxed_addr
= new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("boxed"));
244 ccall
.add_argument (boxed_addr
);
245 ccode
.add_expression (ccall
);
247 var csetcall
= new
CCodeFunctionCall ();
248 csetcall
.call
= get_value_setter_function (prop
.property_type
);
249 csetcall
.add_argument (new
CCodeIdentifier ("value"));
250 csetcall
.add_argument (boxed_addr
);
251 add_guarded_expression (prop
, csetcall
);
253 if (requires_destroy (prop
.get_accessor
.value_type
)) {
254 ccode
.add_expression (destroy_value (new
GLibValue (prop
.get_accessor
.value_type
, new
CCodeIdentifier ("boxed"), true)));
258 ccall
= new
CCodeFunctionCall (cfunc
);
259 ccall
.add_argument (cself
);
260 var array_type
= prop
.property_type as ArrayType
;
261 if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
264 ccode
.add_declaration ("int", new
CCodeVariableDeclarator ("length"));
265 ccall
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("length")));
267 var csetcall
= new
CCodeFunctionCall ();
268 if (prop
.get_accessor
.value_type
.value_owned
) {
269 csetcall
.call
= get_value_taker_function (prop
.property_type
);
271 csetcall
.call
= get_value_setter_function (prop
.property_type
);
273 csetcall
.add_argument (new
CCodeIdentifier ("value"));
274 csetcall
.add_argument (ccall
);
275 add_guarded_expression (prop
, csetcall
);
276 if (array_type
!= null && array_type
.element_type
.data_type
== string_type
.data_type
) {
282 ccode
.add_default ();
283 emit_invalid_property_id_warn ();
290 cfile
.add_function_declaration (get_prop
);
291 cfile
.add_function (get_prop
);
294 private void add_set_property_function (Class cl
) {
295 var set_prop
= new
CCodeFunction ("_vala_%s_set_property".printf (get_ccode_lower_case_name (cl
, null)), "void");
296 set_prop
.modifiers
= CCodeModifiers
.STATIC
;
297 set_prop
.add_parameter (new
CCodeParameter ("object", "GObject *"));
298 set_prop
.add_parameter (new
CCodeParameter ("property_id", "guint"));
299 set_prop
.add_parameter (new
CCodeParameter ("value", "const GValue *"));
300 set_prop
.add_parameter (new
CCodeParameter ("pspec", "GParamSpec *"));
302 push_function (set_prop
);
304 CCodeFunctionCall ccall
= generate_instance_cast (new
CCodeIdentifier ("object"), cl
);
305 ccode
.add_declaration ("%s *".printf (get_ccode_name (cl
)), new
CCodeVariableDeclarator ("self", ccall
));
307 ccode
.open_switch (new
CCodeIdentifier ("property_id"));
308 var props
= cl
.get_properties ();
309 foreach (Property prop
in props
) {
310 if (prop
.set_accessor
== null || prop
.is_abstract
) {
313 if (!is_gobject_property (prop
)) {
317 Property base_prop
= prop
;
318 CCodeExpression cself
= new
CCodeIdentifier ("self");
319 if (prop
.base_property
!= null) {
320 var base_type
= (Class
) prop
.base_property
.parent_symbol
;
321 base_prop
= prop
.base_property
;
322 cself
= get_cvalue_ (transform_value (new
GLibValue (new
ObjectType (cl
), cself
, true), new
ObjectType (base_type
), prop
));
324 generate_property_accessor_declaration (prop
.base_property
.set_accessor
, cfile
);
325 } else if (prop
.base_interface_property
!= null) {
326 var base_type
= (Interface
) prop
.base_interface_property
.parent_symbol
;
327 base_prop
= prop
.base_interface_property
;
328 cself
= get_cvalue_ (transform_value (new
GLibValue (new
ObjectType (cl
), cself
, true), new
ObjectType (base_type
), prop
));
330 generate_property_accessor_declaration (prop
.base_interface_property
.set_accessor
, cfile
);
333 CCodeExpression cfunc
;
334 if (!get_ccode_no_accessor_method (base_prop
) && !get_ccode_concrete_accessor (base_prop
)) {
335 cfunc
= new
CCodeIdentifier (get_ccode_name (base_prop
.set_accessor
));
337 // use the static real function as helper
338 cfunc
= new
CCodeIdentifier (get_ccode_real_name (prop
.set_accessor
));
341 ccode
.add_case (new
CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop
))));
342 ccall
= new
CCodeFunctionCall (cfunc
);
343 ccall
.add_argument (cself
);
344 if (prop
.property_type is ArrayType
&& ((ArrayType
)prop
.property_type
).element_type
.data_type
== string_type
.data_type
) {
346 ccode
.add_declaration ("gpointer", new
CCodeVariableDeclarator ("boxed"));
348 var cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_boxed"));
349 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
350 ccode
.add_assignment (new
CCodeIdentifier ("boxed"), cgetcall
);
351 ccall
.add_argument (new
CCodeIdentifier ("boxed"));
353 var cisnull
= new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("boxed"), new
CCodeConstant ("NULL"));
354 var cstrvlen
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strv_length"));
355 cstrvlen
.add_argument (new
CCodeIdentifier ("boxed"));
356 var ccond
= new
CCodeConditionalExpression (cisnull
, new
CCodeConstant ("0"), cstrvlen
);
358 ccall
.add_argument (ccond
);
359 add_guarded_expression (prop
, ccall
);
362 var cgetcall
= new
CCodeFunctionCall ();
363 if (prop
.property_type
.data_type
!= null) {
364 cgetcall
.call
= new
CCodeIdentifier (get_ccode_get_value_function (prop
.property_type
.data_type
));
366 cgetcall
.call
= new
CCodeIdentifier ("g_value_get_pointer");
368 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
369 ccall
.add_argument (cgetcall
);
370 add_guarded_expression (prop
, ccall
);
375 /* type, dup func, and destroy func properties for generic types */
376 foreach (TypeParameter type_param
in cl
.get_type_parameters ()) {
377 string func_name
, enum_value
;
378 CCodeMemberAccess cfield
;
379 CCodeFunctionCall cgetcall
;
381 func_name
= "%s_type".printf (type_param
.name
.ascii_down ());
382 enum_value
= "%s_%s".printf (get_ccode_lower_case_name (cl
, null), func_name
).ascii_up ();
383 ccode
.add_case (new
CCodeIdentifier (enum_value
));
384 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
385 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_gtype"));
386 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
387 ccode
.add_assignment (cfield
, cgetcall
);
390 func_name
= "%s_dup_func".printf (type_param
.name
.ascii_down ());
391 enum_value
= "%s_%s".printf (get_ccode_lower_case_name (cl
, null), func_name
).ascii_up ();
392 ccode
.add_case (new
CCodeIdentifier (enum_value
));
393 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
394 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_pointer"));
395 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
396 ccode
.add_assignment (cfield
, cgetcall
);
399 func_name
= "%s_destroy_func".printf (type_param
.name
.ascii_down ());
400 enum_value
= "%s_%s".printf (get_ccode_lower_case_name (cl
, null), func_name
).ascii_up ();
401 ccode
.add_case (new
CCodeIdentifier (enum_value
));
402 cfield
= new CCodeMemberAccess
.pointer (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("self"), "priv"), func_name
);
403 cgetcall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_pointer"));
404 cgetcall
.add_argument (new
CCodeIdentifier ("value"));
405 ccode
.add_assignment (cfield
, cgetcall
);
408 ccode
.add_default ();
409 emit_invalid_property_id_warn ();
416 cfile
.add_function_declaration (set_prop
);
417 cfile
.add_function (set_prop
);
420 private void emit_invalid_property_id_warn () {
421 // warn on invalid property id
422 var cwarn
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
423 cwarn
.add_argument (new
CCodeIdentifier ("object"));
424 cwarn
.add_argument (new
CCodeIdentifier ("property_id"));
425 cwarn
.add_argument (new
CCodeIdentifier ("pspec"));
426 ccode
.add_expression (cwarn
);
429 public override void visit_constructor (Constructor c
) {
430 push_line (c
.source_reference
);
432 var cl
= (Class
) c
.parent_symbol
;
434 if (c
.binding
== MemberBinding
.INSTANCE
) {
435 if (!cl
.is_subtype_of (gobject_type
)) {
436 Report
.error (c
.source_reference
, "construct blocks require GLib.Object");
441 push_context (new
EmitContext (c
));
443 var function
= new
CCodeFunction ("%s_constructor".printf (get_ccode_lower_case_name (cl
, null)), "GObject *");
444 function
.modifiers
= CCodeModifiers
.STATIC
;
446 function
.add_parameter (new
CCodeParameter ("type", "GType"));
447 function
.add_parameter (new
CCodeParameter ("n_construct_properties", "guint"));
448 function
.add_parameter (new
CCodeParameter ("construct_properties", "GObjectConstructParam *"));
450 cfile
.add_function_declaration (function
);
452 push_function (function
);
454 ccode
.add_declaration ("GObject *", new
CCodeVariableDeclarator ("obj"));
455 ccode
.add_declaration ("GObjectClass *", new
CCodeVariableDeclarator ("parent_class"));
457 var ccast
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_OBJECT_CLASS"));
458 ccast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (cl
, null))));
459 ccode
.add_assignment (new
CCodeIdentifier ("parent_class"), ccast
);
461 var ccall
= new
CCodeFunctionCall (new CCodeMemberAccess
.pointer (new
CCodeIdentifier ("parent_class"), "constructor"));
462 ccall
.add_argument (new
CCodeIdentifier ("type"));
463 ccall
.add_argument (new
CCodeIdentifier ("n_construct_properties"));
464 ccall
.add_argument (new
CCodeIdentifier ("construct_properties"));
465 ccode
.add_assignment (new
CCodeIdentifier ("obj"), ccall
);
468 ccall
= generate_instance_cast (new
CCodeIdentifier ("obj"), cl
);
470 ccode
.add_declaration ("%s *".printf (get_ccode_name (cl
)), new
CCodeVariableDeclarator ("self"));
471 ccode
.add_assignment (new
CCodeIdentifier ("self"), ccall
);
475 if (current_method_inner_error
) {
476 /* always separate error parameter and inner_error local variable
477 * as error may be set to NULL but we're always interested in inner errors
479 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
482 ccode
.add_return (new
CCodeIdentifier ("obj"));
485 cfile
.add_function (function
);
488 } else if (c
.binding
== MemberBinding
.CLASS
) {
492 Report
.error (c
.source_reference
, "class constructors are not supported in compact classes");
497 push_context (base_init_context
);
501 if (current_method_inner_error
) {
502 /* always separate error parameter and inner_error local variable
503 * as error may be set to NULL but we're always interested in inner errors
505 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
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 push_context (class_init_context
);
523 if (current_method_inner_error
) {
524 /* always separate error parameter and inner_error local variable
525 * as error may be set to NULL but we're always interested in inner errors
527 ccode
.add_declaration ("GError *", new CCodeVariableDeclarator
.zero ("_inner_error_", new
CCodeConstant ("NULL")));
532 Report
.error (c
.source_reference
, "internal error: constructors must have instance, class, or static binding");
538 public override string get_dynamic_property_getter_cname (DynamicProperty prop
) {
539 if (prop
.dynamic_type
.data_type
== null
540 || !prop
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
541 return base.get_dynamic_property_getter_cname (prop
);
544 string getter_cname
= "_dynamic_get_%s%d".printf (prop
.name
, dynamic_property_id
++);
546 var func
= new
CCodeFunction (getter_cname
, get_ccode_name (prop
.property_type
));
547 func
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
549 func
.add_parameter (new
CCodeParameter ("obj", get_ccode_name (prop
.dynamic_type
)));
551 push_function (func
);
553 ccode
.add_declaration (get_ccode_name (prop
.property_type
), new
CCodeVariableDeclarator ("result"));
555 var call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_get"));
556 call
.add_argument (new
CCodeIdentifier ("obj"));
557 call
.add_argument (get_property_canonical_cconstant (prop
));
558 call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier ("result")));
559 call
.add_argument (new
CCodeConstant ("NULL"));
561 ccode
.add_expression (call
);
563 ccode
.add_return (new
CCodeIdentifier ("result"));
567 // append to C source file
568 cfile
.add_function_declaration (func
);
569 cfile
.add_function (func
);
574 public override string get_dynamic_property_setter_cname (DynamicProperty prop
) {
575 if (prop
.dynamic_type
.data_type
== null
576 || !prop
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
577 return base.get_dynamic_property_setter_cname (prop
);
580 string setter_cname
= "_dynamic_set_%s%d".printf (prop
.name
, dynamic_property_id
++);
582 var func
= new
CCodeFunction (setter_cname
, "void");
583 func
.modifiers
|= CCodeModifiers
.STATIC
| CCodeModifiers
.INLINE
;
584 func
.add_parameter (new
CCodeParameter ("obj", get_ccode_name (prop
.dynamic_type
)));
585 func
.add_parameter (new
CCodeParameter ("value", get_ccode_name (prop
.property_type
)));
587 push_function (func
);
589 var call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_set"));
590 call
.add_argument (new
CCodeIdentifier ("obj"));
591 call
.add_argument (get_property_canonical_cconstant (prop
));
592 call
.add_argument (new
CCodeIdentifier ("value"));
593 call
.add_argument (new
CCodeConstant ("NULL"));
595 ccode
.add_expression (call
);
599 // append to C source file
600 cfile
.add_function_declaration (func
);
601 cfile
.add_function (func
);
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
, "gulong");
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 push_function (func
);
623 generate_gobject_connect_wrapper (sig
, false);
626 // append to C source file
627 cfile
.add_function_declaration (func
);
628 cfile
.add_function (func
);
630 return connect_wrapper_name
;
633 public override string get_dynamic_signal_connect_after_wrapper_name (DynamicSignal sig
) {
634 if (sig
.dynamic_type
.data_type
== null
635 || !sig
.dynamic_type
.data_type
.is_subtype_of (gobject_type
)) {
636 return base.get_dynamic_signal_connect_wrapper_name (sig
);
639 string connect_wrapper_name
= "_%sconnect_after".printf (get_dynamic_signal_cname (sig
));
640 var func
= new
CCodeFunction (connect_wrapper_name
, "gulong");
641 func
.add_parameter (new
CCodeParameter ("obj", "gpointer"));
642 func
.add_parameter (new
CCodeParameter ("signal_name", "const char *"));
643 func
.add_parameter (new
CCodeParameter ("handler", "GCallback"));
644 func
.add_parameter (new
CCodeParameter ("data", "gpointer"));
645 push_function (func
);
646 generate_gobject_connect_wrapper (sig
, true);
649 // append to C source file
650 cfile
.add_function_declaration (func
);
651 cfile
.add_function (func
);
653 return connect_wrapper_name
;
656 void generate_gobject_connect_wrapper (DynamicSignal sig
, bool after
) {
657 var m
= (Method
) sig
.handler
.symbol_reference
;
661 string connect_func
= "g_signal_connect_object";
662 if (m
.binding
!= MemberBinding
.INSTANCE
) {
664 connect_func
= "g_signal_connect";
666 connect_func
= "g_signal_connect_after";
669 var call
= new
CCodeFunctionCall (new
CCodeIdentifier (connect_func
));
670 call
.add_argument (new
CCodeIdentifier ("obj"));
671 call
.add_argument (new
CCodeIdentifier ("signal_name"));
672 call
.add_argument (new
CCodeIdentifier ("handler"));
673 call
.add_argument (new
CCodeIdentifier ("data"));
675 if (m
.binding
== MemberBinding
.INSTANCE
) {
677 call
.add_argument (new
CCodeConstant ("0"));
679 call
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
683 ccode
.add_return (call
);
686 public override void visit_property (Property prop
) {
687 base.visit_property (prop
);
689 if (is_gobject_property (prop
) && prop
.parent_symbol is Class
) {
690 prop_enum
.add_value (new
CCodeEnumValue ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop
))));
694 public override bool is_gobject_property (Property prop
) {
695 var type_sym
= prop
.parent_symbol as ObjectTypeSymbol
;
696 if (type_sym
== null || !type_sym
.is_subtype_of (gobject_type
)) {
700 if (prop
.binding
!= MemberBinding
.INSTANCE
) {
704 if (prop
.access
== SymbolAccessibility
.PRIVATE
) {
708 if (!has_valid_gobject_property_type (prop
)) {
712 if (type_sym is Class
&& prop
.base_interface_property
!= null &&
713 !is_gobject_property (prop
.base_interface_property
)) {
717 if (!prop
.name
[0].isalpha ()) {
718 // GObject requires properties to start with a letter
722 if (type_sym is Interface
&& !prop
.is_abstract
&& !prop
.external
&& !prop
.external_package
) {
723 // GObject does not support non-abstract interface properties,
724 // however we assume external properties always are GObject properties
728 if (type_sym is Interface
&& type_sym
.get_attribute ("DBus") != null) {
729 // GObject properties not currently supported in D-Bus interfaces
736 bool has_valid_gobject_property_type (Property prop
) {
737 var st
= prop
.property_type
.data_type as Struct
;
738 if (st
!= null && (!get_ccode_has_type_id (st
) || prop
.property_type
.nullable
)) {
742 if (prop
.property_type is ArrayType
&& ((ArrayType
)prop
.property_type
).element_type
.data_type
!= string_type
.data_type
) {
746 var d
= prop
.property_type as DelegateType
;
747 if (d
!= null && d
.delegate_symbol
.has_target
) {
754 public override void visit_method_call (MethodCall expr
) {
755 if (expr
.call is MemberAccess
) {
756 push_line (expr
.source_reference
);
758 var ma
= expr
.call as MemberAccess
;
759 if (ma
.inner
!= null && ma
.inner
.symbol_reference
== gobject_type
&&
760 (ma
.member_name
== "new" || ma
.member_name
== "newv"
761 || ma
.member_name
== "new_valist" || ma
.member_name
== "new_with_properties")) {
762 // Object.new (...) creation
763 // runtime check to ref_sink the instance if it's a floating type
764 base.visit_method_call (expr
);
766 var initiallyunowned_ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_IS_INITIALLY_UNOWNED"));
767 initiallyunowned_ccall
.add_argument (get_cvalue (expr
));
768 var sink_ref_ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_object_ref_sink"));
769 sink_ref_ccall
.add_argument (get_cvalue (expr
));
770 var cexpr
= new
CCodeConditionalExpression (initiallyunowned_ccall
, sink_ref_ccall
, get_cvalue (expr
));
772 expr
.target_value
= store_temp_value (new
GLibValue (expr
.value_type
, cexpr
), expr
);
774 } else if (ma
.symbol_reference
== gobject_type
) {
775 // Object (...) chain up
776 // check it's only used with valid properties
777 foreach (var arg
in expr
.get_argument_list ()) {
778 var named_argument
= arg as NamedArgument
;
779 if (named_argument
== null) {
780 Report
.error (arg
.source_reference
, "Named argument expected");
783 var prop
= SemanticAnalyzer
.symbol_lookup_inherited (current_class
, named_argument
.name
) as Property
;
785 Report
.error (arg
.source_reference
, "Property `%s' not found in `%s'".printf (named_argument
.name
, current_class
.get_full_name ()));
788 if (!is_gobject_property (prop
)) {
789 Report
.error (arg
.source_reference
, "Property `%s' not supported in Object (property: value) constructor chain up".printf (named_argument
.name
));
792 if (!arg
.value_type
.compatible (prop
.property_type
)) {
793 Report
.error (arg
.source_reference
, "Cannot convert from `%s' to `%s'".printf (arg
.value_type
.to_string (), prop
.property_type
.to_string ()));
802 base.visit_method_call (expr
);