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 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
) {
185 Report
.error (sig
.source_reference
, "Signals are not supported in compact classes");
190 foreach (DataType base_type
in cl
.get_base_types ()) {
191 if (SemanticAnalyzer
.symbol_lookup_inherited (base_type
.data_type
, sig
.name
) is Signal
) {
193 Report
.error (sig
.source_reference
, "Signals with the same name as a signal in a base type are not supported");
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) {
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
)) {
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"));
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
)));
239 if (p
.variable_type
.is_array () && !dbus
) {
240 callback_decl
.add_parameter (new
CCodeParameter ("arg_%d".printf (n_params
), "gint"));
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"));
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
) {
304 get_value_function
= "g_value_get_boxed";
306 if (((ArrayType
) p
.variable_type
).element_type
.data_type
== string_type
.data_type
) {
307 get_value_function
= "g_value_get_boxed";
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
;
321 get_value_function
= "g_value_get_uint";
323 get_value_function
= "g_value_get_int";
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
);
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
);
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 ()) {
347 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
349 if (((ArrayType
) return_type
).element_type
.data_type
== string_type
.data_type
) {
350 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
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
;
368 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_uint"));
370 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_int"));
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
));
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";
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";
411 flags
+= "G_SIGNAL_ACTION";
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"));
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"));
444 csignew
.add_argument (new
CCodeConstant (sig
.return_type
.data_type
.get_type_id ()));
448 foreach (Parameter param
in params
) {
450 if (param
.variable_type
.is_array ()) {
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"));
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"));
469 csignew
.add_argument (new
CCodeConstant (param
.variable_type
.data_type
.get_type_id ()));
473 marshal_arg
.name
= marshaller
;
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
);
498 base.visit_element_access (expr
);
502 bool in_gobject_instance (Method m
) {
504 if (m
.binding
== MemberBinding
.INSTANCE
) {
505 result
= m
.this_parameter
.variable_type
.data_type
.is_subtype_of (gobject_type
);
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
) {
517 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
521 assignment
.error
= true;
522 Report
.error (assignment
.source_reference
, "Specified compound assignment type for signals not supported.");
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;
536 emit_signal_assignment (assignment
);
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
));
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
);
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
);
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
);
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
) {
604 var m
= (Method
) handler
.symbol_reference
;
608 if (sig is DynamicSignal
) {
610 connect_func
= get_dynamic_signal_connect_wrapper_name ((DynamicSignal
) sig
);
612 connect_func
= get_dynamic_signal_connect_after_wrapper_name ((DynamicSignal
) sig
);
615 connect_func
= "g_signal_connect_data";
616 } else if (in_gobject_instance (m
)) {
617 connect_func
= "g_signal_connect_object";
619 connect_func
= "g_signal_connect";
621 connect_func
= "g_signal_connect_after";
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
);
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
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) {
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
));
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
);
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"));
676 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
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"));
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"));
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"));
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
727 ccall
.add_argument (new
CCodeConstant ("0"));
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
));
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
751 ccall
.add_argument (new
CCodeConstant ("0"));
753 ccall
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
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
);
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
);