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
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) {
30 } else if (t is ErrorType
) {
32 } else if (t is ArrayType
) {
36 if (((ArrayType
) t
).element_type
.data_type
== string_type
.data_type
) {
39 return ("POINTER,INT");
42 } else if (t is VoidType
) {
44 } else if (dbus
&& DBusModule
.get_type_signature (t
).has_prefix ("(")) {
46 } else if (t
.data_type is Enum
) {
47 var en
= (Enum
) t
.data_type
;
55 return en
.get_marshaller_type_name ();
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
) {
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
);
75 if (predefined_marshal_set
.contains (signature
)) {
76 prefix
= "g_cclosure_marshal";
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) {
87 foreach (Parameter p
in params
) {
88 ret
= "%s_%s".printf (ret
, get_marshaller_type_name_for_parameter (p
, dbus
).replace (",", "_"));
95 private string?
get_value_type_name_from_type_reference (DataType t
) {
96 if (t is PointerType
|| t
.type_parameter
!= null) {
98 } else if (t is VoidType
) {
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
) {
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 ();
111 } else if (t
.data_type is Enum
) {
113 } else if (t is ArrayType
) {
115 } else if (t is ErrorType
) {
122 private string?
get_value_type_name_from_parameter (Parameter p
) {
123 if (p
.direction
!= ParameterDirection
.IN
) {
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) {
133 signature
= "%s:".printf (get_marshaller_type_name (return_type
, dbus
));
134 if (params
== null || params
.size
== 0) {
135 signature
= signature
+ "VOID";
138 foreach (Parameter p
in params
) {
140 signature
= signature
+ get_marshaller_type_name_for_parameter (p
, dbus
);
143 signature
= "%s,%s".printf (signature
, get_marshaller_type_name_for_parameter (p
, dbus
));
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
)) {
158 Report
.error (detail_expr
.source_reference
, "only string details are supported");
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 var ccomma
= new
CCodeCommaExpression ();
176 ccomma
.append_expression (new
CCodeAssignment (get_variable_cexpression (detail_decl
.name
), ccall
));
177 ccomma
.append_expression (get_variable_cexpression (detail_decl
.name
));
181 public override void visit_signal (Signal sig
) {
182 // parent_symbol may be null for dynamic signals
184 var cl
= sig
.parent_symbol as Class
;
185 if (cl
!= null && cl
.is_compact
) {
187 Report
.error (sig
.source_reference
, "Signals are not supported in compact classes");
192 foreach (DataType base_type
in cl
.get_base_types ()) {
193 if (SemanticAnalyzer
.symbol_lookup_inherited (base_type
.data_type
, sig
.name
) is Signal
) {
195 Report
.error (sig
.source_reference
, "Signals with the same name as a signal in a base type are not supported");
201 sig
.accept_children (this
);
203 // declare parameter type
204 foreach (Parameter p
in sig
.get_parameters ()) {
205 generate_parameter (p
, cfile
, new HashMap
<int,CCodeParameter
> (), null);
208 generate_marshaller (sig
.get_parameters (), sig
.return_type
);
211 public override void generate_marshaller (List
<Parameter
> params
, DataType return_type
, bool dbus
= false) {
215 /* check whether a signal with the same signature already exists for this source file (or predefined) */
216 signature
= get_marshaller_signature (params
, return_type
, dbus
);
217 if (predefined_marshal_set
.contains (signature
) || user_marshal_set
.contains (signature
)) {
221 var signal_marshaller
= new
CCodeFunction (get_marshaller_function (params
, return_type
, null, dbus
), "void");
222 signal_marshaller
.modifiers
= CCodeModifiers
.STATIC
;
224 signal_marshaller
.add_parameter (new
CCodeParameter ("closure", "GClosure *"));
225 signal_marshaller
.add_parameter (new
CCodeParameter ("return_value", "GValue *"));
226 signal_marshaller
.add_parameter (new
CCodeParameter ("n_param_values", "guint"));
227 signal_marshaller
.add_parameter (new
CCodeParameter ("param_values", "const GValue *"));
228 signal_marshaller
.add_parameter (new
CCodeParameter ("invocation_hint", "gpointer"));
229 signal_marshaller
.add_parameter (new
CCodeParameter ("marshal_data", "gpointer"));
231 cfile
.add_function_declaration (signal_marshaller
);
233 var marshaller_body
= new
CCodeBlock ();
235 var callback_decl
= new
CCodeFunctionDeclarator (get_marshaller_function (params
, return_type
, "GMarshalFunc", dbus
));
236 callback_decl
.add_parameter (new
CCodeParameter ("data1", "gpointer"));
238 foreach (Parameter p
in params
) {
239 callback_decl
.add_parameter (new
CCodeParameter ("arg_%d".printf (n_params
), get_value_type_name_from_parameter (p
)));
241 if (p
.variable_type
.is_array () && !dbus
) {
242 callback_decl
.add_parameter (new
CCodeParameter ("arg_%d".printf (n_params
), "gint"));
246 callback_decl
.add_parameter (new
CCodeParameter ("data2", "gpointer"));
247 marshaller_body
.add_statement (new
CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type
), callback_decl
));
249 var var_decl
= new
CCodeDeclaration (get_marshaller_function (params
, return_type
, "GMarshalFunc", dbus
));
250 var_decl
.modifiers
= CCodeModifiers
.REGISTER
;
251 var_decl
.add_declarator (new
CCodeVariableDeclarator ("callback"));
252 marshaller_body
.add_statement (var_decl
);
254 var_decl
= new
CCodeDeclaration ("GCClosure *");
255 var_decl
.modifiers
= CCodeModifiers
.REGISTER
;
256 var_decl
.add_declarator (new
CCodeVariableDeclarator ("cc", new
CCodeCastExpression (new
CCodeIdentifier ("closure"), "GCClosure *")));
257 marshaller_body
.add_statement (var_decl
);
259 var_decl
= new
CCodeDeclaration ("gpointer");
260 var_decl
.modifiers
= CCodeModifiers
.REGISTER
;
261 var_decl
.add_declarator (new
CCodeVariableDeclarator ("data1"));
262 var_decl
.add_declarator (new
CCodeVariableDeclarator ("data2"));
263 marshaller_body
.add_statement (var_decl
);
265 CCodeFunctionCall fc
;
267 if (return_type
.data_type
!= null || return_type
.is_array ()) {
268 var_decl
= new
CCodeDeclaration (get_value_type_name_from_type_reference (return_type
));
269 var_decl
.add_declarator (new
CCodeVariableDeclarator ("v_return"));
270 marshaller_body
.add_statement (var_decl
);
272 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_return_if_fail"));
273 fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("return_value"), new
CCodeConstant ("NULL")));
274 marshaller_body
.add_statement (new
CCodeExpressionStatement (fc
));
277 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_return_if_fail"));
278 fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("n_param_values"), new
CCodeConstant (n_params
.to_string())));
279 marshaller_body
.add_statement (new
CCodeExpressionStatement (fc
));
281 var data
= new
CCodeMemberAccess (new
CCodeIdentifier ("closure"), "data", true);
282 var param
= new
CCodeMemberAccess (new
CCodeMemberAccess (new
CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
283 var cond
= new
CCodeFunctionCall (new
CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
284 cond
.add_argument (new
CCodeIdentifier ("closure"));
285 var true_block
= new
CCodeBlock ();
286 true_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data1"), data
)));
287 true_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data2"), param
)));
288 var false_block
= new
CCodeBlock ();
289 false_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data1"), param
)));
290 false_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data2"), data
)));
291 marshaller_body
.add_statement (new
CCodeIfStatement (cond
, true_block
, false_block
));
293 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
)));
294 marshaller_body
.add_statement (new
CCodeExpressionStatement (c_assign
));
296 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("callback"));
297 fc
.add_argument (new
CCodeIdentifier ("data1"));
299 foreach (Parameter p
in params
) {
300 string get_value_function
;
301 bool is_array
= p
.variable_type
.is_array ();
302 if (p
.direction
!= ParameterDirection
.IN
) {
303 get_value_function
= "g_value_get_pointer";
304 } else if (is_array
) {
306 get_value_function
= "g_value_get_boxed";
308 if (((ArrayType
) p
.variable_type
).element_type
.data_type
== string_type
.data_type
) {
309 get_value_function
= "g_value_get_boxed";
311 get_value_function
= "g_value_get_pointer";
314 } else if (p
.variable_type is PointerType
|| p
.variable_type
.type_parameter
!= null) {
315 get_value_function
= "g_value_get_pointer";
316 } else if (p
.variable_type is ErrorType
) {
317 get_value_function
= "g_value_get_pointer";
318 } else if (dbus
&& DBusModule
.get_type_signature (p
.variable_type
).has_prefix ("(")) {
319 get_value_function
= "g_value_get_boxed";
320 } else if (dbus
&& p
.variable_type
.data_type is Enum
) {
321 var en
= (Enum
) p
.variable_type
.data_type
;
323 get_value_function
= "g_value_get_uint";
325 get_value_function
= "g_value_get_int";
328 get_value_function
= p
.variable_type
.data_type
.get_get_value_function ();
330 var inner_fc
= new
CCodeFunctionCall (new
CCodeIdentifier (get_value_function
));
331 inner_fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("param_values"), new
CCodeIdentifier (i
.to_string ())));
332 fc
.add_argument (inner_fc
);
334 if (is_array
&& !dbus
) {
335 inner_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_int"));
336 inner_fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("param_values"), new
CCodeIdentifier (i
.to_string ())));
337 fc
.add_argument (inner_fc
);
341 fc
.add_argument (new
CCodeIdentifier ("data2"));
343 if (return_type
.data_type
!= null || return_type
.is_array ()) {
344 marshaller_body
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("v_return"), fc
)));
346 CCodeFunctionCall set_fc
;
347 if (return_type
.is_array ()) {
349 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
351 if (((ArrayType
) return_type
).element_type
.data_type
== string_type
.data_type
) {
352 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
354 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
357 } else if (return_type
.type_parameter
!= null) {
358 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
359 } else if (return_type is ErrorType
) {
360 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
361 } else if (return_type
.data_type
== string_type
.data_type
) {
362 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_string"));
363 } else if (return_type
.data_type is Class
|| return_type
.data_type is Interface
) {
364 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_object"));
365 } else if (dbus
&& DBusModule
.get_type_signature (return_type
).has_prefix ("(")) {
366 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
367 } else if (dbus
&& return_type
.data_type is Enum
) {
368 var en
= (Enum
) return_type
.data_type
;
370 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_uint"));
372 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_int"));
375 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier (return_type
.data_type
.get_set_value_function ()));
377 set_fc
.add_argument (new
CCodeIdentifier ("return_value"));
378 set_fc
.add_argument (new
CCodeIdentifier ("v_return"));
380 marshaller_body
.add_statement (new
CCodeExpressionStatement (set_fc
));
382 marshaller_body
.add_statement (new
CCodeExpressionStatement (fc
));
385 signal_marshaller
.block
= marshaller_body
;
387 cfile
.add_function (signal_marshaller
);
388 user_marshal_set
.add (signature
);
391 public override CCodeFunctionCall
get_signal_creation (Signal sig
, TypeSymbol type
) {
392 var csignew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_new"));
393 var cl
= sig
.parent_symbol as Class
;
394 csignew
.add_argument (new
CCodeConstant ("\"%s\"".printf (sig
.get_cname ())));
395 csignew
.add_argument (new
CCodeIdentifier (type
.get_type_id ()));
396 string[] flags
= new
string[0];
397 if (sig
.run_type
== "first") {
398 flags
+= "G_SIGNAL_RUN_FIRST";
399 } else if (sig
.run_type
== "cleanup") {
400 flags
+= "G_SIGNAL_RUN_CLEANUP";
402 flags
+= "G_SIGNAL_RUN_LAST";
404 if (sig
.is_detailed
) {
405 flags
+= "G_SIGNAL_DETAILED";
408 if (sig
.no_recurse
) {
409 flags
+= "G_SIGNAL_NO_RECURSE";
413 flags
+= "G_SIGNAL_ACTION";
417 flags
+= "G_SIGNAL_NO_HOOKS";
420 csignew
.add_argument (new
CCodeConstant (string.joinv (" | ", flags
)));
422 if (sig
.default_handler
== null) {
423 csignew
.add_argument (new
CCodeConstant ("0"));
425 var struct_offset
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_STRUCT_OFFSET"));
426 struct_offset
.add_argument (new
CCodeIdentifier ("%sClass".printf (cl
.get_cname ())));
427 struct_offset
.add_argument (new
CCodeIdentifier (sig
.default_handler
.vfunc_name
));
428 csignew
.add_argument (struct_offset
);
430 csignew
.add_argument (new
CCodeConstant ("NULL"));
431 csignew
.add_argument (new
CCodeConstant ("NULL"));
433 string marshaller
= get_marshaller_function (sig
.get_parameters (), sig
.return_type
);
435 var marshal_arg
= new
CCodeIdentifier (marshaller
);
436 csignew
.add_argument (marshal_arg
);
438 var params
= sig
.get_parameters ();
439 if (sig
.return_type is PointerType
|| sig
.return_type
.type_parameter
!= null) {
440 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
441 } else if (sig
.return_type is ErrorType
) {
442 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
443 } else if (sig
.return_type
.data_type
== null) {
444 csignew
.add_argument (new
CCodeConstant ("G_TYPE_NONE"));
446 csignew
.add_argument (new
CCodeConstant (sig
.return_type
.data_type
.get_type_id ()));
450 foreach (Parameter param
in params
) {
452 if (param
.variable_type
.is_array ()) {
457 csignew
.add_argument (new
CCodeConstant ("%d".printf (params_len
)));
458 foreach (Parameter param
in params
) {
459 if (param
.variable_type
.is_array ()) {
460 if (((ArrayType
) param
.variable_type
).element_type
.data_type
== string_type
.data_type
) {
461 csignew
.add_argument (new
CCodeConstant ("G_TYPE_STRV"));
463 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
465 csignew
.add_argument (new
CCodeConstant ("G_TYPE_INT"));
466 } else if (param
.variable_type is PointerType
|| param
.variable_type
.type_parameter
!= null || param
.direction
!= ParameterDirection
.IN
) {
467 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
468 } else if (param
.variable_type is ErrorType
) {
469 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
471 csignew
.add_argument (new
CCodeConstant (param
.variable_type
.data_type
.get_type_id ()));
475 marshal_arg
.name
= marshaller
;
480 public virtual CCodeExpression
get_dbus_g_type (DataType data_type
) {
481 return new
CCodeConstant (data_type
.data_type
.get_type_id ());
484 public override void visit_element_access (ElementAccess expr
) {
485 if (expr
.container is MemberAccess
&& expr
.container
.symbol_reference is Signal
) {
486 // detailed signal emission
487 var sig
= (Signal
) expr
.symbol_reference
;
488 var ma
= (MemberAccess
) expr
.container
;
490 var detail_expr
= expr
.get_indices ().get (0);
491 var signal_name_cexpr
= get_signal_name_cexpression (sig
, detail_expr
, expr
);
493 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_emit_by_name"));
494 ccall
.add_argument (get_cvalue (ma
.inner
));
495 if (signal_name_cexpr
!= null) {
496 ccall
.add_argument (signal_name_cexpr
);
498 set_cvalue (expr
, ccall
);
500 base.visit_element_access (expr
);
504 bool in_gobject_instance (Method m
) {
506 if (m
.binding
== MemberBinding
.INSTANCE
) {
507 result
= m
.this_parameter
.variable_type
.data_type
.is_subtype_of (gobject_type
);
512 CCodeExpression?
emit_signal_assignment (Assignment assignment
) {
513 var sig
= (Signal
) assignment
.left
.symbol_reference
;
515 bool disconnect
= false;
517 if (assignment
.operator
== AssignmentOperator
.ADD
) {
519 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
523 assignment
.error
= true;
524 Report
.error (assignment
.source_reference
, "Specified compound assignment type for signals not supported.");
528 return connect_signal (sig
, assignment
.left
, assignment
.right
, disconnect
, false, assignment
);
531 public override void visit_assignment (Assignment assignment
) {
532 if (assignment
.left
.symbol_reference is Signal
) {
533 if (assignment
.left
.error
|| assignment
.right
.error
) {
534 assignment
.error
= true;
538 set_cvalue (assignment
, emit_signal_assignment (assignment
));
540 base.visit_assignment (assignment
);
544 public override void visit_member_access (MemberAccess expr
) {
545 if (expr
.symbol_reference is Signal
) {
546 CCodeExpression pub_inst
= null;
548 if (expr
.inner
!= null) {
549 pub_inst
= get_cvalue (expr
.inner
);
552 var sig
= (Signal
) expr
.symbol_reference
;
553 var cl
= (TypeSymbol
) sig
.parent_symbol
;
555 if (expr
.inner is BaseAccess
&& sig
.is_virtual
) {
556 var m
= sig
.default_handler
;
557 var base_class
= (Class
) m
.parent_symbol
;
558 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
559 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
561 set_cvalue (expr
, new CCodeMemberAccess
.pointer (vcast
, m
.name
));
565 if (sig
.has_emitter
) {
566 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_%s".printf (cl
.get_lower_case_cname (null), sig
.name
)));
568 ccall
.add_argument (pub_inst
);
569 set_cvalue (expr
, ccall
);
571 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_emit_by_name"));
572 ccall
.add_argument (pub_inst
);
574 ccall
.add_argument (sig
.get_canonical_cconstant ());
576 set_cvalue (expr
, ccall
);
579 base.visit_member_access (expr
);
583 public override void visit_method_call (MethodCall expr
) {
584 var method_type
= expr
.call
.value_type as MethodType
;
586 if (method_type
== null || !(method_type
.method_symbol
.parent_symbol is Signal
)) {
587 // no signal connect/disconnect call
588 base.visit_method_call (expr
);
592 var sig
= (Signal
) method_type
.method_symbol
.parent_symbol
;
593 var signal_access
= ((MemberAccess
) expr
.call
).inner
;
594 var handler
= expr
.get_argument_list ().get (0);
596 bool disconnect
= (method_type
.method_symbol
.name
== "disconnect");
597 bool after
= (method_type
.method_symbol
.name
== "connect_after");
599 set_cvalue (expr
, connect_signal (sig
, signal_access
, handler
, disconnect
, after
, expr
));
602 CCodeExpression?
connect_signal (Signal sig
, Expression signal_access
, Expression handler
, bool disconnect
, bool after
, CodeNode expr
) {
605 var m
= (Method
) handler
.symbol_reference
;
609 if (sig is DynamicSignal
) {
611 connect_func
= get_dynamic_signal_connect_wrapper_name ((DynamicSignal
) sig
);
613 connect_func
= get_dynamic_signal_connect_after_wrapper_name ((DynamicSignal
) sig
);
616 connect_func
= "g_signal_connect_data";
617 } else if (in_gobject_instance (m
)) {
618 connect_func
= "g_signal_connect_object";
620 connect_func
= "g_signal_connect";
622 connect_func
= "g_signal_connect_after";
626 if (handler is LambdaExpression
) {
627 Report
.error (handler
.source_reference
, "Cannot disconnect lambda expression from signal. Use Object.disconnect.");
629 if (sig is DynamicSignal
) {
630 connect_func
= get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal
) sig
);
632 connect_func
= "g_signal_handlers_disconnect_matched";
636 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (connect_func
));
638 CCodeExpression signal_name_cexpr
= null;
640 // first argument: instance of sender
642 if (signal_access is ElementAccess
) {
643 var ea
= (ElementAccess
) signal_access
;
644 ma
= (MemberAccess
) ea
.container
;
645 var detail_expr
= ea
.get_indices ().get (0);
646 signal_name_cexpr
= get_signal_name_cexpression (sig
, detail_expr
, expr
);
647 if (signal_name_cexpr
== null) {
651 ma
= (MemberAccess
) signal_access
;
652 signal_name_cexpr
= get_signal_name_cexpression (sig
, null, expr
);
654 if (ma
.inner
!= null) {
655 ccall
.add_argument ((CCodeExpression
) get_ccodenode (ma
.inner
));
657 ccall
.add_argument (get_result_cexpression ("self"));
660 CCodeCommaExpression? ccomma
= null;
662 if (sig is DynamicSignal
) {
663 // dynamic_signal_connect or dynamic_signal_disconnect
665 // second argument: signal name
666 ccall
.add_argument (new
CCodeConstant ("\"%s\"".printf (sig
.name
)));
667 } else if (!disconnect
) {
668 // g_signal_connect_object or g_signal_connect
670 // second argument: signal name
671 ccall
.add_argument (signal_name_cexpr
);
673 // g_signal_handlers_disconnect_matched
675 // second argument: mask
676 if (!(signal_access is ElementAccess
)) {
677 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
679 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
683 ccomma
= new
CCodeCommaExpression ();
684 var temp_decl
= get_temp_variable (uint_type
);
685 emit_temp_var (temp_decl
);
686 var parse_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_parse_name"));
687 parse_call
.add_argument (signal_name_cexpr
);
688 var decl_type
= (TypeSymbol
) sig
.parent_symbol
;
689 parse_call
.add_argument (new
CCodeIdentifier (decl_type
.get_type_id ()));
690 parse_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_decl
.name
)));
691 LocalVariable? detail_temp_decl
= null;
692 if (!(signal_access is ElementAccess
)) {
693 parse_call
.add_argument (new
CCodeConstant ("NULL"));
694 parse_call
.add_argument (new
CCodeConstant ("FALSE"));
696 detail_temp_decl
= get_temp_variable (gquark_type
);
697 emit_temp_var (detail_temp_decl
);
698 parse_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (detail_temp_decl
.name
)));
699 parse_call
.add_argument (new
CCodeConstant ("TRUE"));
701 ccomma
.append_expression (parse_call
);
703 // third argument: signal_id
704 ccall
.add_argument (get_variable_cexpression (temp_decl
.name
));
706 // fourth argument: detail
707 if (detail_temp_decl
== null) {
708 ccall
.add_argument (new
CCodeConstant ("0"));
710 ccall
.add_argument (get_variable_cexpression (detail_temp_decl
.name
));
712 // fifth argument: closure
713 ccall
.add_argument (new
CCodeConstant ("NULL"));
716 // third resp. sixth argument: handler
717 ccall
.add_argument (new
CCodeCastExpression (get_cvalue (handler
), "GCallback"));
720 // g_signal_connect_data
722 // fourth argument: user_data
723 CCodeExpression handler_destroy_notify
;
724 ccall
.add_argument (get_delegate_target_cexpression (handler
, out handler_destroy_notify
));
726 // fifth argument: destroy_notify
727 ccall
.add_argument (new
CCodeCastExpression (handler_destroy_notify
, "GClosureNotify"));
729 // sixth argument: connect_flags
731 ccall
.add_argument (new
CCodeConstant ("0"));
733 ccall
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
734 } else if (m
.binding
== MemberBinding
.INSTANCE
) {
735 // g_signal_connect_object or g_signal_handlers_disconnect_matched
736 // or dynamic_signal_connect or dynamic_signal_disconnect
738 // fourth resp. seventh argument: object/user_data
739 if (handler is MemberAccess
) {
740 var right_ma
= (MemberAccess
) handler
;
741 if (right_ma
.inner
!= null) {
742 ccall
.add_argument (get_cvalue (right_ma
.inner
));
744 ccall
.add_argument (get_result_cexpression ("self"));
746 } else if (handler is LambdaExpression
) {
747 ccall
.add_argument (get_result_cexpression ("self"));
749 if (!disconnect
&& !(sig is DynamicSignal
)
750 && in_gobject_instance (m
)) {
751 // g_signal_connect_object
753 // fifth argument: connect_flags
755 ccall
.add_argument (new
CCodeConstant ("0"));
757 ccall
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
760 // g_signal_connect or g_signal_connect_after or g_signal_handlers_disconnect_matched
761 // or dynamic_signal_connect or dynamic_signal_disconnect
763 // fourth resp. seventh argument: user_data
764 ccall
.add_argument (new
CCodeConstant ("NULL"));
767 if (ccomma
!= null) {
768 ccomma
.append_expression (ccall
);