girparser: Support negative integer literals in metadata.
[vala-lang.git] / codegen / valagsignalmodule.vala
blobfaf6e859811e31be88c8720721f5d3a4ad3ae277
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) {
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 (((ArrayType) t).element_type.data_type == string_type.data_type) {
34 return ("BOXED,INT");
35 } else {
36 return ("POINTER,INT");
38 } else if (t is VoidType) {
39 return ("VOID");
40 } else if (t.data_type is Enum) {
41 var en = (Enum) t.data_type;
42 return en.get_marshaller_type_name ();
43 } else {
44 return t.data_type.get_marshaller_type_name ();
48 private string get_marshaller_type_name_for_parameter (Parameter param) {
49 if (param.direction != ParameterDirection.IN) {
50 return ("POINTER");
51 } else {
52 return get_marshaller_type_name (param.variable_type);
56 string get_marshaller_function (List<Parameter> params, DataType return_type, string? prefix = null) {
57 var signature = get_marshaller_signature (params, return_type);
58 string ret;
60 if (prefix == null) {
61 if (predefined_marshal_set.contains (signature)) {
62 prefix = "g_cclosure_marshal";
63 } else {
64 prefix = "g_cclosure_user_marshal";
68 ret = "%s_%s_".printf (prefix, get_marshaller_type_name (return_type));
70 if (params == null || params.size == 0) {
71 ret = ret + "_VOID";
72 } else {
73 foreach (Parameter p in params) {
74 ret = "%s_%s".printf (ret, get_marshaller_type_name_for_parameter (p).replace (",", "_"));
78 return ret;
81 private string? get_value_type_name_from_type_reference (DataType t) {
82 if (t is PointerType || t.type_parameter != null) {
83 return "gpointer";
84 } else if (t is VoidType) {
85 return "void";
86 } else if (t.data_type == string_type.data_type) {
87 return "const char*";
88 } else if (t.data_type is Class || t.data_type is Interface) {
89 return "gpointer";
90 } else if (t.data_type is Struct) {
91 var st = (Struct) t.data_type;
92 if (st.is_simple_type ()) {
93 return t.data_type.get_cname ();
94 } else {
95 return "gpointer";
97 } else if (t.data_type is Enum) {
98 return "gint";
99 } else if (t is ArrayType) {
100 return "gpointer";
101 } else if (t is ErrorType) {
102 return "gpointer";
105 return null;
108 private string? get_value_type_name_from_parameter (Parameter p) {
109 if (p.direction != ParameterDirection.IN) {
110 return "gpointer";
111 } else {
112 return get_value_type_name_from_type_reference (p.variable_type);
116 private string get_marshaller_signature (List<Parameter> params, DataType return_type) {
117 string signature;
119 signature = "%s:".printf (get_marshaller_type_name (return_type));
120 if (params == null || params.size == 0) {
121 signature = signature + "VOID";
122 } else {
123 bool first = true;
124 foreach (Parameter p in params) {
125 if (first) {
126 signature = signature + get_marshaller_type_name_for_parameter (p);
127 first = false;
128 } else {
129 signature = "%s,%s".printf (signature, get_marshaller_type_name_for_parameter (p));
134 return signature;
137 private CCodeExpression? get_signal_name_cexpression (Signal sig, Expression? detail_expr, CodeNode node) {
138 if (detail_expr == null) {
139 return sig.get_canonical_cconstant ();
142 if (detail_expr.value_type is NullType || !detail_expr.value_type.compatible (string_type)) {
143 node.error = true;
144 Report.error (detail_expr.source_reference, "only string details are supported");
145 return null;
148 if (detail_expr is StringLiteral) {
149 return sig.get_canonical_cconstant (((StringLiteral) detail_expr).eval ());
152 var detail_decl = get_temp_variable (detail_expr.value_type, true, node);
153 emit_temp_var (detail_decl);
154 temp_ref_vars.insert (0, detail_decl);
156 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat"));
157 ccall.add_argument (sig.get_canonical_cconstant (""));
158 ccall.add_argument (get_cvalue (detail_expr));
159 ccall.add_argument (new CCodeConstant ("NULL"));
161 ccode.add_assignment (get_variable_cexpression (detail_decl.name), ccall);
162 return get_variable_cexpression (detail_decl.name);
165 public override void visit_signal (Signal sig) {
166 // parent_symbol may be null for dynamic signals
168 var cl = sig.parent_symbol as Class;
169 if (cl != null && cl.is_compact) {
170 sig.error = true;
171 Report.error (sig.source_reference, "Signals are not supported in compact classes");
172 return;
175 if (cl != null) {
176 foreach (DataType base_type in cl.get_base_types ()) {
177 if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, sig.name) is Signal) {
178 sig.error = true;
179 Report.error (sig.source_reference, "Signals with the same name as a signal in a base type are not supported");
180 return;
185 sig.accept_children (this);
187 // declare parameter type
188 foreach (Parameter p in sig.get_parameters ()) {
189 generate_parameter (p, cfile, new HashMap<int,CCodeParameter> (), null);
192 generate_marshaller (sig.get_parameters (), sig.return_type);
195 void generate_marshaller (List<Parameter> params, DataType return_type) {
196 string signature;
197 int n_params, i;
199 /* check whether a signal with the same signature already exists for this source file (or predefined) */
200 signature = get_marshaller_signature (params, return_type);
201 if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) {
202 return;
205 var signal_marshaller = new CCodeFunction (get_marshaller_function (params, return_type, null), "void");
206 signal_marshaller.modifiers = CCodeModifiers.STATIC;
208 signal_marshaller.add_parameter (new CCodeParameter ("closure", "GClosure *"));
209 signal_marshaller.add_parameter (new CCodeParameter ("return_value", "GValue *"));
210 signal_marshaller.add_parameter (new CCodeParameter ("n_param_values", "guint"));
211 signal_marshaller.add_parameter (new CCodeParameter ("param_values", "const GValue *"));
212 signal_marshaller.add_parameter (new CCodeParameter ("invocation_hint", "gpointer"));
213 signal_marshaller.add_parameter (new CCodeParameter ("marshal_data", "gpointer"));
215 cfile.add_function_declaration (signal_marshaller);
217 var marshaller_body = new CCodeBlock ();
219 var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (params, return_type, "GMarshalFunc"));
220 callback_decl.add_parameter (new CCodeParameter ("data1", "gpointer"));
221 n_params = 1;
222 foreach (Parameter p in params) {
223 callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), get_value_type_name_from_parameter (p)));
224 n_params++;
225 if (p.variable_type.is_array ()) {
226 callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), "gint"));
227 n_params++;
230 callback_decl.add_parameter (new CCodeParameter ("data2", "gpointer"));
231 marshaller_body.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type), callback_decl));
233 var var_decl = new CCodeDeclaration (get_marshaller_function (params, return_type, "GMarshalFunc"));
234 var_decl.modifiers = CCodeModifiers.REGISTER;
235 var_decl.add_declarator (new CCodeVariableDeclarator ("callback"));
236 marshaller_body.add_statement (var_decl);
238 var_decl = new CCodeDeclaration ("GCClosure *");
239 var_decl.modifiers = CCodeModifiers.REGISTER;
240 var_decl.add_declarator (new CCodeVariableDeclarator ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")));
241 marshaller_body.add_statement (var_decl);
243 var_decl = new CCodeDeclaration ("gpointer");
244 var_decl.modifiers = CCodeModifiers.REGISTER;
245 var_decl.add_declarator (new CCodeVariableDeclarator ("data1"));
246 var_decl.add_declarator (new CCodeVariableDeclarator ("data2"));
247 marshaller_body.add_statement (var_decl);
249 CCodeFunctionCall fc;
251 if (return_type.data_type != null || return_type.is_array ()) {
252 var_decl = new CCodeDeclaration (get_value_type_name_from_type_reference (return_type));
253 var_decl.add_declarator (new CCodeVariableDeclarator ("v_return"));
254 marshaller_body.add_statement (var_decl);
256 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
257 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL")));
258 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
261 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
262 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string())));
263 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
265 var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true);
266 var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
267 var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
268 cond.add_argument (new CCodeIdentifier ("closure"));
269 var true_block = new CCodeBlock ();
270 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), data)));
271 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), param)));
272 var false_block = new CCodeBlock ();
273 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), param)));
274 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), data)));
275 marshaller_body.add_statement (new CCodeIfStatement (cond, true_block, false_block));
277 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")));
278 marshaller_body.add_statement (new CCodeExpressionStatement (c_assign));
280 fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
281 fc.add_argument (new CCodeIdentifier ("data1"));
282 i = 1;
283 foreach (Parameter p in params) {
284 string get_value_function;
285 bool is_array = p.variable_type.is_array ();
286 if (p.direction != ParameterDirection.IN) {
287 get_value_function = "g_value_get_pointer";
288 } else if (is_array) {
289 if (((ArrayType) p.variable_type).element_type.data_type == string_type.data_type) {
290 get_value_function = "g_value_get_boxed";
291 } else {
292 get_value_function = "g_value_get_pointer";
294 } else if (p.variable_type is PointerType || p.variable_type.type_parameter != null) {
295 get_value_function = "g_value_get_pointer";
296 } else if (p.variable_type is ErrorType) {
297 get_value_function = "g_value_get_pointer";
298 } else {
299 get_value_function = p.variable_type.data_type.get_get_value_function ();
301 var inner_fc = new CCodeFunctionCall (new CCodeIdentifier (get_value_function));
302 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
303 fc.add_argument (inner_fc);
304 i++;
305 if (is_array) {
306 inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_int"));
307 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
308 fc.add_argument (inner_fc);
309 i++;
312 fc.add_argument (new CCodeIdentifier ("data2"));
314 if (return_type.data_type != null || return_type.is_array ()) {
315 marshaller_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("v_return"), fc)));
317 CCodeFunctionCall set_fc;
318 if (return_type.is_array ()) {
319 if (((ArrayType) return_type).element_type.data_type == string_type.data_type) {
320 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
321 } else {
322 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
324 } else if (return_type.type_parameter != null) {
325 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
326 } else if (return_type is ErrorType) {
327 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
328 } else if (return_type.data_type == string_type.data_type) {
329 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_string"));
330 } else if (return_type.data_type is Class || return_type.data_type is Interface) {
331 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object"));
332 } else {
333 set_fc = new CCodeFunctionCall (new CCodeIdentifier (return_type.data_type.get_set_value_function ()));
335 set_fc.add_argument (new CCodeIdentifier ("return_value"));
336 set_fc.add_argument (new CCodeIdentifier ("v_return"));
338 marshaller_body.add_statement (new CCodeExpressionStatement (set_fc));
339 } else {
340 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
343 signal_marshaller.block = marshaller_body;
345 cfile.add_function (signal_marshaller);
346 user_marshal_set.add (signature);
349 public override CCodeFunctionCall get_signal_creation (Signal sig, TypeSymbol type) {
350 var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new"));
351 var cl = sig.parent_symbol as Class;
352 csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.get_cname ())));
353 csignew.add_argument (new CCodeIdentifier (type.get_type_id ()));
354 string[] flags = new string[0];
355 if (sig.run_type == "first") {
356 flags += "G_SIGNAL_RUN_FIRST";
357 } else if (sig.run_type == "cleanup") {
358 flags += "G_SIGNAL_RUN_CLEANUP";
359 } else {
360 flags += "G_SIGNAL_RUN_LAST";
362 if (sig.is_detailed) {
363 flags += "G_SIGNAL_DETAILED";
366 if (sig.no_recurse) {
367 flags += "G_SIGNAL_NO_RECURSE";
370 if (sig.is_action) {
371 flags += "G_SIGNAL_ACTION";
374 if (sig.no_hooks) {
375 flags += "G_SIGNAL_NO_HOOKS";
378 csignew.add_argument (new CCodeConstant (string.joinv (" | ", flags)));
380 if (sig.default_handler == null) {
381 csignew.add_argument (new CCodeConstant ("0"));
382 } else {
383 var struct_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET"));
384 struct_offset.add_argument (new CCodeIdentifier ("%sClass".printf (cl.get_cname ())));
385 struct_offset.add_argument (new CCodeIdentifier (sig.default_handler.vfunc_name));
386 csignew.add_argument (struct_offset);
388 csignew.add_argument (new CCodeConstant ("NULL"));
389 csignew.add_argument (new CCodeConstant ("NULL"));
391 string marshaller = get_marshaller_function (sig.get_parameters (), sig.return_type);
393 var marshal_arg = new CCodeIdentifier (marshaller);
394 csignew.add_argument (marshal_arg);
396 var params = sig.get_parameters ();
397 if (sig.return_type is PointerType || sig.return_type.type_parameter != null) {
398 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
399 } else if (sig.return_type is ErrorType) {
400 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
401 } else if (sig.return_type.data_type == null) {
402 csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
403 } else {
404 csignew.add_argument (new CCodeConstant (sig.return_type.data_type.get_type_id ()));
407 int params_len = 0;
408 foreach (Parameter param in params) {
409 params_len++;
410 if (param.variable_type.is_array ()) {
411 params_len++;
415 csignew.add_argument (new CCodeConstant ("%d".printf (params_len)));
416 foreach (Parameter param in params) {
417 if (param.variable_type.is_array ()) {
418 if (((ArrayType) param.variable_type).element_type.data_type == string_type.data_type) {
419 csignew.add_argument (new CCodeConstant ("G_TYPE_STRV"));
420 } else {
421 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
423 csignew.add_argument (new CCodeConstant ("G_TYPE_INT"));
424 } else if (param.variable_type is PointerType || param.variable_type.type_parameter != null || param.direction != ParameterDirection.IN) {
425 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
426 } else if (param.variable_type is ErrorType) {
427 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
428 } else {
429 csignew.add_argument (new CCodeConstant (param.variable_type.data_type.get_type_id ()));
433 marshal_arg.name = marshaller;
435 return csignew;
438 public override void visit_element_access (ElementAccess expr) {
439 if (expr.container is MemberAccess && expr.container.symbol_reference is Signal && expr.parent_node is MethodCall) {
440 // detailed signal emission
441 var sig = (Signal) expr.symbol_reference;
442 var ma = (MemberAccess) expr.container;
444 var detail_expr = expr.get_indices ().get (0);
445 var signal_name_cexpr = get_signal_name_cexpression (sig, detail_expr, expr);
447 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
448 ccall.add_argument (get_cvalue (ma.inner));
449 if (signal_name_cexpr != null) {
450 ccall.add_argument (signal_name_cexpr);
452 set_cvalue (expr, ccall);
453 } else {
454 base.visit_element_access (expr);
458 bool in_gobject_instance (Method m) {
459 bool result = false;
460 if (m.binding == MemberBinding.INSTANCE) {
461 result = m.this_parameter.variable_type.data_type.is_subtype_of (gobject_type);
463 return result;
466 void emit_signal_assignment (Assignment assignment) {
467 var sig = (Signal) assignment.left.symbol_reference;
469 bool disconnect = false;
471 if (assignment.operator == AssignmentOperator.ADD) {
472 // connect
473 } else if (assignment.operator == AssignmentOperator.SUB) {
474 // disconnect
475 disconnect = true;
476 } else {
477 assignment.error = true;
478 Report.error (assignment.source_reference, "Specified compound assignment type for signals not supported.");
479 return;
482 connect_signal (sig, assignment.left, assignment.right, disconnect, false, assignment);
485 public override void visit_assignment (Assignment assignment) {
486 if (assignment.left.symbol_reference is Signal) {
487 if (assignment.left.error || assignment.right.error) {
488 assignment.error = true;
489 return;
492 emit_signal_assignment (assignment);
493 } else {
494 base.visit_assignment (assignment);
498 public override void visit_member_access (MemberAccess expr) {
499 if (expr.symbol_reference is Signal) {
500 CCodeExpression pub_inst = null;
502 if (expr.inner != null) {
503 pub_inst = get_cvalue (expr.inner);
506 var sig = (Signal) expr.symbol_reference;
507 var cl = (TypeSymbol) sig.parent_symbol;
509 if (expr.inner is BaseAccess && sig.is_virtual) {
510 var m = sig.default_handler;
511 var base_class = (Class) m.parent_symbol;
512 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
513 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
515 set_cvalue (expr, new CCodeMemberAccess.pointer (vcast, m.name));
516 return;
519 if (sig.has_emitter) {
520 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name)));
522 ccall.add_argument (pub_inst);
523 set_cvalue (expr, ccall);
524 } else {
525 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
526 ccall.add_argument (pub_inst);
528 ccall.add_argument (sig.get_canonical_cconstant ());
530 set_cvalue (expr, ccall);
532 } else {
533 base.visit_member_access (expr);
537 public override void visit_method_call (MethodCall expr) {
538 var method_type = expr.call.value_type as MethodType;
540 if (method_type == null || !(method_type.method_symbol.parent_symbol is Signal)) {
541 // no signal connect/disconnect call
542 base.visit_method_call (expr);
543 return;
546 var sig = (Signal) method_type.method_symbol.parent_symbol;
547 var signal_access = ((MemberAccess) expr.call).inner;
548 var handler = expr.get_argument_list ().get (0);
550 bool disconnect = (method_type.method_symbol.name == "disconnect");
551 bool after = (method_type.method_symbol.name == "connect_after");
553 var cexpr = connect_signal (sig, signal_access, handler, disconnect, after, expr);
554 set_cvalue (expr, cexpr);
557 CCodeExpression? connect_signal (Signal sig, Expression signal_access, Expression handler, bool disconnect, bool after, CodeNode expr) {
558 string connect_func;
560 var m = (Method) handler.symbol_reference;
562 if (!disconnect) {
563 // connect
564 if (sig is DynamicSignal) {
565 if (!after)
566 connect_func = get_dynamic_signal_connect_wrapper_name ((DynamicSignal) sig);
567 else
568 connect_func = get_dynamic_signal_connect_after_wrapper_name ((DynamicSignal) sig);
569 } else {
570 if (m.closure) {
571 connect_func = "g_signal_connect_data";
572 } else if (in_gobject_instance (m)) {
573 connect_func = "g_signal_connect_object";
574 } else if (!after) {
575 connect_func = "g_signal_connect";
576 } else
577 connect_func = "g_signal_connect_after";
579 } else {
580 // disconnect
581 if (handler is LambdaExpression) {
582 Report.error (handler.source_reference, "Cannot disconnect lambda expression from signal. Use Object.disconnect.");
584 if (sig is DynamicSignal) {
585 connect_func = get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal) sig);
586 } else {
587 connect_func = "g_signal_handlers_disconnect_matched";
591 var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
593 CCodeExpression signal_name_cexpr = null;
595 // first argument: instance of sender
596 MemberAccess ma;
597 if (signal_access is ElementAccess) {
598 var ea = (ElementAccess) signal_access;
599 ma = (MemberAccess) ea.container;
600 var detail_expr = ea.get_indices ().get (0);
601 signal_name_cexpr = get_signal_name_cexpression (sig, detail_expr, expr);
602 if (signal_name_cexpr == null) {
603 return null;
605 } else {
606 ma = (MemberAccess) signal_access;
607 signal_name_cexpr = get_signal_name_cexpression (sig, null, expr);
609 if (ma.inner != null) {
610 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
611 } else {
612 ccall.add_argument (get_result_cexpression ("self"));
615 if (sig is DynamicSignal) {
616 // dynamic_signal_connect or dynamic_signal_disconnect
618 // second argument: signal name
619 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
620 } else if (!disconnect) {
621 // g_signal_connect_object or g_signal_connect
623 // second argument: signal name
624 ccall.add_argument (signal_name_cexpr);
625 } else {
626 // g_signal_handlers_disconnect_matched
628 // second argument: mask
629 if (!(signal_access is ElementAccess)) {
630 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
631 } else {
632 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
635 // get signal id
636 var temp_decl = get_temp_variable (uint_type);
637 emit_temp_var (temp_decl);
638 var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
639 parse_call.add_argument (signal_name_cexpr);
640 var decl_type = (TypeSymbol) sig.parent_symbol;
641 parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
642 parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_decl.name)));
643 LocalVariable? detail_temp_decl = null;
644 if (!(signal_access is ElementAccess)) {
645 parse_call.add_argument (new CCodeConstant ("NULL"));
646 parse_call.add_argument (new CCodeConstant ("FALSE"));
647 } else {
648 detail_temp_decl = get_temp_variable (gquark_type);
649 emit_temp_var (detail_temp_decl);
650 parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (detail_temp_decl.name)));
651 parse_call.add_argument (new CCodeConstant ("TRUE"));
653 ccode.add_expression (parse_call);
655 // third argument: signal_id
656 ccall.add_argument (get_variable_cexpression (temp_decl.name));
658 // fourth argument: detail
659 if (detail_temp_decl == null) {
660 ccall.add_argument (new CCodeConstant ("0"));
661 } else {
662 ccall.add_argument (get_variable_cexpression (detail_temp_decl.name));
664 // fifth argument: closure
665 ccall.add_argument (new CCodeConstant ("NULL"));
668 // third resp. sixth argument: handler
669 ccall.add_argument (new CCodeCastExpression (get_cvalue (handler), "GCallback"));
671 if (m.closure) {
672 // g_signal_connect_data
674 // fourth argument: user_data
675 CCodeExpression handler_destroy_notify;
676 ccall.add_argument (get_delegate_target_cexpression (handler, out handler_destroy_notify));
678 // fifth argument: destroy_notify
679 ccall.add_argument (new CCodeCastExpression (handler_destroy_notify, "GClosureNotify"));
681 // sixth argument: connect_flags
682 if (!after)
683 ccall.add_argument (new CCodeConstant ("0"));
684 else
685 ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
686 } else if (m.binding == MemberBinding.INSTANCE) {
687 // g_signal_connect_object or g_signal_handlers_disconnect_matched
688 // or dynamic_signal_connect or dynamic_signal_disconnect
690 // fourth resp. seventh argument: object/user_data
691 if (handler is MemberAccess) {
692 var right_ma = (MemberAccess) handler;
693 if (right_ma.inner != null) {
694 ccall.add_argument (get_cvalue (right_ma.inner));
695 } else {
696 ccall.add_argument (get_result_cexpression ("self"));
698 } else if (handler is LambdaExpression) {
699 ccall.add_argument (get_result_cexpression ("self"));
701 if (!disconnect && !(sig is DynamicSignal)
702 && in_gobject_instance (m)) {
703 // g_signal_connect_object
705 // fifth argument: connect_flags
706 if (!after)
707 ccall.add_argument (new CCodeConstant ("0"));
708 else
709 ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER"));
711 } else {
712 // g_signal_connect or g_signal_connect_after or g_signal_handlers_disconnect_matched
713 // or dynamic_signal_connect or dynamic_signal_disconnect
715 // fourth resp. seventh argument: user_data
716 ccall.add_argument (new CCodeConstant ("NULL"));
719 if (disconnect || expr.parent_node is ExpressionStatement) {
720 ccode.add_expression (ccall);
721 return null;
722 } else {
723 var temp_var = get_temp_variable (ulong_type);
724 var temp_ref = get_variable_cexpression (temp_var.name);
726 emit_temp_var (temp_var);
728 ccode.add_assignment (temp_ref, ccall);
730 return temp_ref;