Fix ellipsis parameter position in generated methods
[vala-lang.git] / codegen / valagsignalmodule.vala
blobe36f5f248827dfcc3e10ceadd710a37cee09c67b
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 (FormalParameter 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<FormalParameter> 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 (FormalParameter p in params) {
88 ret = "%s_%s".printf (ret, get_marshaller_type_name_for_parameter (p, dbus));
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 (FormalParameter 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<FormalParameter> 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 (FormalParameter 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 public override void visit_signal (Signal sig) {
152 // parent_symbol may be null for dynamic signals
154 var cl = sig.parent_symbol as Class;
155 if (cl != null && cl.is_compact) {
156 sig.error = true;
157 Report.error (sig.source_reference, "Signals are not supported in compact classes");
158 return;
161 if (cl != null) {
162 foreach (DataType base_type in cl.get_base_types ()) {
163 if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, sig.name) is Signal) {
164 sig.error = true;
165 Report.error (sig.source_reference, "Signals with the same name as a signal in a base type are not supported");
166 return;
171 sig.accept_children (this);
173 // declare parameter type
174 foreach (FormalParameter p in sig.get_parameters ()) {
175 generate_parameter (p, source_declarations, new HashMap<int,CCodeFormalParameter> (), null);
178 generate_marshaller (sig.get_parameters (), sig.return_type);
181 public override void generate_marshaller (List<FormalParameter> params, DataType return_type, bool dbus = false) {
182 string signature;
183 int n_params, i;
185 /* check whether a signal with the same signature already exists for this source file (or predefined) */
186 signature = get_marshaller_signature (params, return_type, dbus);
187 if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) {
188 return;
191 var signal_marshaller = new CCodeFunction (get_marshaller_function (params, return_type, null, dbus), "void");
192 signal_marshaller.modifiers = CCodeModifiers.STATIC;
194 signal_marshaller.add_parameter (new CCodeFormalParameter ("closure", "GClosure *"));
195 signal_marshaller.add_parameter (new CCodeFormalParameter ("return_value", "GValue *"));
196 signal_marshaller.add_parameter (new CCodeFormalParameter ("n_param_values", "guint"));
197 signal_marshaller.add_parameter (new CCodeFormalParameter ("param_values", "const GValue *"));
198 signal_marshaller.add_parameter (new CCodeFormalParameter ("invocation_hint", "gpointer"));
199 signal_marshaller.add_parameter (new CCodeFormalParameter ("marshal_data", "gpointer"));
201 source_signal_marshaller_declaration.append (signal_marshaller.copy ());
203 var marshaller_body = new CCodeBlock ();
205 var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (params, return_type, "GMarshalFunc", dbus));
206 callback_decl.add_parameter (new CCodeFormalParameter ("data1", "gpointer"));
207 n_params = 1;
208 foreach (FormalParameter p in params) {
209 callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), get_value_type_name_from_parameter (p)));
210 n_params++;
211 if (p.variable_type.is_array () && !dbus) {
212 callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), "gint"));
213 n_params++;
216 callback_decl.add_parameter (new CCodeFormalParameter ("data2", "gpointer"));
217 marshaller_body.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type), callback_decl));
219 var var_decl = new CCodeDeclaration (get_marshaller_function (params, return_type, "GMarshalFunc", dbus));
220 var_decl.modifiers = CCodeModifiers.REGISTER;
221 var_decl.add_declarator (new CCodeVariableDeclarator ("callback"));
222 marshaller_body.add_statement (var_decl);
224 var_decl = new CCodeDeclaration ("GCClosure *");
225 var_decl.modifiers = CCodeModifiers.REGISTER;
226 var_decl.add_declarator (new CCodeVariableDeclarator ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")));
227 marshaller_body.add_statement (var_decl);
229 var_decl = new CCodeDeclaration ("gpointer");
230 var_decl.modifiers = CCodeModifiers.REGISTER;
231 var_decl.add_declarator (new CCodeVariableDeclarator ("data1"));
232 var_decl.add_declarator (new CCodeVariableDeclarator ("data2"));
233 marshaller_body.add_statement (var_decl);
235 CCodeFunctionCall fc;
237 if (return_type.data_type != null || return_type.is_array ()) {
238 var_decl = new CCodeDeclaration (get_value_type_name_from_type_reference (return_type));
239 var_decl.add_declarator (new CCodeVariableDeclarator ("v_return"));
240 marshaller_body.add_statement (var_decl);
242 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
243 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL")));
244 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
247 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
248 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string())));
249 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
251 var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true);
252 var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
253 var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
254 cond.add_argument (new CCodeIdentifier ("closure"));
255 var true_block = new CCodeBlock ();
256 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), data)));
257 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), param)));
258 var false_block = new CCodeBlock ();
259 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), param)));
260 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), data)));
261 marshaller_body.add_statement (new CCodeIfStatement (cond, true_block, false_block));
263 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)));
264 marshaller_body.add_statement (new CCodeExpressionStatement (c_assign));
266 fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
267 fc.add_argument (new CCodeIdentifier ("data1"));
268 i = 1;
269 foreach (FormalParameter p in params) {
270 string get_value_function;
271 bool is_array = p.variable_type.is_array ();
272 if (p.direction != ParameterDirection.IN) {
273 get_value_function = "g_value_get_pointer";
274 } else if (is_array) {
275 if (dbus) {
276 get_value_function = "g_value_get_boxed";
277 } else {
278 if (((ArrayType) p.variable_type).element_type.data_type == string_type.data_type) {
279 get_value_function = "g_value_get_boxed";
280 } else {
281 get_value_function = "g_value_get_pointer";
284 } else if (p.variable_type is PointerType || p.variable_type.type_parameter != null) {
285 get_value_function = "g_value_get_pointer";
286 } else if (p.variable_type is ErrorType) {
287 get_value_function = "g_value_get_pointer";
288 } else if (dbus && DBusModule.get_type_signature (p.variable_type).has_prefix ("(")) {
289 get_value_function = "g_value_get_boxed";
290 } else if (dbus && p.variable_type.data_type is Enum) {
291 var en = (Enum) p.variable_type.data_type;
292 if (en.is_flags) {
293 get_value_function = "g_value_get_uint";
294 } else {
295 get_value_function = "g_value_get_int";
297 } else {
298 get_value_function = p.variable_type.data_type.get_get_value_function ();
300 var inner_fc = new CCodeFunctionCall (new CCodeIdentifier (get_value_function));
301 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
302 fc.add_argument (inner_fc);
303 i++;
304 if (is_array && !dbus) {
305 inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_int"));
306 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
307 fc.add_argument (inner_fc);
308 i++;
311 fc.add_argument (new CCodeIdentifier ("data2"));
313 if (return_type.data_type != null || return_type.is_array ()) {
314 marshaller_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("v_return"), fc)));
316 CCodeFunctionCall set_fc;
317 if (return_type.is_array ()) {
318 if (dbus) {
319 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
320 } else {
321 if (((ArrayType) return_type).element_type.data_type == string_type.data_type) {
322 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
323 } else {
324 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
327 } else if (return_type.type_parameter != null) {
328 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
329 } else if (return_type is ErrorType) {
330 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
331 } else if (return_type.data_type == string_type.data_type) {
332 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_string"));
333 } else if (return_type.data_type is Class || return_type.data_type is Interface) {
334 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object"));
335 } else if (dbus && DBusModule.get_type_signature (return_type).has_prefix ("(")) {
336 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
337 } else if (dbus && return_type.data_type is Enum) {
338 var en = (Enum) return_type.data_type;
339 if (en.is_flags) {
340 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_uint"));
341 } else {
342 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_int"));
344 } else {
345 set_fc = new CCodeFunctionCall (new CCodeIdentifier (return_type.data_type.get_set_value_function ()));
347 set_fc.add_argument (new CCodeIdentifier ("return_value"));
348 set_fc.add_argument (new CCodeIdentifier ("v_return"));
350 marshaller_body.add_statement (new CCodeExpressionStatement (set_fc));
351 } else {
352 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
355 signal_marshaller.block = marshaller_body;
357 source_signal_marshaller_definition.append (signal_marshaller);
358 user_marshal_set.add (signature);
361 public override CCodeFunctionCall get_signal_creation (Signal sig, TypeSymbol type) {
362 var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new"));
363 var cl = sig.parent_symbol as Class;
364 csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.get_cname ())));
365 csignew.add_argument (new CCodeIdentifier (type.get_type_id ()));
366 string[] flags = new string[0];
367 if (sig.run_type == "first") {
368 flags += "G_SIGNAL_RUN_FIRST";
369 } else if (sig.run_type == "cleanup") {
370 flags += "G_SIGNAL_RUN_CLEANUP";
371 } else {
372 flags += "G_SIGNAL_RUN_LAST";
374 if (sig.is_detailed) {
375 flags += "G_SIGNAL_DETAILED";
378 if (sig.no_recurse) {
379 flags += "G_SIGNAL_NO_RECURSE";
382 if (sig.is_action) {
383 flags += "G_SIGNAL_ACTION";
386 if (sig.no_hooks) {
387 flags += "G_SIGNAL_NO_HOOKS";
390 csignew.add_argument (new CCodeConstant (string.joinv (" | ", flags)));
392 if (sig.default_handler == null) {
393 csignew.add_argument (new CCodeConstant ("0"));
394 } else {
395 var struct_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET"));
396 struct_offset.add_argument (new CCodeIdentifier ("%sClass".printf (cl.get_cname ())));
397 struct_offset.add_argument (new CCodeIdentifier (sig.default_handler.vfunc_name));
398 csignew.add_argument (struct_offset);
400 csignew.add_argument (new CCodeConstant ("NULL"));
401 csignew.add_argument (new CCodeConstant ("NULL"));
403 string marshaller = get_marshaller_function (sig.get_parameters (), sig.return_type);
405 var marshal_arg = new CCodeIdentifier (marshaller);
406 csignew.add_argument (marshal_arg);
408 var params = sig.get_parameters ();
409 if (sig.return_type is PointerType || sig.return_type.type_parameter != null) {
410 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
411 } else if (sig.return_type is ErrorType) {
412 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
413 } else if (sig.return_type.data_type == null) {
414 csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
415 } else {
416 csignew.add_argument (new CCodeConstant (sig.return_type.data_type.get_type_id ()));
419 int params_len = 0;
420 foreach (FormalParameter param in params) {
421 params_len++;
422 if (param.variable_type.is_array ()) {
423 params_len++;
427 csignew.add_argument (new CCodeConstant ("%d".printf (params_len)));
428 foreach (FormalParameter param in params) {
429 if (param.variable_type.is_array ()) {
430 if (((ArrayType) param.variable_type).element_type.data_type == string_type.data_type) {
431 csignew.add_argument (new CCodeConstant ("G_TYPE_STRV"));
432 } else {
433 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
435 csignew.add_argument (new CCodeConstant ("G_TYPE_INT"));
436 } else if (param.variable_type is PointerType || param.variable_type.type_parameter != null || param.direction != ParameterDirection.IN) {
437 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
438 } else if (param.variable_type is ErrorType) {
439 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
440 } else {
441 csignew.add_argument (new CCodeConstant (param.variable_type.data_type.get_type_id ()));
445 marshal_arg.name = marshaller;
447 return csignew;
450 public virtual CCodeExpression get_dbus_g_type (DataType data_type) {
451 return new CCodeConstant (data_type.data_type.get_type_id ());
454 public override void visit_element_access (ElementAccess expr) {
455 if (expr.container is MemberAccess && expr.container.symbol_reference is Signal) {
456 // detailed signal emission
457 var sig = (Signal) expr.symbol_reference;
458 var ma = (MemberAccess) expr.container;
460 var detail_expr = expr.get_indices ().get (0) as StringLiteral;
461 string signal_detail = detail_expr.eval ();
463 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
464 ccall.add_argument ((CCodeExpression) ma.inner.ccodenode);
465 ccall.add_argument (sig.get_canonical_cconstant (signal_detail));
467 expr.ccodenode = ccall;
468 } else {
469 base.visit_element_access (expr);
473 bool in_gobject_instance (Method m) {
474 bool result = false;
475 if (m.binding == MemberBinding.INSTANCE) {
476 result = m.this_parameter.variable_type.data_type.is_subtype_of (gobject_type);
478 return result;
481 CCodeExpression? emit_signal_assignment (Assignment assignment) {
482 var sig = (Signal) assignment.left.symbol_reference;
484 bool disconnect = false;
486 if (assignment.operator == AssignmentOperator.ADD) {
487 // connect
488 } else if (assignment.operator == AssignmentOperator.SUB) {
489 // disconnect
490 disconnect = true;
491 } else {
492 assignment.error = true;
493 Report.error (assignment.source_reference, "Specified compound assignment type for signals not supported.");
494 return null;
497 return connect_signal (sig, assignment.left, assignment.right, disconnect, false, assignment);
500 public override void visit_assignment (Assignment assignment) {
501 if (assignment.left.symbol_reference is Signal) {
502 if (assignment.left.error || assignment.right.error) {
503 assignment.error = true;
504 return;
507 assignment.ccodenode = emit_signal_assignment (assignment);
508 } else {
509 base.visit_assignment (assignment);
513 public override void visit_member_access (MemberAccess expr) {
514 if (expr.symbol_reference is Signal) {
515 CCodeExpression pub_inst = null;
517 if (expr.inner != null) {
518 pub_inst = (CCodeExpression) expr.inner.ccodenode;
521 var sig = (Signal) expr.symbol_reference;
522 var cl = (TypeSymbol) sig.parent_symbol;
524 if (expr.inner is BaseAccess && sig.is_virtual) {
525 var m = sig.default_handler;
526 var base_class = (Class) m.parent_symbol;
527 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
528 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
530 expr.ccodenode = new CCodeMemberAccess.pointer (vcast, m.name);
531 return;
534 if (sig.has_emitter) {
535 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name)));
537 ccall.add_argument (pub_inst);
538 expr.ccodenode = ccall;
539 } else {
540 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
541 ccall.add_argument (pub_inst);
543 ccall.add_argument (sig.get_canonical_cconstant ());
545 expr.ccodenode = ccall;
547 } else {
548 base.visit_member_access (expr);
552 public override void visit_method_call (MethodCall expr) {
553 var method_type = expr.call.value_type as MethodType;
555 if (method_type == null || !(method_type.method_symbol.parent_symbol is Signal)) {
556 // no signal connect/disconnect call
557 base.visit_method_call (expr);
558 return;
561 var sig = (Signal) method_type.method_symbol.parent_symbol;
562 var signal_access = ((MemberAccess) expr.call).inner;
563 var handler = expr.get_argument_list ().get (0);
565 bool disconnect = (method_type.method_symbol.name == "disconnect");
566 bool after = (method_type.method_symbol.name == "connect_after");
568 expr.ccodenode = connect_signal (sig, signal_access, handler, disconnect, after, expr);
571 CCodeExpression? connect_signal (Signal sig, Expression signal_access, Expression handler, bool disconnect, bool after, CodeNode expr) {
572 string connect_func;
574 var m = (Method) handler.symbol_reference;
576 if (!disconnect) {
577 // connect
578 if (sig is DynamicSignal) {
579 if (!after)
580 connect_func = get_dynamic_signal_connect_wrapper_name ((DynamicSignal) sig);
581 else
582 connect_func = get_dynamic_signal_connect_after_wrapper_name ((DynamicSignal) sig);
583 } else {
584 if (m.closure) {
585 connect_func = "g_signal_connect_data";
586 } else if (in_gobject_instance (m)) {
587 connect_func = "g_signal_connect_object";
588 } else if (!after) {
589 connect_func = "g_signal_connect";
590 } else
591 connect_func = "g_signal_connect_after";
593 } else {
594 // disconnect
595 if (sig is DynamicSignal) {
596 connect_func = get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal) sig);
597 } else {
598 connect_func = "g_signal_handlers_disconnect_matched";
602 var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
604 string signal_detail = null;
606 // first argument: instance of sender
607 MemberAccess ma;
608 if (signal_access is ElementAccess) {
609 var ea = (ElementAccess) signal_access;
610 ma = (MemberAccess) ea.container;
611 var detail_expr = ea.get_indices ().get (0) as StringLiteral;
612 if (detail_expr == null) {
613 expr.error = true;
614 Report.error (detail_expr.source_reference, "internal error: only literal string details supported");
615 return null;
617 signal_detail = detail_expr.eval ();
618 } else {
619 ma = (MemberAccess) signal_access;
621 if (ma.inner != null) {
622 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
623 } else {
624 ccall.add_argument (get_result_cexpression ("self"));
627 CCodeCommaExpression? ccomma = null;
629 if (sig is DynamicSignal) {
630 // dynamic_signal_connect or dynamic_signal_disconnect
632 // second argument: signal name
633 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
634 } else if (!disconnect) {
635 // g_signal_connect_object or g_signal_connect
637 // second argument: signal name
638 ccall.add_argument (sig.get_canonical_cconstant (signal_detail));
639 } else {
640 // g_signal_handlers_disconnect_matched
642 // second argument: mask
643 if (signal_detail == null) {
644 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
645 } else {
646 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
649 // get signal id
650 ccomma = new CCodeCommaExpression ();
651 var temp_decl = get_temp_variable (uint_type);
652 temp_vars.add (temp_decl);
653 var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
654 parse_call.add_argument (sig.get_canonical_cconstant (signal_detail));
655 var decl_type = (TypeSymbol) sig.parent_symbol;
656 parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
657 parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_decl.name)));
658 LocalVariable? detail_temp_decl = null;
659 if (signal_detail == null) {
660 parse_call.add_argument (new CCodeConstant ("NULL"));
661 parse_call.add_argument (new CCodeConstant ("FALSE"));
662 } else {
663 detail_temp_decl = get_temp_variable (gquark_type);
664 temp_vars.add (detail_temp_decl);
665 parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (detail_temp_decl.name)));
666 parse_call.add_argument (new CCodeConstant ("TRUE"));
668 ccomma.append_expression (parse_call);
670 // third argument: signal_id
671 ccall.add_argument (get_variable_cexpression (temp_decl.name));
673 // fourth argument: detail
674 if (detail_temp_decl == null) {
675 ccall.add_argument (new CCodeConstant ("0"));
676 } else {
677 ccall.add_argument (get_variable_cexpression (detail_temp_decl.name));
679 // fifth argument: closure
680 ccall.add_argument (new CCodeConstant ("NULL"));
683 // third resp. sixth argument: handler
684 ccall.add_argument (new CCodeCastExpression ((CCodeExpression) handler.ccodenode, "GCallback"));
686 if (m.closure) {
687 // g_signal_connect_data
689 // fourth argument: user_data
690 CCodeExpression handler_destroy_notify;
691 ccall.add_argument (get_delegate_target_cexpression (handler, out handler_destroy_notify));
693 // fifth argument: destroy_notify
694 ccall.add_argument (new CCodeCastExpression (handler_destroy_notify, "GClosureNotify"));
696 // sixth argument: connect_flags
697 if (!after)
698 ccall.add_argument (new CCodeConstant ("0"));
699 else
700 ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
701 } else if (m.binding == MemberBinding.INSTANCE) {
702 // g_signal_connect_object or g_signal_handlers_disconnect_matched
703 // or dynamic_signal_connect or dynamic_signal_disconnect
705 // fourth resp. seventh argument: object/user_data
706 if (handler is MemberAccess) {
707 var right_ma = (MemberAccess) handler;
708 if (right_ma.inner != null) {
709 ccall.add_argument ((CCodeExpression) right_ma.inner.ccodenode);
710 } else {
711 ccall.add_argument (get_result_cexpression ("self"));
713 } else if (handler is LambdaExpression) {
714 ccall.add_argument (get_result_cexpression ("self"));
716 if (!disconnect && !(sig is DynamicSignal)
717 && in_gobject_instance (m)) {
718 // g_signal_connect_object
720 // fifth argument: connect_flags
721 if (!after)
722 ccall.add_argument (new CCodeConstant ("0"));
723 else
724 ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
726 } else {
727 // g_signal_connect or g_signal_connect_after or g_signal_handlers_disconnect_matched
728 // or dynamic_signal_connect or dynamic_signal_disconnect
730 // fourth resp. seventh argument: user_data
731 ccall.add_argument (new CCodeConstant ("NULL"));
734 if (ccomma != null) {
735 ccomma.append_expression (ccall);
736 return ccomma;
737 } else {
738 return ccall;