Line data Source code
1 : /* valagsignalmodule.vala
2 : *
3 : * Copyright (C) 2006-2010 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 2914 : public class Vala.GSignalModule : GObjectModule {
27 223 : string get_marshaller_function (Signal sig, List<Parameter> params, DataType return_type, string? prefix = null) {
28 223 : var signature = get_marshaller_signature (sig, params, return_type);
29 : string ret;
30 :
31 223 : if (prefix == null) {
32 121 : if (predefined_marshal_set.contains (signature)) {
33 : prefix = "g_cclosure_marshal";
34 : } else {
35 76 : prefix = "g_cclosure_user_marshal";
36 : }
37 : }
38 :
39 223 : ret = "%s_%s_".printf (prefix, get_ccode_marshaller_type_name (return_type));
40 :
41 715 : foreach (Parameter p in params) {
42 246 : ret = "%s_%s".printf (ret, get_ccode_marshaller_type_name (p).replace (",", "_"));
43 : }
44 223 : if (sig.return_type.is_real_non_null_struct_type ()) {
45 6 : ret = ret + "_POINTER";
46 217 : } else if (params.size == 0) {
47 58 : ret = ret + "_VOID";
48 : }
49 :
50 223 : return ret;
51 : }
52 :
53 94 : private string? get_value_type_name_from_type_reference (DataType t) {
54 94 : if (t is PointerType || t is GenericType) {
55 3 : return "gpointer";
56 91 : } else if (t is VoidType) {
57 16 : return "void";
58 75 : } else if (get_ccode_type_id (t) == get_ccode_type_id (string_type)) {
59 18 : return "const char*";
60 57 : } else if (t.type_symbol is Class || t.type_symbol is Interface) {
61 9 : return "gpointer";
62 48 : } else if (t is ValueType && t.nullable) {
63 12 : return "gpointer";
64 36 : } else if (t.type_symbol is Struct) {
65 28 : unowned Struct st = (Struct) t.type_symbol;
66 28 : if (st.is_simple_type ()) {
67 26 : return get_ccode_name (t.type_symbol);
68 : } else {
69 2 : return "gpointer";
70 : }
71 8 : } else if (t.type_symbol is Enum) {
72 3 : unowned Enum en = (Enum) t.type_symbol;
73 3 : if (en.is_flags) {
74 1 : return "guint";
75 : } else {
76 2 : return "gint";
77 : }
78 5 : } else if (t is ArrayType) {
79 3 : return "gpointer";
80 2 : } else if (t is DelegateType) {
81 2 : return "gpointer";
82 0 : } else if (t is ErrorType) {
83 0 : return "gpointer";
84 : }
85 :
86 94 : return null;
87 : }
88 :
89 43 : private string? get_value_type_name_from_parameter (Parameter p) {
90 43 : if (p.direction != ParameterDirection.IN) {
91 1 : return "gpointer";
92 : } else {
93 42 : return get_value_type_name_from_type_reference (p.variable_type);
94 : }
95 : }
96 :
97 310 : private string get_marshaller_signature (Signal sig, List<Parameter> params, DataType return_type) {
98 : string signature;
99 :
100 310 : signature = "%s:".printf (get_ccode_marshaller_type_name (return_type));
101 310 : bool first = true;
102 950 : foreach (Parameter p in params) {
103 320 : if (first) {
104 220 : signature = signature + get_ccode_marshaller_type_name (p);
105 220 : first = false;
106 : } else {
107 100 : signature = "%s,%s".printf (signature, get_ccode_marshaller_type_name (p));
108 : }
109 : }
110 310 : if (sig.return_type.is_real_non_null_struct_type ()) {
111 8 : signature = signature + (first ? "POINTER" : ",POINTER");
112 302 : } else if (params.size == 0) {
113 88 : signature = signature + "VOID";
114 : }
115 :
116 : return signature;
117 : }
118 :
119 101 : private CCodeExpression get_signal_name_cexpression (Signal sig, Expression? detail_expr, CodeNode node) {
120 101 : if (detail_expr == null) {
121 88 : return get_signal_canonical_constant (sig);
122 : }
123 :
124 13 : if (detail_expr is StringLiteral) {
125 11 : return get_signal_canonical_constant (sig, ((StringLiteral) detail_expr).eval ());
126 : }
127 :
128 2 : var detail_value = create_temp_value (detail_expr.value_type, false, node, true);
129 2 : temp_ref_values.insert (0, detail_value);
130 :
131 2 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
132 2 : ccall.add_argument (get_signal_canonical_constant (sig, ""));
133 2 : ccall.add_argument (get_cvalue (detail_expr));
134 2 : ccall.add_argument (new CCodeConstant ("NULL"));
135 :
136 2 : ccode.add_assignment (get_cvalue_ (detail_value), ccall);
137 206 : return get_cvalue_ (detail_value);
138 : }
139 :
140 267 : private CCodeExpression get_signal_id_cexpression (Signal sig) {
141 17501 : var cl = (TypeSymbol) sig.parent_symbol;
142 267 : var signal_array = new CCodeIdentifier ("%s_signals".printf (get_ccode_lower_case_name (cl)));
143 267 : var signal_enum_value = new CCodeIdentifier ("%s_%s_SIGNAL".printf (get_ccode_upper_case_name (cl), get_ccode_upper_case_name (sig)));
144 :
145 267 : return new CCodeElementAccess (signal_array, signal_enum_value);
146 : }
147 :
148 3 : private CCodeExpression get_detail_cexpression (Expression detail_expr, CodeNode node) {
149 3 : var detail_cexpr = get_cvalue (detail_expr);
150 : CCodeFunctionCall detail_ccall;
151 3 : if (is_constant_ccode_expression (detail_cexpr)) {
152 1 : detail_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
153 : } else {
154 2 : detail_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
155 : }
156 3 : detail_ccall.add_argument (detail_cexpr);
157 :
158 3 : return detail_ccall;
159 : }
160 :
161 87 : public override void visit_signal (Signal sig) {
162 87 : if (signal_enum != null && sig.parent_symbol is TypeSymbol) {
163 87 : signal_enum.add_value (new CCodeEnumValue ("%s_%s_SIGNAL".printf (get_ccode_upper_case_name ((TypeSymbol) sig.parent_symbol), get_ccode_upper_case_name (sig))));
164 : }
165 :
166 87 : sig.accept_children (this);
167 :
168 : // declare parameter type
169 87 : unowned List<Parameter> params = sig.get_parameters ();
170 235 : foreach (Parameter p in params) {
171 74 : generate_parameter (p, cfile, new HashMap<int,CCodeParameter> (), null);
172 : }
173 :
174 87 : if (sig.return_type.is_real_non_null_struct_type ()) {
175 2 : generate_marshaller (sig, params, new VoidType ());
176 : } else {
177 85 : generate_marshaller (sig, params, sig.return_type);
178 : }
179 : }
180 :
181 121 : void generate_marshaller (Signal sig, List<Parameter> params, DataType return_type) {
182 : string signature;
183 : int n_params, i;
184 :
185 : /* check whether a signal with the same signature already exists for this source file (or predefined) */
186 87 : signature = get_marshaller_signature (sig, params, return_type);
187 87 : if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) {
188 53 : return;
189 : }
190 :
191 34 : var signal_marshaller = new CCodeFunction (get_marshaller_function (sig, params, return_type, null), "void");
192 34 : signal_marshaller.modifiers = CCodeModifiers.STATIC;
193 :
194 34 : signal_marshaller.add_parameter (new CCodeParameter ("closure", "GClosure *"));
195 34 : signal_marshaller.add_parameter (new CCodeParameter ("return_value", "GValue *"));
196 34 : signal_marshaller.add_parameter (new CCodeParameter ("n_param_values", "guint"));
197 34 : signal_marshaller.add_parameter (new CCodeParameter ("param_values", "const GValue *"));
198 34 : signal_marshaller.add_parameter (new CCodeParameter ("invocation_hint", "gpointer"));
199 34 : signal_marshaller.add_parameter (new CCodeParameter ("marshal_data", "gpointer"));
200 :
201 34 : push_function (signal_marshaller);
202 :
203 34 : var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (sig, params, return_type, "GMarshalFunc"));
204 34 : callback_decl.add_parameter (new CCodeParameter ("data1", "gpointer"));
205 34 : n_params = 1;
206 120 : foreach (Parameter p in params) {
207 43 : callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), get_value_type_name_from_parameter (p)));
208 43 : n_params++;
209 46 : if (p.variable_type is ArrayType) {
210 3 : var array_type = (ArrayType) p.variable_type;
211 3 : var length_ctype = get_ccode_array_length_type (p);
212 8 : for (var j = 0; j < array_type.rank; j++) {
213 5 : callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), length_ctype));
214 5 : n_params++;
215 : }
216 40 : } else if (p.variable_type is DelegateType) {
217 2 : unowned DelegateType delegate_type = (DelegateType) p.variable_type;
218 2 : if (delegate_type.delegate_symbol.has_target) {
219 2 : callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), get_ccode_name (delegate_target_type)));
220 2 : n_params++;
221 2 : if (delegate_type.is_disposable ()) {
222 1 : callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), get_ccode_name (delegate_target_destroy_type)));
223 1 : n_params++;
224 : }
225 : }
226 : }
227 : }
228 34 : if (sig.return_type.is_real_non_null_struct_type ()) {
229 1 : callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), "gpointer"));
230 1 : n_params++;
231 : }
232 :
233 34 : callback_decl.add_parameter (new CCodeParameter ("data2", "gpointer"));
234 34 : ccode.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type), callback_decl));
235 :
236 34 : ccode.add_declaration (get_marshaller_function (sig, params, return_type, "GMarshalFunc"), new CCodeVariableDeclarator ("callback"), CCodeModifiers.REGISTER);
237 :
238 34 : ccode.add_declaration ("GCClosure *", new CCodeVariableDeclarator ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")), CCodeModifiers.REGISTER);
239 :
240 34 : ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("data1"), CCodeModifiers.REGISTER);
241 34 : ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("data2"), CCodeModifiers.REGISTER);
242 :
243 : CCodeFunctionCall fc;
244 :
245 34 : if (return_type.type_symbol != null || return_type is ArrayType) {
246 18 : ccode.add_declaration (get_value_type_name_from_type_reference (return_type), new CCodeVariableDeclarator ("v_return"));
247 :
248 18 : fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
249 18 : fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL")));
250 18 : ccode.add_expression (fc);
251 : }
252 :
253 34 : fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
254 34 : fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string())));
255 34 : ccode.add_expression (fc);
256 :
257 34 : var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true);
258 34 : var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
259 34 : var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
260 34 : cond.add_argument (new CCodeIdentifier ("closure"));
261 34 : ccode.open_if (cond);
262 34 : ccode.add_assignment (new CCodeIdentifier ("data1"), data);
263 34 : ccode.add_assignment (new CCodeIdentifier ("data2"), param);
264 34 : ccode.add_else ();
265 34 : ccode.add_assignment (new CCodeIdentifier ("data1"), param);
266 34 : ccode.add_assignment (new CCodeIdentifier ("data2"), data);
267 34 : ccode.close ();
268 :
269 34 : var c_assign_rhs = new CCodeCastExpression (new CCodeConditionalExpression (new CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new CCodeIdentifier ("cc"), "callback", true)), get_marshaller_function (sig, params, return_type, "GMarshalFunc"));
270 34 : ccode.add_assignment (new CCodeIdentifier ("callback"), c_assign_rhs);
271 :
272 34 : fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
273 34 : fc.add_argument (new CCodeIdentifier ("data1"));
274 34 : i = 1;
275 120 : foreach (Parameter p in params) {
276 : CCodeFunctionCall inner_fc;
277 43 : if (p.direction != ParameterDirection.IN) {
278 1 : inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
279 42 : } else if (p.variable_type is ValueType && p.variable_type.nullable) {
280 4 : inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
281 : } else {
282 38 : inner_fc = new CCodeFunctionCall (get_value_getter_function (p.variable_type));
283 : }
284 43 : inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
285 43 : fc.add_argument (inner_fc);
286 43 : i++;
287 46 : if (p.variable_type is ArrayType) {
288 3 : var array_type = (ArrayType) p.variable_type;
289 3 : var length_value_function = get_ccode_get_value_function (array_type.length_type.type_symbol);
290 3 : assert (length_value_function != null && length_value_function != "");
291 8 : for (var j = 0; j < array_type.rank; j++) {
292 5 : inner_fc = new CCodeFunctionCall (new CCodeIdentifier (length_value_function));
293 5 : inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
294 5 : fc.add_argument (inner_fc);
295 5 : i++;
296 : }
297 40 : } else if (p.variable_type is DelegateType) {
298 2 : unowned DelegateType delegate_type = (DelegateType) p.variable_type;
299 2 : if (delegate_type.delegate_symbol.has_target) {
300 2 : inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
301 2 : inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
302 2 : fc.add_argument (inner_fc);
303 2 : i++;
304 2 : if (delegate_type.is_disposable ()) {
305 1 : inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
306 1 : inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
307 1 : fc.add_argument (inner_fc);
308 1 : i++;
309 : }
310 : }
311 : }
312 : }
313 35 : if (sig.return_type.is_real_non_null_struct_type ()) {
314 1 : var inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer"));
315 1 : inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
316 1 : fc.add_argument (inner_fc);
317 1 : i++;
318 : }
319 34 : fc.add_argument (new CCodeIdentifier ("data2"));
320 :
321 52 : if (return_type.type_symbol != null || return_type is ArrayType) {
322 18 : ccode.add_assignment (new CCodeIdentifier ("v_return"), fc);
323 :
324 : CCodeFunctionCall set_fc;
325 18 : if (return_type is ValueType) {
326 11 : if (return_type.nullable) {
327 4 : set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
328 : } else {
329 7 : set_fc = new CCodeFunctionCall (get_value_setter_function (return_type));
330 : }
331 : } else {
332 7 : set_fc = new CCodeFunctionCall (get_value_taker_function (return_type));
333 : }
334 18 : set_fc.add_argument (new CCodeIdentifier ("return_value"));
335 18 : set_fc.add_argument (new CCodeIdentifier ("v_return"));
336 :
337 18 : ccode.add_expression (set_fc);
338 : } else {
339 16 : ccode.add_expression (fc);
340 : }
341 :
342 34 : pop_function ();
343 :
344 34 : cfile.add_function_declaration (signal_marshaller);
345 34 : cfile.add_function (signal_marshaller);
346 34 : user_marshal_set.add (signature);
347 : }
348 :
349 87 : public override CCodeExpression get_signal_creation (Signal sig, ObjectTypeSymbol type) {
350 : CCodeFunctionCall csignew;
351 87 : if (sig.default_handler == null || sig.is_virtual) {
352 85 : csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new"));
353 : } else {
354 2 : csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new_class_handler"));
355 : }
356 87 : csignew.add_argument (new CCodeConstant ("\"%s\"".printf (get_ccode_name (sig))));
357 87 : csignew.add_argument (new CCodeIdentifier (get_ccode_type_id (type)));
358 87 : string[] flags = new string[0];
359 87 : var run_type = sig.get_attribute_string ("Signal", "run");
360 87 : if (run_type == "first") {
361 0 : flags += "G_SIGNAL_RUN_FIRST";
362 87 : } else if (run_type == "cleanup") {
363 0 : flags += "G_SIGNAL_RUN_CLEANUP";
364 : } else {
365 174 : flags += "G_SIGNAL_RUN_LAST";
366 : }
367 87 : if (sig.get_attribute_bool ("Signal", "detailed")) {
368 2 : flags += "G_SIGNAL_DETAILED";
369 : }
370 :
371 87 : if (sig.get_attribute_bool ("Signal", "no_recurse")) {
372 0 : flags += "G_SIGNAL_NO_RECURSE";
373 : }
374 :
375 87 : if (sig.get_attribute_bool ("Signal", "action")) {
376 0 : flags += "G_SIGNAL_ACTION";
377 : }
378 :
379 87 : if (sig.get_attribute_bool ("Signal", "no_hooks")) {
380 0 : flags += "G_SIGNAL_NO_HOOKS";
381 : }
382 :
383 87 : if (sig.version.deprecated) {
384 0 : flags += "G_SIGNAL_DEPRECATED";
385 : }
386 :
387 87 : csignew.add_argument (new CCodeConstant (string.joinv (" | ", flags)));
388 :
389 87 : if (sig.default_handler == null) {
390 76 : csignew.add_argument (new CCodeConstant ("0"));
391 20 : } else if (sig.is_virtual) {
392 9 : var struct_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET"));
393 9 : struct_offset.add_argument (new CCodeIdentifier (get_ccode_type_name (type)));
394 9 : struct_offset.add_argument (new CCodeIdentifier (get_ccode_vfunc_name (sig.default_handler)));
395 9 : csignew.add_argument (struct_offset);
396 : } else {
397 2 : csignew.add_argument (new CCodeCastExpression (new CCodeIdentifier (get_ccode_real_name (sig.default_handler)), "GCallback"));
398 : }
399 87 : csignew.add_argument (new CCodeConstant ("NULL"));
400 87 : csignew.add_argument (new CCodeConstant ("NULL"));
401 :
402 87 : unowned List<Parameter> params = sig.get_parameters ();
403 : string marshaller;
404 87 : if (sig.return_type.is_real_non_null_struct_type ()) {
405 2 : marshaller = get_marshaller_function (sig, params, new VoidType ());
406 : } else {
407 85 : marshaller = get_marshaller_function (sig, params, sig.return_type);
408 : }
409 :
410 87 : var marshal_arg = new CCodeIdentifier (marshaller);
411 87 : csignew.add_argument (marshal_arg);
412 :
413 87 : if (sig.return_type is PointerType || sig.return_type is GenericType) {
414 2 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
415 85 : } else if (sig.return_type is ErrorType) {
416 0 : csignew.add_argument (new CCodeConstant ("G_TYPE_ERROR"));
417 85 : } else if (sig.return_type is ValueType && sig.return_type.nullable) {
418 6 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
419 79 : } else if (sig.return_type.type_symbol == null) {
420 61 : csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
421 18 : } else if (sig.return_type.is_real_non_null_struct_type ()) {
422 2 : csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
423 : } else {
424 16 : csignew.add_argument (new CCodeConstant (get_ccode_type_id (sig.return_type.type_symbol)));
425 : }
426 :
427 87 : int params_len = 0;
428 235 : foreach (Parameter param in params) {
429 74 : params_len++;
430 74 : if (param.variable_type is ArrayType) {
431 3 : params_len += ((ArrayType) param.variable_type).rank;
432 71 : } else if (param.variable_type is DelegateType) {
433 3 : unowned DelegateType delegate_type = (DelegateType) param.variable_type;
434 3 : if (delegate_type.delegate_symbol.has_target) {
435 2 : params_len++;
436 2 : if (delegate_type.is_disposable ()) {
437 1 : params_len++;
438 : }
439 : }
440 : }
441 : }
442 87 : if (sig.return_type.is_real_non_null_struct_type ()) {
443 2 : params_len++;
444 : }
445 :
446 87 : csignew.add_argument (new CCodeConstant ("%d".printf (params_len)));
447 235 : foreach (Parameter param in params) {
448 77 : if (param.variable_type is ArrayType) {
449 3 : var array_type = (ArrayType) param.variable_type;
450 3 : if (array_type.element_type.type_symbol == string_type.type_symbol) {
451 2 : csignew.add_argument (new CCodeConstant ("G_TYPE_STRV"));
452 : } else {
453 1 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
454 : }
455 3 : assert (get_ccode_has_type_id (array_type.length_type.type_symbol));
456 3 : var length_type_id = get_ccode_type_id (array_type.length_type.type_symbol);
457 8 : for (var i = 0; i < array_type.rank; i++) {
458 5 : csignew.add_argument (new CCodeConstant (length_type_id));
459 : }
460 71 : } else if (param.variable_type is DelegateType) {
461 3 : unowned DelegateType delegate_type = (DelegateType) param.variable_type;
462 3 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
463 3 : if (delegate_type.delegate_symbol.has_target) {
464 2 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
465 2 : if (delegate_type.is_disposable ()) {
466 1 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
467 : }
468 : }
469 68 : } else if (param.variable_type is PointerType || param.variable_type is GenericType || param.direction != ParameterDirection.IN) {
470 5 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
471 63 : } else if (param.variable_type is ErrorType) {
472 2 : csignew.add_argument (new CCodeConstant ("G_TYPE_ERROR"));
473 61 : } else if (param.variable_type is ValueType && param.variable_type.nullable) {
474 8 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
475 : } else {
476 53 : csignew.add_argument (new CCodeConstant (get_ccode_type_id (param.variable_type.type_symbol)));
477 : }
478 : }
479 87 : if (sig.return_type.is_real_non_null_struct_type ()) {
480 2 : csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
481 : }
482 :
483 87 : marshal_arg.name = marshaller;
484 :
485 174 : return new CCodeAssignment (get_signal_id_cexpression (sig), csignew);
486 : }
487 :
488 1305 : public override void visit_element_access (ElementAccess expr) {
489 1305 : if (!(expr.container is MemberAccess && expr.container.symbol_reference is Signal)) {
490 1289 : base.visit_element_access (expr);
491 1289 : return;
492 : }
493 :
494 19 : if (expr.parent_node is MethodCall) {
495 : // detailed signal emission
496 3 : unowned Signal sig = (Signal) expr.symbol_reference;
497 3 : unowned MemberAccess ma = (MemberAccess) expr.container;
498 3 : var detail_expr = expr.get_indices ().get (0);
499 :
500 3 : set_cvalue (expr, emit_signal (sig, ma, detail_expr));
501 : } else {
502 : // signal connect or disconnect
503 : }
504 : }
505 :
506 89 : bool in_gobject_instance (Method m) {
507 89 : bool result = false;
508 89 : if (m.binding == MemberBinding.INSTANCE) {
509 30 : result = m.this_parameter.variable_type.type_symbol.is_subtype_of (gobject_type);
510 : }
511 : return result;
512 : }
513 :
514 75800 : public override void visit_member_access (MemberAccess expr) {
515 75800 : if (!(expr.symbol_reference is Signal)) {
516 75602 : base.visit_member_access (expr);
517 75602 : return;
518 : }
519 :
520 198 : unowned Signal sig = (Signal) expr.symbol_reference;
521 :
522 198 : set_cvalue (expr, emit_signal (sig, expr));
523 : }
524 :
525 201 : CCodeExpression emit_signal (Signal sig, MemberAccess expr, Expression? detail_expr = null) {
526 201 : CCodeExpression pub_inst = null;
527 :
528 201 : if (expr.inner != null) {
529 201 : pub_inst = get_cvalue (expr.inner);
530 : }
531 :
532 201 : if (expr.inner is BaseAccess && sig.is_virtual) {
533 2 : var m = sig.default_handler;
534 2 : var base_class = (Class) m.parent_symbol;
535 2 : var vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class)));
536 2 : vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class))));
537 2 : return new CCodeMemberAccess.pointer (vcast, m.name);
538 : }
539 :
540 199 : if (!sig.external_package && expr.source_reference.file == sig.source_reference.file && !(sig is DynamicSignal)) {
541 180 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit"));
542 180 : ccall.add_argument (pub_inst);
543 180 : ccall.add_argument (get_signal_id_cexpression (sig));
544 180 : if (detail_expr == null) {
545 177 : ccall.add_argument (new CCodeConstant ("0"));
546 : } else {
547 3 : ccall.add_argument (get_detail_cexpression (detail_expr, expr));
548 : }
549 180 : return ccall;
550 19 : } else if (get_ccode_has_emitter (sig)) {
551 : string emitter_func;
552 11 : if (sig.emitter != null) {
553 11 : if (!sig.external_package && expr.source_reference.file != sig.source_reference.file) {
554 0 : generate_method_declaration (sig.emitter, cfile);
555 : }
556 11 : emitter_func = get_ccode_lower_case_name (sig.emitter);
557 : } else {
558 0 : unowned TypeSymbol sym = (TypeSymbol) sig.parent_symbol;
559 0 : emitter_func = "%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_lower_case_name (sig));
560 : }
561 11 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (emitter_func));
562 11 : ccall.add_argument (pub_inst);
563 11 : return ccall;
564 : } else {
565 8 : var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
566 8 : ccall.add_argument (pub_inst);
567 8 : if (detail_expr == null) {
568 8 : ccall.add_argument (get_signal_canonical_constant (sig));
569 : } else {
570 0 : ccall.add_argument (get_signal_name_cexpression (sig, detail_expr, expr));
571 : }
572 8 : return ccall;
573 : }
574 : }
575 :
576 17647 : public override void visit_method_call (MethodCall expr) {
577 17546 : var method_type = expr.call.value_type as MethodType;
578 :
579 16773 : if (method_type == null || !(method_type.method_symbol.parent_symbol is Signal)) {
580 : // no signal connect/disconnect call
581 17445 : base.visit_method_call (expr);
582 17445 : return;
583 : }
584 :
585 101 : var sig = (Signal) method_type.method_symbol.parent_symbol;
586 101 : var signal_access = ((MemberAccess) expr.call).inner;
587 101 : var handler = expr.get_argument_list ().get (0);
588 :
589 101 : bool disconnect = (method_type.method_symbol.name == "disconnect");
590 101 : bool after = (method_type.method_symbol.name == "connect_after");
591 :
592 101 : var cexpr = connect_signal (sig, signal_access, handler, disconnect, after, expr);
593 101 : set_cvalue (expr, cexpr);
594 : }
595 :
596 101 : CCodeExpression? connect_signal (Signal sig, Expression signal_access, Expression handler, bool disconnect, bool after, CodeNode expr) {
597 : string connect_func;
598 :
599 101 : DelegateType? dt = null;
600 101 : if (handler.symbol_reference is Variable) {
601 20 : dt = ((Variable) handler.symbol_reference).variable_type as DelegateType;
602 20 : if (dt != null && !context.experimental) {
603 20 : Report.warning (handler.source_reference, "Connecting delegates to signals is experimental");
604 : }
605 : // Use actual lambda expression if available for proper target/destroy handling
606 20 : if (((Variable) handler.symbol_reference).initializer is LambdaExpression) {
607 14 : handler = ((Variable) handler.symbol_reference).initializer;
608 14 : dt = null;
609 : }
610 : }
611 101 : var m = handler.symbol_reference as Method;
612 :
613 101 : if (!disconnect) {
614 : // connect
615 90 : if (!(sig is DynamicSignal) && ((m != null && m.closure) || (dt != null && dt.value_owned))) {
616 14 : connect_func = "g_signal_connect_data";
617 76 : } else if (m != null && in_gobject_instance (m)) {
618 13 : connect_func = "g_signal_connect_object";
619 63 : } else if (!after) {
620 62 : connect_func = "g_signal_connect";
621 : } else {
622 1 : connect_func = "g_signal_connect_after";
623 : }
624 : } else {
625 : // disconnect
626 11 : if (sig is DynamicSignal) {
627 0 : connect_func = "VALA_UNSUPPORTED";
628 : } else {
629 11 : connect_func = "g_signal_handlers_disconnect_matched";
630 : }
631 : }
632 :
633 101 : var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
634 :
635 101 : CCodeExpression signal_name_cexpr = null;
636 :
637 : // first argument: instance of sender
638 : MemberAccess ma;
639 114 : if (signal_access is ElementAccess) {
640 13 : var ea = (ElementAccess) signal_access;
641 13 : ma = (MemberAccess) ea.container;
642 13 : var detail_expr = ea.get_indices ().get (0);
643 13 : signal_name_cexpr = get_signal_name_cexpression (sig, detail_expr, expr);
644 : } else {
645 88 : ma = (MemberAccess) signal_access;
646 88 : signal_name_cexpr = get_signal_name_cexpression (sig, null, expr);
647 : }
648 101 : if (ma.inner != null) {
649 101 : ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
650 : } else {
651 0 : ccall.add_argument (get_this_cexpression ());
652 : }
653 :
654 101 : if (sig is DynamicSignal) {
655 : // dynamic_signal_connect or dynamic_signal_disconnect
656 :
657 : // second argument: signal name
658 6 : ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_ccode_name (sig))));
659 106 : } else if (!disconnect) {
660 : // g_signal_connect_object or g_signal_connect
661 :
662 : // second argument: signal name
663 84 : ccall.add_argument (signal_name_cexpr);
664 : } else {
665 : // g_signal_handlers_disconnect_matched
666 :
667 : // second argument: mask
668 11 : if (!(signal_access is ElementAccess)) {
669 10 : ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
670 : } else {
671 1 : ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
672 : }
673 :
674 : // get signal id
675 11 : var temp_decl = get_temp_variable (uint_type);
676 11 : emit_temp_var (temp_decl);
677 11 : var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
678 11 : parse_call.add_argument (signal_name_cexpr);
679 11 : var decl_type = (TypeSymbol) sig.parent_symbol;
680 11 : parse_call.add_argument (new CCodeIdentifier (get_ccode_type_id (decl_type)));
681 11 : parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_decl.name)));
682 11 : LocalVariable? detail_temp_decl = null;
683 11 : if (!(signal_access is ElementAccess)) {
684 10 : parse_call.add_argument (new CCodeConstant ("NULL"));
685 10 : parse_call.add_argument (new CCodeConstant ("FALSE"));
686 : } else {
687 1 : detail_temp_decl = get_temp_variable (gquark_type);
688 1 : emit_temp_var (detail_temp_decl);
689 1 : parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (detail_temp_decl.name)));
690 1 : parse_call.add_argument (new CCodeConstant ("TRUE"));
691 : }
692 11 : ccode.add_expression (parse_call);
693 :
694 : // third argument: signal_id
695 11 : ccall.add_argument (get_variable_cexpression (temp_decl.name));
696 :
697 : // fourth argument: detail
698 11 : if (detail_temp_decl == null) {
699 10 : ccall.add_argument (new CCodeConstant ("0"));
700 : } else {
701 1 : ccall.add_argument (get_variable_cexpression (detail_temp_decl.name));
702 : }
703 : // fifth argument: closure
704 11 : ccall.add_argument (new CCodeConstant ("NULL"));
705 : }
706 :
707 : // third resp. sixth argument: handler
708 101 : ccall.add_argument (new CCodeCastExpression (get_cvalue (handler), "GCallback"));
709 :
710 113 : if (m != null && m.closure) {
711 : // g_signal_connect_data
712 :
713 : // fourth argument: user_data
714 : CCodeExpression handler_destroy_notify;
715 12 : ccall.add_argument (get_delegate_target_cexpression (handler, out handler_destroy_notify));
716 :
717 : // fifth argument: destroy_notify
718 12 : ccall.add_argument (new CCodeCastExpression (handler_destroy_notify, "GClosureNotify"));
719 :
720 : // sixth argument: connect_flags
721 12 : if (!after)
722 12 : ccall.add_argument (new CCodeConstant ("0"));
723 : else
724 0 : ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
725 89 : } else if (m != null && m.binding == MemberBinding.INSTANCE) {
726 : // g_signal_connect_object or g_signal_handlers_disconnect_matched
727 : // or dynamic_signal_connect or dynamic_signal_disconnect
728 :
729 : // fourth resp. seventh argument: object/user_data
730 26 : if (handler is MemberAccess) {
731 6 : var right_ma = (MemberAccess) handler;
732 6 : if (right_ma.inner != null) {
733 6 : ccall.add_argument (get_cvalue (right_ma.inner));
734 : } else {
735 0 : ccall.add_argument (get_this_cexpression ());
736 : }
737 14 : } else if (handler is LambdaExpression) {
738 14 : ccall.add_argument (get_this_cexpression ());
739 : }
740 20 : if (!disconnect && in_gobject_instance (m)) {
741 : // g_signal_connect_object
742 :
743 : // fifth argument: connect_flags
744 13 : if (!after)
745 12 : ccall.add_argument (new CCodeConstant ("0"));
746 : else
747 1 : ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
748 : }
749 75 : } else if (dt != null && dt.delegate_symbol.has_target) {
750 : // fourth argument: user_data
751 : CCodeExpression handler_destroy_notify;
752 6 : ccall.add_argument (get_delegate_target_cexpression (handler, out handler_destroy_notify));
753 6 : if (!disconnect && dt.value_owned) {
754 : // fifth argument: destroy_notify
755 : //FIXME handler_destroy_notify is NULL
756 2 : ccall.add_argument (new CCodeCastExpression (handler_destroy_notify, "GClosureNotify"));
757 : // sixth argument: connect_flags
758 2 : if (!after)
759 2 : ccall.add_argument (new CCodeConstant ("0"));
760 : else
761 0 : ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
762 : }
763 : } else {
764 : // g_signal_connect or g_signal_connect_after or g_signal_handlers_disconnect_matched
765 : // or dynamic_signal_connect or dynamic_signal_disconnect
766 :
767 : // fourth resp. seventh argument: user_data
768 63 : ccall.add_argument (new CCodeConstant ("NULL"));
769 : }
770 :
771 101 : if (disconnect || expr.parent_node is ExpressionStatement) {
772 93 : ccode.add_expression (ccall);
773 93 : return null;
774 : } else {
775 8 : var temp_var = get_temp_variable (ulong_type);
776 8 : var temp_ref = get_variable_cexpression (temp_var.name);
777 :
778 8 : emit_temp_var (temp_var);
779 :
780 8 : ccode.add_assignment (temp_ref, ccall);
781 :
782 8 : return temp_ref;
783 : }
784 : }
785 : }
786 :
|