codegen: Drop useless comma expression when handling struct arguments
[vala-lang.git] / codegen / valagsignalmodule.vala
blob5ee461e7cda3bc728564098f46e05b797cc84a84
1 /* valagsignalmodule.vala
3 * Copyright (C) 2006-2010 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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
26 public class Vala.GSignalModule : GObjectModule {
27 private string get_marshaller_type_name (DataType t, bool dbus = false) {
28 if (t is PointerType || t.type_parameter != null) {
29 return ("POINTER");
30 } else if (t is ErrorType) {
31 return ("POINTER");
32 } else if (t is ArrayType) {
33 if (dbus) {
34 return ("BOXED");
35 } else {
36 if (((ArrayType) t).element_type.data_type == string_type.data_type) {
37 return ("BOXED,INT");
38 } else {
39 return ("POINTER,INT");
42 } else if (t is VoidType) {
43 return ("VOID");
44 } else if (dbus && DBusModule.get_type_signature (t).has_prefix ("(")) {
45 return ("BOXED");
46 } else if (t.data_type is Enum) {
47 var en = (Enum) t.data_type;
48 if (dbus) {
49 if (en.is_flags) {
50 return ("UINT");
51 } else {
52 return ("INT");
54 } else {
55 return en.get_marshaller_type_name ();
57 } else {
58 return t.data_type.get_marshaller_type_name ();
62 private string get_marshaller_type_name_for_parameter (Parameter param, bool dbus = false) {
63 if (param.direction != ParameterDirection.IN) {
64 return ("POINTER");
65 } else {
66 return get_marshaller_type_name (param.variable_type, dbus);
70 public override string get_marshaller_function (List<Parameter> params, DataType return_type, string? prefix = null, bool dbus = false) {
71 var signature = get_marshaller_signature (params, return_type, dbus);
72 string ret;
74 if (prefix == null) {
75 if (predefined_marshal_set.contains (signature)) {
76 prefix = "g_cclosure_marshal";
77 } else {
78 prefix = "g_cclosure_user_marshal";
82 ret = "%s_%s_".printf (prefix, get_marshaller_type_name (return_type, dbus));
84 if (params == null || params.size == 0) {
85 ret = ret + "_VOID";
86 } else {
87 foreach (Parameter p in params) {
88 ret = "%s_%s".printf (ret, get_marshaller_type_name_for_parameter (p, dbus).replace (",", "_"));
92 return ret;
95 private string? get_value_type_name_from_type_reference (DataType t) {
96 if (t is PointerType || t.type_parameter != null) {
97 return "gpointer";
98 } else if (t is VoidType) {
99 return "void";
100 } else if (t.data_type == string_type.data_type) {
101 return "const char*";
102 } else if (t.data_type is Class || t.data_type is Interface) {
103 return "gpointer";
104 } else if (t.data_type is Struct) {
105 var st = (Struct) t.data_type;
106 if (st.is_simple_type ()) {
107 return t.data_type.get_cname ();
108 } else {
109 return "gpointer";
111 } else if (t.data_type is Enum) {
112 return "gint";
113 } else if (t is ArrayType) {
114 return "gpointer";
115 } else if (t is ErrorType) {
116 return "gpointer";
119 return null;
122 private string? get_value_type_name_from_parameter (Parameter p) {
123 if (p.direction != ParameterDirection.IN) {
124 return "gpointer";
125 } else {
126 return get_value_type_name_from_type_reference (p.variable_type);
130 private string get_marshaller_signature (List<Parameter> params, DataType return_type, bool dbus = false) {
131 string signature;
133 signature = "%s:".printf (get_marshaller_type_name (return_type, dbus));
134 if (params == null || params.size == 0) {
135 signature = signature + "VOID";
136 } else {
137 bool first = true;
138 foreach (Parameter p in params) {
139 if (first) {
140 signature = signature + get_marshaller_type_name_for_parameter (p, dbus);
141 first = false;
142 } else {
143 signature = "%s,%s".printf (signature, get_marshaller_type_name_for_parameter (p, dbus));
148 return signature;
151 private CCodeExpression? get_signal_name_cexpression (Signal sig, Expression? detail_expr, CodeNode node) {
152 if (detail_expr == null) {
153 return sig.get_canonical_cconstant ();
156 if (detail_expr.value_type is NullType || !detail_expr.value_type.compatible (string_type)) {
157 node.error = true;
158 Report.error (detail_expr.source_reference, "only string details are supported");
159 return null;
162 if (detail_expr is StringLiteral) {
163 return sig.get_canonical_cconstant (((StringLiteral) detail_expr).eval ());
166 var detail_decl = get_temp_variable (detail_expr.value_type, true, node);
167 emit_temp_var (detail_decl);
168 temp_ref_vars.insert (0, detail_decl);
170 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
171 ccall.add_argument (sig.get_canonical_cconstant (""));
172 ccall.add_argument (get_cvalue (detail_expr));
173 ccall.add_argument (new CCodeConstant ("NULL"));
175 ccode.add_assignment (get_variable_cexpression (detail_decl.name), ccall);
176 return get_variable_cexpression (detail_decl.name);
179 public override void visit_signal (Signal sig) {
180 // parent_symbol may be null for dynamic signals
182 var cl = sig.parent_symbol as Class;
183 if (cl != null && cl.is_compact) {
184 sig.error = true;
185 Report.error (sig.source_reference, "Signals are not supported in compact classes");
186 return;
189 if (cl != null) {
190 foreach (DataType base_type in cl.get_base_types ()) {
191 if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, sig.name) is Signal) {
192 sig.error = true;
193 Report.error (sig.source_reference, "Signals with the same name as a signal in a base type are not supported");
194 return;
199 sig.accept_children (this);
201 // declare parameter type
202 foreach (Parameter p in sig.get_parameters ()) {
203 generate_parameter (p, cfile, new HashMap<int,CCodeParameter> (), null);
206 generate_marshaller (sig.get_parameters (), sig.return_type);
209 public override void generate_marshaller (List<Parameter> params, DataType return_type, bool dbus = false) {
210 string signature;
211 int n_params, i;
213 /* check whether a signal with the same signature already exists for this source file (or predefined) */
214 signature = get_marshaller_signature (params, return_type, dbus);
215 if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) {
216 return;
219 var signal_marshaller = new CCodeFunction (get_marshaller_function (params, return_type, null, dbus), "void");
220 signal_marshaller.modifiers = CCodeModifiers.STATIC;
222 signal_marshaller.add_parameter (new CCodeParameter ("closure", "GClosure *"));
223 signal_marshaller.add_parameter (new CCodeParameter ("return_value", "GValue *"));
224 signal_marshaller.add_parameter (new CCodeParameter ("n_param_values", "guint"));
225 signal_marshaller.add_parameter (new CCodeParameter ("param_values", "const GValue *"));
226 signal_marshaller.add_parameter (new CCodeParameter ("invocation_hint", "gpointer"));
227 signal_marshaller.add_parameter (new CCodeParameter ("marshal_data", "gpointer"));
229 cfile.add_function_declaration (signal_marshaller);
231 var marshaller_body = new CCodeBlock ();
233 var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (params, return_type, "GMarshalFunc", dbus));
234 callback_decl.add_parameter (new CCodeParameter ("data1", "gpointer"));
235 n_params = 1;
236 foreach (Parameter p in params) {
237 callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), get_value_type_name_from_parameter (p)));
238 n_params++;
239 if (p.variable_type.is_array () && !dbus) {
240 callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), "gint"));
241 n_params++;
244 callback_decl.add_parameter (new CCodeParameter ("data2", "gpointer"));
245 marshaller_body.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type), callback_decl));
247 var var_decl = new CCodeDeclaration (get_marshaller_function (params, return_type, "GMarshalFunc", dbus));
248 var_decl.modifiers = CCodeModifiers.REGISTER;
249 var_decl.add_declarator (new CCodeVariableDeclarator ("callback"));
250 marshaller_body.add_statement (var_decl);
252 var_decl = new CCodeDeclaration ("GCClosure *");
253 var_decl.modifiers = CCodeModifiers.REGISTER;
254 var_decl.add_declarator (new CCodeVariableDeclarator ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")));
255 marshaller_body.add_statement (var_decl);
257 var_decl = new CCodeDeclaration ("gpointer");
258 var_decl.modifiers = CCodeModifiers.REGISTER;
259 var_decl.add_declarator (new CCodeVariableDeclarator ("data1"));
260 var_decl.add_declarator (new CCodeVariableDeclarator ("data2"));
261 marshaller_body.add_statement (var_decl);
263 CCodeFunctionCall fc;
265 if (return_type.data_type != null || return_type.is_array ()) {
266 var_decl = new CCodeDeclaration (get_value_type_name_from_type_reference (return_type));
267 var_decl.add_declarator (new CCodeVariableDeclarator ("v_return"));
268 marshaller_body.add_statement (var_decl);
270 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
271 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL")));
272 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
275 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
276 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string())));
277 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
279 var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true);
280 var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
281 var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
282 cond.add_argument (new CCodeIdentifier ("closure"));
283 var true_block = new CCodeBlock ();
284 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), data)));
285 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), param)));
286 var false_block = new CCodeBlock ();
287 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), param)));
288 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), data)));
289 marshaller_body.add_statement (new CCodeIfStatement (cond, true_block, false_block));
291 var c_assign = new CCodeAssignment (new CCodeIdentifier ("callback"), new CCodeCastExpression (new CCodeConditionalExpression (new CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new CCodeIdentifier ("cc"), "callback", true)), get_marshaller_function (params, return_type, "GMarshalFunc", dbus)));
292 marshaller_body.add_statement (new CCodeExpressionStatement (c_assign));
294 fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
295 fc.add_argument (new CCodeIdentifier ("data1"));
296 i = 1;
297 foreach (Parameter p in params) {
298 string get_value_function;
299 bool is_array = p.variable_type.is_array ();
300 if (p.direction != ParameterDirection.IN) {
301 get_value_function = "g_value_get_pointer";
302 } else if (is_array) {
303 if (dbus) {
304 get_value_function = "g_value_get_boxed";
305 } else {
306 if (((ArrayType) p.variable_type).element_type.data_type == string_type.data_type) {
307 get_value_function = "g_value_get_boxed";
308 } else {
309 get_value_function = "g_value_get_pointer";
312 } else if (p.variable_type is PointerType || p.variable_type.type_parameter != null) {
313 get_value_function = "g_value_get_pointer";
314 } else if (p.variable_type is ErrorType) {
315 get_value_function = "g_value_get_pointer";
316 } else if (dbus && DBusModule.get_type_signature (p.variable_type).has_prefix ("(")) {
317 get_value_function = "g_value_get_boxed";
318 } else if (dbus && p.variable_type.data_type is Enum) {
319 var en = (Enum) p.variable_type.data_type;
320 if (en.is_flags) {
321 get_value_function = "g_value_get_uint";
322 } else {
323 get_value_function = "g_value_get_int";
325 } else {
326 get_value_function = p.variable_type.data_type.get_get_value_function ();
328 var inner_fc = new CCodeFunctionCall (new CCodeIdentifier (get_value_function));
329 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
330 fc.add_argument (inner_fc);
331 i++;
332 if (is_array && !dbus) {
333 inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_int"));
334 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
335 fc.add_argument (inner_fc);
336 i++;
339 fc.add_argument (new CCodeIdentifier ("data2"));
341 if (return_type.data_type != null || return_type.is_array ()) {
342 marshaller_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("v_return"), fc)));
344 CCodeFunctionCall set_fc;
345 if (return_type.is_array ()) {
346 if (dbus) {
347 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
348 } else {
349 if (((ArrayType) return_type).element_type.data_type == string_type.data_type) {
350 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
351 } else {
352 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
355 } else if (return_type.type_parameter != null) {
356 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
357 } else if (return_type is ErrorType) {
358 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
359 } else if (return_type.data_type == string_type.data_type) {
360 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_string"));
361 } else if (return_type.data_type is Class || return_type.data_type is Interface) {
362 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object"));
363 } else if (dbus && DBusModule.get_type_signature (return_type).has_prefix ("(")) {
364 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
365 } else if (dbus && return_type.data_type is Enum) {
366 var en = (Enum) return_type.data_type;
367 if (en.is_flags) {
368 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_uint"));
369 } else {
370 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_int"));
372 } else {
373 set_fc = new CCodeFunctionCall (new CCodeIdentifier (return_type.data_type.get_set_value_function ()));
375 set_fc.add_argument (new CCodeIdentifier ("return_value"));
376 set_fc.add_argument (new CCodeIdentifier ("v_return"));
378 marshaller_body.add_statement (new CCodeExpressionStatement (set_fc));
379 } else {
380 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
383 signal_marshaller.block = marshaller_body;
385 cfile.add_function (signal_marshaller);
386 user_marshal_set.add (signature);
389 public override CCodeFunctionCall get_signal_creation (Signal sig, TypeSymbol type) {
390 var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new"));
391 var cl = sig.parent_symbol as Class;
392 csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.get_cname ())));
393 csignew.add_argument (new CCodeIdentifier (type.get_type_id ()));
394 string[] flags = new string[0];
395 if (sig.run_type == "first") {
396 flags += "G_SIGNAL_RUN_FIRST";
397 } else if (sig.run_type == "cleanup") {
398 flags += "G_SIGNAL_RUN_CLEANUP";
399 } else {
400 flags += "G_SIGNAL_RUN_LAST";
402 if (sig.is_detailed) {
403 flags += "G_SIGNAL_DETAILED";
406 if (sig.no_recurse) {
407 flags += "G_SIGNAL_NO_RECURSE";
410 if (sig.is_action) {
411 flags += "G_SIGNAL_ACTION";
414 if (sig.no_hooks) {
415 flags += "G_SIGNAL_NO_HOOKS";
418 csignew.add_argument (new CCodeConstant (string.joinv (" | ", flags)));
420 if (sig.default_handler == null) {
421 csignew.add_argument (new CCodeConstant ("0"));
422 } else {
423 var struct_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET"));
424 struct_offset.add_argument (new CCodeIdentifier ("%sClass".printf (cl.get_cname ())));
425 struct_offset.add_argument (new CCodeIdentifier (sig.default_handler.vfunc_name));
426 csignew.add_argument (struct_offset);
428 csignew.add_argument (new CCodeConstant ("NULL"));
429 csignew.add_argument (new CCodeConstant ("NULL"));
431 string marshaller = get_marshaller_function (sig.get_parameters (), sig.return_type);
433 var marshal_arg = new CCodeIdentifier (marshaller);
434 csignew.add_argument (marshal_arg);
436 var params = sig.get_parameters ();
437 if (sig.return_type is PointerType || sig.return_type.type_parameter != null) {
438 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
439 } else if (sig.return_type is ErrorType) {
440 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
441 } else if (sig.return_type.data_type == null) {
442 csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
443 } else {
444 csignew.add_argument (new CCodeConstant (sig.return_type.data_type.get_type_id ()));
447 int params_len = 0;
448 foreach (Parameter param in params) {
449 params_len++;
450 if (param.variable_type.is_array ()) {
451 params_len++;
455 csignew.add_argument (new CCodeConstant ("%d".printf (params_len)));
456 foreach (Parameter param in params) {
457 if (param.variable_type.is_array ()) {
458 if (((ArrayType) param.variable_type).element_type.data_type == string_type.data_type) {
459 csignew.add_argument (new CCodeConstant ("G_TYPE_STRV"));
460 } else {
461 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
463 csignew.add_argument (new CCodeConstant ("G_TYPE_INT"));
464 } else if (param.variable_type is PointerType || param.variable_type.type_parameter != null || param.direction != ParameterDirection.IN) {
465 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
466 } else if (param.variable_type is ErrorType) {
467 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
468 } else {
469 csignew.add_argument (new CCodeConstant (param.variable_type.data_type.get_type_id ()));
473 marshal_arg.name = marshaller;
475 return csignew;
478 public virtual CCodeExpression get_dbus_g_type (DataType data_type) {
479 return new CCodeConstant (data_type.data_type.get_type_id ());
482 public override void visit_element_access (ElementAccess expr) {
483 if (expr.container is MemberAccess && expr.container.symbol_reference is Signal && expr.parent_node is MethodCall) {
484 // detailed signal emission
485 var sig = (Signal) expr.symbol_reference;
486 var ma = (MemberAccess) expr.container;
488 var detail_expr = expr.get_indices ().get (0);
489 var signal_name_cexpr = get_signal_name_cexpression (sig, detail_expr, expr);
491 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
492 ccall.add_argument (get_cvalue (ma.inner));
493 if (signal_name_cexpr != null) {
494 ccall.add_argument (signal_name_cexpr);
496 set_cvalue (expr, ccall);
497 } else {
498 base.visit_element_access (expr);
502 bool in_gobject_instance (Method m) {
503 bool result = false;
504 if (m.binding == MemberBinding.INSTANCE) {
505 result = m.this_parameter.variable_type.data_type.is_subtype_of (gobject_type);
507 return result;
510 void emit_signal_assignment (Assignment assignment) {
511 var sig = (Signal) assignment.left.symbol_reference;
513 bool disconnect = false;
515 if (assignment.operator == AssignmentOperator.ADD) {
516 // connect
517 } else if (assignment.operator == AssignmentOperator.SUB) {
518 // disconnect
519 disconnect = true;
520 } else {
521 assignment.error = true;
522 Report.error (assignment.source_reference, "Specified compound assignment type for signals not supported.");
523 return;
526 connect_signal (sig, assignment.left, assignment.right, disconnect, false, assignment);
529 public override void visit_assignment (Assignment assignment) {
530 if (assignment.left.symbol_reference is Signal) {
531 if (assignment.left.error || assignment.right.error) {
532 assignment.error = true;
533 return;
536 emit_signal_assignment (assignment);
537 } else {
538 base.visit_assignment (assignment);
542 public override void visit_member_access (MemberAccess expr) {
543 if (expr.symbol_reference is Signal) {
544 CCodeExpression pub_inst = null;
546 if (expr.inner != null) {
547 pub_inst = get_cvalue (expr.inner);
550 var sig = (Signal) expr.symbol_reference;
551 var cl = (TypeSymbol) sig.parent_symbol;
553 if (expr.inner is BaseAccess && sig.is_virtual) {
554 var m = sig.default_handler;
555 var base_class = (Class) m.parent_symbol;
556 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
557 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
559 set_cvalue (expr, new CCodeMemberAccess.pointer (vcast, m.name));
560 return;
563 if (sig.has_emitter) {
564 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name)));
566 ccall.add_argument (pub_inst);
567 set_cvalue (expr, ccall);
568 } else {
569 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
570 ccall.add_argument (pub_inst);
572 ccall.add_argument (sig.get_canonical_cconstant ());
574 set_cvalue (expr, ccall);
576 } else {
577 base.visit_member_access (expr);
581 public override void visit_method_call (MethodCall expr) {
582 var method_type = expr.call.value_type as MethodType;
584 if (method_type == null || !(method_type.method_symbol.parent_symbol is Signal)) {
585 // no signal connect/disconnect call
586 base.visit_method_call (expr);
587 return;
590 var sig = (Signal) method_type.method_symbol.parent_symbol;
591 var signal_access = ((MemberAccess) expr.call).inner;
592 var handler = expr.get_argument_list ().get (0);
594 bool disconnect = (method_type.method_symbol.name == "disconnect");
595 bool after = (method_type.method_symbol.name == "connect_after");
597 var cexpr = connect_signal (sig, signal_access, handler, disconnect, after, expr);
598 set_cvalue (expr, cexpr);
601 CCodeExpression? connect_signal (Signal sig, Expression signal_access, Expression handler, bool disconnect, bool after, CodeNode expr) {
602 string connect_func;
604 var m = (Method) handler.symbol_reference;
606 if (!disconnect) {
607 // connect
608 if (sig is DynamicSignal) {
609 if (!after)
610 connect_func = get_dynamic_signal_connect_wrapper_name ((DynamicSignal) sig);
611 else
612 connect_func = get_dynamic_signal_connect_after_wrapper_name ((DynamicSignal) sig);
613 } else {
614 if (m.closure) {
615 connect_func = "g_signal_connect_data";
616 } else if (in_gobject_instance (m)) {
617 connect_func = "g_signal_connect_object";
618 } else if (!after) {
619 connect_func = "g_signal_connect";
620 } else
621 connect_func = "g_signal_connect_after";
623 } else {
624 // disconnect
625 if (handler is LambdaExpression) {
626 Report.error (handler.source_reference, "Cannot disconnect lambda expression from signal. Use Object.disconnect.");
628 if (sig is DynamicSignal) {
629 connect_func = get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal) sig);
630 } else {
631 connect_func = "g_signal_handlers_disconnect_matched";
635 var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
637 CCodeExpression signal_name_cexpr = null;
639 // first argument: instance of sender
640 MemberAccess ma;
641 if (signal_access is ElementAccess) {
642 var ea = (ElementAccess) signal_access;
643 ma = (MemberAccess) ea.container;
644 var detail_expr = ea.get_indices ().get (0);
645 signal_name_cexpr = get_signal_name_cexpression (sig, detail_expr, expr);
646 if (signal_name_cexpr == null) {
647 return null;
649 } else {
650 ma = (MemberAccess) signal_access;
651 signal_name_cexpr = get_signal_name_cexpression (sig, null, expr);
653 if (ma.inner != null) {
654 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
655 } else {
656 ccall.add_argument (get_result_cexpression ("self"));
659 if (sig is DynamicSignal) {
660 // dynamic_signal_connect or dynamic_signal_disconnect
662 // second argument: signal name
663 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
664 } else if (!disconnect) {
665 // g_signal_connect_object or g_signal_connect
667 // second argument: signal name
668 ccall.add_argument (signal_name_cexpr);
669 } else {
670 // g_signal_handlers_disconnect_matched
672 // second argument: mask
673 if (!(signal_access is ElementAccess)) {
674 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
675 } else {
676 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
679 // get signal id
680 var temp_decl = get_temp_variable (uint_type);
681 emit_temp_var (temp_decl);
682 var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
683 parse_call.add_argument (signal_name_cexpr);
684 var decl_type = (TypeSymbol) sig.parent_symbol;
685 parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
686 parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_decl.name)));
687 LocalVariable? detail_temp_decl = null;
688 if (!(signal_access is ElementAccess)) {
689 parse_call.add_argument (new CCodeConstant ("NULL"));
690 parse_call.add_argument (new CCodeConstant ("FALSE"));
691 } else {
692 detail_temp_decl = get_temp_variable (gquark_type);
693 emit_temp_var (detail_temp_decl);
694 parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (detail_temp_decl.name)));
695 parse_call.add_argument (new CCodeConstant ("TRUE"));
697 ccode.add_expression (parse_call);
699 // third argument: signal_id
700 ccall.add_argument (get_variable_cexpression (temp_decl.name));
702 // fourth argument: detail
703 if (detail_temp_decl == null) {
704 ccall.add_argument (new CCodeConstant ("0"));
705 } else {
706 ccall.add_argument (get_variable_cexpression (detail_temp_decl.name));
708 // fifth argument: closure
709 ccall.add_argument (new CCodeConstant ("NULL"));
712 // third resp. sixth argument: handler
713 ccall.add_argument (new CCodeCastExpression (get_cvalue (handler), "GCallback"));
715 if (m.closure) {
716 // g_signal_connect_data
718 // fourth argument: user_data
719 CCodeExpression handler_destroy_notify;
720 ccall.add_argument (get_delegate_target_cexpression (handler, out handler_destroy_notify));
722 // fifth argument: destroy_notify
723 ccall.add_argument (new CCodeCastExpression (handler_destroy_notify, "GClosureNotify"));
725 // sixth argument: connect_flags
726 if (!after)
727 ccall.add_argument (new CCodeConstant ("0"));
728 else
729 ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
730 } else if (m.binding == MemberBinding.INSTANCE) {
731 // g_signal_connect_object or g_signal_handlers_disconnect_matched
732 // or dynamic_signal_connect or dynamic_signal_disconnect
734 // fourth resp. seventh argument: object/user_data
735 if (handler is MemberAccess) {
736 var right_ma = (MemberAccess) handler;
737 if (right_ma.inner != null) {
738 ccall.add_argument (get_cvalue (right_ma.inner));
739 } else {
740 ccall.add_argument (get_result_cexpression ("self"));
742 } else if (handler is LambdaExpression) {
743 ccall.add_argument (get_result_cexpression ("self"));
745 if (!disconnect && !(sig is DynamicSignal)
746 && in_gobject_instance (m)) {
747 // g_signal_connect_object
749 // fifth argument: connect_flags
750 if (!after)
751 ccall.add_argument (new CCodeConstant ("0"));
752 else
753 ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
755 } else {
756 // g_signal_connect or g_signal_connect_after or g_signal_handlers_disconnect_matched
757 // or dynamic_signal_connect or dynamic_signal_disconnect
759 // fourth resp. seventh argument: user_data
760 ccall.add_argument (new CCodeConstant ("NULL"));
763 if (disconnect || expr.parent_node is ExpressionStatement) {
764 ccode.add_expression (ccall);
765 return null;
766 } else {
767 var temp_var = get_temp_variable (ulong_type);
768 var temp_ref = get_variable_cexpression (temp_var.name);
770 emit_temp_var (temp_var);
772 ccode.add_assignment (temp_ref, ccall);
774 return temp_ref;