Line data Source code
1 : /* valagobjectmodule.vala
2 : *
3 : * Copyright (C) 2006-2011 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
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.
10 :
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.
15 :
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
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 :
26 4371 : public class Vala.GObjectModule : GTypeModule {
27 : int signal_wrapper_id;
28 :
29 780 : public override void visit_class (Class cl) {
30 780 : base.visit_class (cl);
31 :
32 780 : if (!cl.is_subtype_of (gobject_type)) {
33 : return;
34 : }
35 :
36 425 : push_line (cl.source_reference);
37 425 : if (class_has_readable_properties (cl) || cl.has_type_parameters ()) {
38 160 : add_get_property_function (cl);
39 : }
40 425 : if (class_has_writable_properties (cl) || cl.has_type_parameters ()) {
41 135 : add_set_property_function (cl);
42 : }
43 425 : pop_line ();
44 : }
45 :
46 1159 : public override void generate_class_init (Class cl) {
47 734 : if (!cl.is_subtype_of (gobject_type)) {
48 : return;
49 : }
50 :
51 : /* set property handlers */
52 425 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
53 425 : ccall.add_argument (new CCodeIdentifier ("klass"));
54 425 : if (class_has_readable_properties (cl) || cl.has_type_parameters ()) {
55 160 : ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "get_property"), new CCodeIdentifier ("_vala_%s_get_property".printf (get_ccode_lower_case_name (cl, null))));
56 : }
57 425 : if (class_has_writable_properties (cl) || cl.has_type_parameters ()) {
58 135 : ccode.add_assignment (new CCodeMemberAccess.pointer (ccall, "set_property"), new CCodeIdentifier ("_vala_%s_set_property".printf (get_ccode_lower_case_name (cl, null))));
59 : }
60 :
61 : /* set constructor */
62 445 : if (cl.constructor != null) {
63 20 : var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
64 20 : ccast.add_argument (new CCodeIdentifier ("klass"));
65 20 : ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "constructor"), new CCodeIdentifier ("%sconstructor".printf (get_ccode_lower_case_prefix (cl))));
66 : }
67 :
68 : /* set finalize function */
69 630 : if (cl.get_fields ().size > 0 || cl.destructor != null) {
70 205 : var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
71 205 : ccast.add_argument (new CCodeIdentifier ("klass"));
72 205 : ccode.add_assignment (new CCodeMemberAccess.pointer (ccast, "finalize"), new CCodeIdentifier ("%sfinalize".printf (get_ccode_lower_case_prefix (cl))));
73 : }
74 :
75 : /* create type, dup_func, and destroy_func properties for generic types */
76 465 : foreach (TypeParameter type_param in cl.get_type_parameters ()) {
77 : string func_name, enum_value;
78 : CCodeConstant func_name_constant;
79 : CCodeFunctionCall cinst, cspec;
80 :
81 :
82 20 : func_name = get_ccode_type_id (type_param);
83 20 : func_name_constant = new CCodeConstant ("\"%s\"".printf (func_name.replace ("_", "-")));
84 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
85 20 : cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
86 20 : cinst.add_argument (ccall);
87 20 : cinst.add_argument (new CCodeConstant (enum_value));
88 20 : cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_gtype"));
89 20 : cspec.add_argument (func_name_constant);
90 20 : cspec.add_argument (new CCodeConstant ("\"type\""));
91 20 : cspec.add_argument (new CCodeConstant ("\"type\""));
92 20 : cspec.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
93 20 : cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY"));
94 20 : cinst.add_argument (cspec);
95 20 : ccode.add_expression (cinst);
96 20 : prop_enum.add_value (new CCodeEnumValue (enum_value));
97 :
98 :
99 20 : func_name = get_ccode_copy_function (type_param);
100 20 : func_name_constant = new CCodeConstant ("\"%s\"".printf (func_name.replace ("_", "-")));
101 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
102 20 : cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
103 20 : cinst.add_argument (ccall);
104 20 : cinst.add_argument (new CCodeConstant (enum_value));
105 20 : cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
106 20 : cspec.add_argument (func_name_constant);
107 20 : cspec.add_argument (new CCodeConstant ("\"dup func\""));
108 20 : cspec.add_argument (new CCodeConstant ("\"dup func\""));
109 20 : cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY"));
110 20 : cinst.add_argument (cspec);
111 20 : ccode.add_expression (cinst);
112 20 : prop_enum.add_value (new CCodeEnumValue (enum_value));
113 :
114 :
115 20 : func_name = get_ccode_destroy_function (type_param);
116 20 : func_name_constant = new CCodeConstant ("\"%s\"".printf (func_name.replace ("_", "-")));
117 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
118 20 : cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
119 20 : cinst.add_argument (ccall);
120 20 : cinst.add_argument (new CCodeConstant (enum_value));
121 20 : cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
122 20 : cspec.add_argument (func_name_constant);
123 20 : cspec.add_argument (new CCodeConstant ("\"destroy func\""));
124 20 : cspec.add_argument (new CCodeConstant ("\"destroy func\""));
125 20 : cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY"));
126 20 : cinst.add_argument (cspec);
127 20 : ccode.add_expression (cinst);
128 20 : prop_enum.add_value (new CCodeEnumValue (enum_value));
129 : }
130 :
131 : /* create properties */
132 720 : var props = cl.get_properties ();
133 1151 : foreach (Property prop in props) {
134 368 : if (!context.analyzer.is_gobject_property (prop)) {
135 10 : if (!context.analyzer.is_gobject_property_type (prop.property_type)) {
136 6 : Report.warning (prop.source_reference, "Type `%s' can not be used for a GLib.Object property", prop.property_type.to_qualified_string ());
137 : }
138 10 : continue;
139 : }
140 :
141 358 : if (prop.comment != null) {
142 91 : ccode.add_statement (new CCodeComment (prop.comment.content));
143 : }
144 :
145 358 : var cinst = new CCodeFunctionCall ();
146 358 : cinst.add_argument (ccall);
147 358 : cinst.add_argument (new CCodeConstant ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
148 :
149 : //TODO g_object_class_override_property should be used more regulary
150 358 : unowned Property? base_prop = prop.base_interface_property;
151 360 : if (base_prop != null && base_prop.property_type is GenericType) {
152 2 : cinst.call = new CCodeIdentifier ("g_object_class_override_property");
153 2 : cinst.add_argument (get_property_canonical_cconstant (prop));
154 :
155 2 : ccode.add_expression (cinst);
156 :
157 2 : var cfind = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_find_property"));
158 2 : cfind.add_argument (ccall);
159 2 : cfind.add_argument (get_property_canonical_cconstant (prop));
160 2 : ccode.add_expression (new CCodeAssignment (get_param_spec_cexpression (prop), cfind));
161 : } else {
162 356 : cinst.call = new CCodeIdentifier ("g_object_class_install_property");
163 356 : cinst.add_argument (get_param_spec (prop));
164 :
165 356 : ccode.add_expression (cinst);
166 : }
167 : }
168 : }
169 :
170 850 : private bool class_has_readable_properties (Class cl) {
171 850 : foreach (Property prop in cl.get_properties ()) {
172 292 : if (prop.get_accessor != null) {
173 292 : return true;
174 : }
175 : }
176 850 : return false;
177 : }
178 :
179 850 : private bool class_has_writable_properties (Class cl) {
180 1002 : foreach (Property prop in cl.get_properties ()) {
181 314 : if (prop.set_accessor != null) {
182 238 : return true;
183 : }
184 : }
185 850 : return false;
186 : }
187 :
188 623 : private void add_guarded_expression (Symbol sym, CCodeExpression expression) {
189 : // prevent deprecation warnings
190 625 : if (sym.version.deprecated) {
191 2 : var guard = new CCodeGGnucSection (GGnucSectionType.IGNORE_DEPRECATIONS);
192 2 : ccode.add_statement (guard);
193 2 : guard.append (new CCodeExpressionStatement (expression));
194 : } else {
195 621 : ccode.add_expression (expression);
196 : }
197 : }
198 :
199 320 : private void add_get_property_function (Class cl) {
200 160 : var get_prop = new CCodeFunction ("_vala_%s_get_property".printf (get_ccode_lower_case_name (cl, null)), "void");
201 160 : get_prop.modifiers = CCodeModifiers.STATIC;
202 160 : get_prop.add_parameter (new CCodeParameter ("object", "GObject *"));
203 160 : get_prop.add_parameter (new CCodeParameter ("property_id", "guint"));
204 160 : get_prop.add_parameter (new CCodeParameter ("value", "GValue *"));
205 160 : get_prop.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
206 :
207 160 : push_function (get_prop);
208 :
209 160 : CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
210 160 : ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", ccall));
211 :
212 160 : ccode.open_switch (new CCodeIdentifier ("property_id"));
213 320 : var props = cl.get_properties ();
214 876 : foreach (Property prop in props) {
215 368 : if (prop.get_accessor == null || prop.is_abstract) {
216 10 : continue;
217 : }
218 358 : if (!context.analyzer.is_gobject_property (prop)) {
219 : // don't register private properties
220 10 : continue;
221 : }
222 :
223 17823 : Property base_prop = prop;
224 348 : CCodeExpression cself = new CCodeIdentifier ("self");
225 383 : if (prop.base_property != null) {
226 35 : var base_type = (Class) prop.base_property.parent_symbol;
227 70 : base_prop = prop.base_property;
228 93 : cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
229 :
230 35 : generate_property_accessor_declaration (prop.base_property.get_accessor, cfile);
231 338 : } else if (prop.base_interface_property != null) {
232 25 : var base_type = (Interface) prop.base_interface_property.parent_symbol;
233 50 : base_prop = prop.base_interface_property;
234 50 : cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
235 :
236 25 : generate_property_accessor_declaration (prop.base_interface_property.get_accessor, cfile);
237 : }
238 :
239 : CCodeExpression cfunc;
240 348 : if (!get_ccode_no_accessor_method (base_prop) && !get_ccode_concrete_accessor (base_prop)) {
241 345 : cfunc = new CCodeIdentifier (get_ccode_name (base_prop.get_accessor));
242 : } else {
243 : // use the static real function as helper
244 3 : cfunc = new CCodeIdentifier (get_ccode_real_name (prop.get_accessor));
245 : }
246 :
247 348 : ccode.add_case (new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
248 696 : if (prop.property_type.is_real_struct_type ()) {
249 22 : ccode.open_block ();
250 22 : ccode.add_declaration (get_ccode_name (prop.property_type), new CCodeVariableDeclarator ("boxed"));
251 :
252 22 : ccall = new CCodeFunctionCall (cfunc);
253 22 : ccall.add_argument (cself);
254 22 : if (prop.property_type.nullable) {
255 3 : ccode.add_assignment (new CCodeIdentifier ("boxed"), ccall);
256 : } else {
257 19 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed")));
258 19 : ccode.add_expression (ccall);
259 : }
260 :
261 22 : var csetcall = new CCodeFunctionCall ();
262 22 : csetcall.call = get_value_setter_function (prop.property_type);
263 22 : csetcall.add_argument (new CCodeIdentifier ("value"));
264 22 : if (prop.property_type.nullable) {
265 3 : csetcall.add_argument (new CCodeIdentifier ("boxed"));
266 : } else {
267 19 : csetcall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("boxed")));
268 : }
269 22 : add_guarded_expression (prop, csetcall);
270 :
271 22 : if (requires_destroy (prop.get_accessor.value_type)) {
272 6 : ccode.add_expression (destroy_value (new GLibValue (prop.get_accessor.value_type, new CCodeIdentifier ("boxed"), true)));
273 : }
274 22 : ccode.close ();
275 : } else {
276 326 : ccall = new CCodeFunctionCall (cfunc);
277 326 : ccall.add_argument (cself);
278 326 : var array_type = prop.property_type as ArrayType;
279 12 : if (array_type != null && get_ccode_array_length (prop) && array_type.element_type.type_symbol == string_type.type_symbol) {
280 : // G_TYPE_STRV
281 7 : ccode.open_block ();
282 7 : ccode.add_declaration ("int", new CCodeVariableDeclarator ("length"));
283 7 : ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("length")));
284 : }
285 326 : var csetcall = new CCodeFunctionCall ();
286 326 : if (prop.get_accessor.value_type.value_owned) {
287 16 : csetcall.call = get_value_taker_function (prop.property_type);
288 : } else {
289 310 : csetcall.call = get_value_setter_function (prop.property_type);
290 : }
291 326 : csetcall.add_argument (new CCodeIdentifier ("value"));
292 326 : if (base_prop != null && prop != base_prop && base_prop.property_type is GenericType) {
293 4 : csetcall.add_argument (convert_from_generic_pointer (ccall, prop.property_type));
294 : } else {
295 322 : csetcall.add_argument (ccall);
296 : }
297 326 : add_guarded_expression (prop, csetcall);
298 326 : if (array_type != null && get_ccode_array_length (prop) && array_type.element_type.type_symbol == string_type.type_symbol) {
299 7 : ccode.close ();
300 : }
301 : }
302 348 : ccode.add_break ();
303 : }
304 :
305 : /* type, dup func, and destroy func properties for generic types */
306 200 : foreach (TypeParameter type_param in cl.get_type_parameters ()) {
307 : string func_name, enum_value;
308 : CCodeMemberAccess cfield;
309 : CCodeFunctionCall csetcall;
310 :
311 20 : func_name = get_ccode_type_id (type_param);
312 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
313 20 : ccode.add_case (new CCodeIdentifier (enum_value));
314 20 : cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
315 20 : csetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_gtype"));
316 20 : csetcall.add_argument (new CCodeIdentifier ("value"));
317 20 : csetcall.add_argument (cfield);
318 20 : ccode.add_expression (csetcall);
319 20 : ccode.add_break ();
320 :
321 20 : func_name = get_ccode_copy_function (type_param);
322 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
323 20 : ccode.add_case (new CCodeIdentifier (enum_value));
324 20 : cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
325 20 : csetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
326 20 : csetcall.add_argument (new CCodeIdentifier ("value"));
327 20 : csetcall.add_argument (cfield);
328 20 : ccode.add_expression (csetcall);
329 20 : ccode.add_break ();
330 :
331 20 : func_name = get_ccode_destroy_function (type_param);
332 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
333 20 : ccode.add_case (new CCodeIdentifier (enum_value));
334 20 : cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
335 20 : csetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
336 20 : csetcall.add_argument (new CCodeIdentifier ("value"));
337 20 : csetcall.add_argument (cfield);
338 20 : ccode.add_expression (csetcall);
339 20 : ccode.add_break ();
340 : }
341 160 : ccode.add_default ();
342 160 : emit_invalid_property_id_warn ();
343 160 : ccode.add_break ();
344 :
345 160 : ccode.close ();
346 :
347 160 : pop_function ();
348 :
349 160 : cfile.add_function_declaration (get_prop);
350 160 : cfile.add_function (get_prop);
351 : }
352 :
353 270 : private void add_set_property_function (Class cl) {
354 135 : var set_prop = new CCodeFunction ("_vala_%s_set_property".printf (get_ccode_lower_case_name (cl, null)), "void");
355 135 : set_prop.modifiers = CCodeModifiers.STATIC;
356 135 : set_prop.add_parameter (new CCodeParameter ("object", "GObject *"));
357 135 : set_prop.add_parameter (new CCodeParameter ("property_id", "guint"));
358 135 : set_prop.add_parameter (new CCodeParameter ("value", "const GValue *"));
359 135 : set_prop.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
360 :
361 135 : push_function (set_prop);
362 :
363 135 : CCodeFunctionCall ccall = generate_instance_cast (new CCodeIdentifier ("object"), cl);
364 135 : ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self", ccall));
365 :
366 135 : ccode.open_switch (new CCodeIdentifier ("property_id"));
367 270 : var props = cl.get_properties ();
368 743 : foreach (Property prop in props) {
369 333 : if (prop.set_accessor == null || prop.is_abstract) {
370 49 : continue;
371 : }
372 284 : if (!context.analyzer.is_gobject_property (prop)) {
373 9 : continue;
374 : }
375 :
376 275 : Property base_prop = prop;
377 275 : CCodeExpression cself = new CCodeIdentifier ("self");
378 287 : if (prop.base_property != null) {
379 12 : var base_type = (Class) prop.base_property.parent_symbol;
380 24 : base_prop = prop.base_property;
381 24 : cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
382 :
383 12 : generate_property_accessor_declaration (prop.base_property.set_accessor, cfile);
384 284 : } else if (prop.base_interface_property != null) {
385 21 : var base_type = (Interface) prop.base_interface_property.parent_symbol;
386 42 : base_prop = prop.base_interface_property;
387 42 : cself = get_cvalue_ (transform_value (new GLibValue (new ObjectType (cl), cself, true), new ObjectType (base_type), prop));
388 :
389 21 : generate_property_accessor_declaration (prop.base_interface_property.set_accessor, cfile);
390 : }
391 :
392 : CCodeExpression cfunc;
393 275 : if (!get_ccode_no_accessor_method (base_prop) && !get_ccode_concrete_accessor (base_prop)) {
394 272 : cfunc = new CCodeIdentifier (get_ccode_name (base_prop.set_accessor));
395 : } else {
396 : // use the static real function as helper
397 3 : cfunc = new CCodeIdentifier (get_ccode_real_name (prop.set_accessor));
398 : }
399 :
400 275 : ccode.add_case (new CCodeIdentifier ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
401 275 : ccall = new CCodeFunctionCall (cfunc);
402 275 : ccall.add_argument (cself);
403 550 : if (prop.property_type is ArrayType && ((ArrayType)prop.property_type).element_type.type_symbol == string_type.type_symbol) {
404 10 : ccode.open_block ();
405 10 : ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("boxed"));
406 :
407 10 : var cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_boxed"));
408 10 : cgetcall.add_argument (new CCodeIdentifier ("value"));
409 10 : ccode.add_assignment (new CCodeIdentifier ("boxed"), cgetcall);
410 10 : ccall.add_argument (new CCodeIdentifier ("boxed"));
411 :
412 17 : if (get_ccode_array_length (prop)) {
413 7 : var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("boxed"), new CCodeConstant ("NULL"));
414 7 : var cstrvlen = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
415 7 : cstrvlen.add_argument (new CCodeIdentifier ("boxed"));
416 7 : var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cstrvlen);
417 :
418 7 : ccall.add_argument (ccond);
419 : }
420 10 : add_guarded_expression (prop, ccall);
421 10 : ccode.close ();
422 : } else {
423 265 : var cgetcall = new CCodeFunctionCall ();
424 265 : if (prop.property_type.type_symbol != null) {
425 261 : cgetcall.call = new CCodeIdentifier (get_ccode_get_value_function (prop.property_type.type_symbol));
426 : } else {
427 4 : cgetcall.call = new CCodeIdentifier ("g_value_get_pointer");
428 : }
429 265 : cgetcall.add_argument (new CCodeIdentifier ("value"));
430 265 : if (base_prop != null && prop != base_prop && base_prop.property_type is GenericType) {
431 4 : ccall.add_argument (convert_to_generic_pointer (cgetcall, prop.property_type));
432 : } else {
433 261 : ccall.add_argument (cgetcall);
434 : }
435 265 : add_guarded_expression (prop, ccall);
436 : }
437 275 : ccode.add_break ();
438 : }
439 :
440 : /* type, dup func, and destroy func properties for generic types */
441 175 : foreach (TypeParameter type_param in cl.get_type_parameters ()) {
442 : string func_name, enum_value;
443 : CCodeMemberAccess cfield;
444 : CCodeFunctionCall cgetcall;
445 :
446 20 : func_name = get_ccode_type_id (type_param);
447 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
448 20 : ccode.add_case (new CCodeIdentifier (enum_value));
449 20 : cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
450 20 : cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_gtype"));
451 20 : cgetcall.add_argument (new CCodeIdentifier ("value"));
452 20 : ccode.add_assignment (cfield, cgetcall);
453 20 : ccode.add_break ();
454 :
455 20 : func_name = get_ccode_copy_function (type_param);
456 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
457 20 : ccode.add_case (new CCodeIdentifier (enum_value));
458 20 : cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
459 20 : cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
460 20 : cgetcall.add_argument (new CCodeIdentifier ("value"));
461 20 : ccode.add_assignment (cfield, cgetcall);
462 20 : ccode.add_break ();
463 :
464 20 : func_name = get_ccode_destroy_function (type_param);
465 20 : enum_value = "%s_%s".printf (get_ccode_lower_case_name (cl, null), func_name).ascii_up ();
466 20 : ccode.add_case (new CCodeIdentifier (enum_value));
467 20 : cfield = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
468 20 : cgetcall = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
469 20 : cgetcall.add_argument (new CCodeIdentifier ("value"));
470 20 : ccode.add_assignment (cfield, cgetcall);
471 20 : ccode.add_break ();
472 : }
473 135 : ccode.add_default ();
474 135 : emit_invalid_property_id_warn ();
475 135 : ccode.add_break ();
476 :
477 135 : ccode.close ();
478 :
479 135 : pop_function ();
480 :
481 135 : cfile.add_function_declaration (set_prop);
482 135 : cfile.add_function (set_prop);
483 : }
484 :
485 590 : private void emit_invalid_property_id_warn () {
486 : // warn on invalid property id
487 295 : var cwarn = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_WARN_INVALID_PROPERTY_ID"));
488 295 : cwarn.add_argument (new CCodeIdentifier ("object"));
489 295 : cwarn.add_argument (new CCodeIdentifier ("property_id"));
490 295 : cwarn.add_argument (new CCodeIdentifier ("pspec"));
491 295 : ccode.add_expression (cwarn);
492 : }
493 :
494 69 : public override void visit_constructor (Constructor c) {
495 35 : push_line (c.source_reference);
496 :
497 35 : var cl = (Class) c.parent_symbol;
498 :
499 55 : if (c.binding == MemberBinding.INSTANCE) {
500 21 : if (!cl.is_subtype_of (gobject_type)) {
501 1 : Report.error (c.source_reference, "construct blocks require GLib.Object");
502 1 : c.error = true;
503 1 : return;
504 : }
505 :
506 20 : push_context (new EmitContext (c));
507 :
508 20 : var function = new CCodeFunction ("%sconstructor".printf (get_ccode_lower_case_prefix (cl)), "GObject *");
509 20 : function.modifiers = CCodeModifiers.STATIC;
510 :
511 20 : function.add_parameter (new CCodeParameter ("type", "GType"));
512 20 : function.add_parameter (new CCodeParameter ("n_construct_properties", "guint"));
513 20 : function.add_parameter (new CCodeParameter ("construct_properties", "GObjectConstructParam *"));
514 :
515 20 : cfile.add_function_declaration (function);
516 :
517 20 : push_function (function);
518 :
519 20 : ccode.add_declaration ("GObject *", new CCodeVariableDeclarator ("obj"));
520 20 : ccode.add_declaration ("GObjectClass *", new CCodeVariableDeclarator ("parent_class"));
521 :
522 23 : if (cl.is_singleton) {
523 3 : var singleton_ref_name = "%s_singleton__ref".printf (get_ccode_name (cl));
524 3 : var singleton_lock_name = "%s_singleton__lock".printf (get_ccode_name (cl));
525 :
526 3 : var singleton_ref = new CCodeDeclaration("GWeakRef");
527 3 : singleton_ref.add_declarator (new CCodeVariableDeclarator (singleton_ref_name));
528 3 : singleton_ref.modifiers = CCodeModifiers.STATIC;
529 3 : ccode.add_statement (singleton_ref);
530 :
531 3 : var mutex_lock = new CCodeDeclaration("GMutex");
532 3 : mutex_lock.add_declarator (new CCodeVariableDeclarator (singleton_lock_name));
533 3 : mutex_lock.modifiers = CCodeModifiers.STATIC;
534 3 : ccode.add_statement (mutex_lock);
535 :
536 3 : var singleton_mutex_lock = new CCodeFunctionCall (new CCodeIdentifier ("g_mutex_lock"));
537 3 : singleton_mutex_lock.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_lock_name)));
538 3 : ccode.add_statement (new CCodeExpressionStatement (singleton_mutex_lock));
539 :
540 3 : var get_from_singleton = new CCodeFunctionCall (new CCodeIdentifier ("g_weak_ref_get"));
541 3 : get_from_singleton.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_ref_name)));
542 3 : ccode.add_assignment (new CCodeIdentifier ("obj"), get_from_singleton);
543 :
544 3 : var check_existance = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("obj"), new CCodeConstant ("NULL"));
545 3 : var return_singleton = new CCodeBlock();
546 :
547 3 : var singleton_mutex_unlock = new CCodeFunctionCall (new CCodeIdentifier ("g_mutex_unlock"));
548 3 : singleton_mutex_unlock.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_lock_name)));
549 3 : return_singleton.add_statement (new CCodeExpressionStatement (singleton_mutex_unlock));
550 3 : return_singleton.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
551 :
552 3 : var if_singleton_alive = new CCodeIfStatement (check_existance, return_singleton);
553 3 : ccode.add_statement (if_singleton_alive);
554 : }
555 :
556 20 : var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
557 20 : ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (cl, null))));
558 20 : ccode.add_assignment (new CCodeIdentifier ("parent_class"), ccast);
559 :
560 20 : var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
561 20 : ccall.add_argument (new CCodeIdentifier ("type"));
562 20 : ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
563 20 : ccall.add_argument (new CCodeIdentifier ("construct_properties"));
564 20 : ccode.add_assignment (new CCodeIdentifier ("obj"), ccall);
565 :
566 :
567 20 : ccall = generate_instance_cast (new CCodeIdentifier ("obj"), cl);
568 :
569 20 : ccode.add_declaration ("%s *".printf (get_ccode_name (cl)), new CCodeVariableDeclarator ("self"));
570 20 : ccode.add_assignment (new CCodeIdentifier ("self"), ccall);
571 :
572 20 : c.body.emit (this);
573 :
574 20 : if (current_method_inner_error) {
575 : /* always separate error parameter and inner_error local variable
576 : * as error may be set to NULL but we're always interested in inner errors
577 : */
578 2 : ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
579 : }
580 :
581 23 : if (cl.is_singleton) {
582 3 : var singleton_ref_name = "%s_singleton__ref".printf (get_ccode_name (cl));
583 3 : var singleton_lock_name = "%s_singleton__lock".printf (get_ccode_name (cl));
584 :
585 3 : var set_singleton_reference = new CCodeFunctionCall (new CCodeIdentifier ("g_weak_ref_set"));
586 3 : set_singleton_reference.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_ref_name)));
587 3 : set_singleton_reference.add_argument (new CCodeIdentifier ("obj"));
588 3 : ccode.add_statement (new CCodeExpressionStatement (set_singleton_reference));
589 :
590 3 : var final_singleton_mutex_unlock = new CCodeFunctionCall (new CCodeIdentifier ("g_mutex_unlock"));
591 3 : final_singleton_mutex_unlock.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (singleton_lock_name)));
592 3 : ccode.add_statement (new CCodeExpressionStatement (final_singleton_mutex_unlock));
593 : }
594 :
595 20 : ccode.add_return (new CCodeIdentifier ("obj"));
596 :
597 20 : pop_function ();
598 20 : cfile.add_function (function);
599 :
600 20 : pop_context ();
601 14 : } else if (c.binding == MemberBinding.CLASS) {
602 : // class constructor
603 :
604 7 : if (cl.is_compact) {
605 0 : Report.error (c.source_reference, "class constructors are not supported in compact classes");
606 0 : c.error = true;
607 0 : return;
608 : }
609 :
610 7 : push_context (base_init_context);
611 :
612 7 : c.body.emit (this);
613 :
614 7 : if (current_method_inner_error) {
615 : /* always separate error parameter and inner_error local variable
616 : * as error may be set to NULL but we're always interested in inner errors
617 : */
618 2 : ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
619 : }
620 :
621 7 : pop_context ();
622 7 : } else if (c.binding == MemberBinding.STATIC) {
623 : // static class constructor
624 : // add to class_init
625 :
626 7 : if (cl.is_compact) {
627 0 : Report.error (c.source_reference, "static constructors are not supported in compact classes");
628 0 : c.error = true;
629 0 : return;
630 : }
631 :
632 7 : push_context (class_init_context);
633 :
634 7 : c.body.emit (this);
635 :
636 7 : if (current_method_inner_error) {
637 : /* always separate error parameter and inner_error local variable
638 : * as error may be set to NULL but we're always interested in inner errors
639 : */
640 2 : ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("_inner_error%d_".printf (current_inner_error_id), new CCodeConstant ("NULL")));
641 : }
642 :
643 7 : pop_context ();
644 : } else {
645 0 : Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
646 : }
647 :
648 34 : pop_line ();
649 : }
650 :
651 6 : public override string get_dynamic_signal_cname (DynamicSignal node) {
652 6 : return "dynamic_%s%d_".printf (node.name, signal_wrapper_id++);
653 : }
654 :
655 510 : public override void visit_property (Property prop) {
656 510 : base.visit_property (prop);
657 :
658 510 : if (context.analyzer.is_gobject_property (prop) && prop.parent_symbol is Class) {
659 358 : prop_enum.add_value (new CCodeEnumValue ("%s_PROPERTY".printf (get_ccode_upper_case_name (prop))));
660 : }
661 : }
662 :
663 17445 : public override void visit_method_call (MethodCall expr) {
664 34395 : if (expr.call is MemberAccess) {
665 16959 : push_line (expr.source_reference);
666 :
667 16959 : var ma = expr.call as MemberAccess;
668 16959 : if (ma.inner != null && ma.inner.symbol_reference == gobject_type &&
669 9 : (ma.member_name == "new" || ma.member_name == "newv"
670 0 : || ma.member_name == "new_valist" || ma.member_name == "new_with_properties")) {
671 : // Object.new (...) creation
672 : // runtime check to ref_sink the instance if it's a floating type
673 9 : base.visit_method_call (expr);
674 :
675 9 : var initiallyunowned_ccall = new CCodeFunctionCall (new CCodeIdentifier ("G_IS_INITIALLY_UNOWNED"));
676 9 : initiallyunowned_ccall.add_argument (get_cvalue (expr));
677 9 : var sink_ref_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_ref_sink"));
678 9 : sink_ref_ccall.add_argument (get_cvalue (expr));
679 9 : var cexpr = new CCodeConditionalExpression (initiallyunowned_ccall, sink_ref_ccall, get_cvalue (expr));
680 :
681 9 : expr.target_value = store_temp_value (new GLibValue (expr.value_type, cexpr), expr);
682 9 : return;
683 16950 : } else if (ma.symbol_reference == gobject_type) {
684 : // Object (...) chain up
685 : // check it's only used with valid properties
686 30 : foreach (var arg in expr.get_argument_list ()) {
687 8 : var named_argument = arg as NamedArgument;
688 8 : if (named_argument == null) {
689 0 : Report.error (arg.source_reference, "Named argument expected");
690 0 : break;
691 : }
692 8 : var prop = SemanticAnalyzer.symbol_lookup_inherited (current_class, named_argument.name) as Property;
693 1 : if (prop == null) {
694 1 : Report.error (arg.source_reference, "Property `%s' not found in `%s'", named_argument.name, current_class.get_full_name ());
695 1 : break;
696 : }
697 7 : if (!context.analyzer.is_gobject_property (prop)) {
698 0 : Report.error (arg.source_reference, "Property `%s' not supported in Object (property: value) constructor chain up", named_argument.name);
699 0 : break;
700 : }
701 7 : if (!arg.value_type.compatible (prop.property_type)) {
702 1 : Report.error (arg.source_reference, "Cannot convert from `%s' to `%s'", arg.value_type.to_string (), prop.property_type.to_string ());
703 1 : break;
704 : }
705 : }
706 : }
707 :
708 16950 : pop_line ();
709 : }
710 :
711 17436 : base.visit_method_call (expr);
712 : }
713 : }
714 :
|