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
) {
28 if (t is PointerType
|| t
.type_parameter
!= null) {
30 } else if (t is ErrorType
) {
32 } else if (t is ArrayType
) {
33 if (((ArrayType
) t
).element_type
.data_type
== string_type
.data_type
) {
36 return ("POINTER,INT");
38 } else if (t is VoidType
) {
40 } else if (t
.data_type is Enum
) {
41 var en
= (Enum
) t
.data_type
;
42 return en
.get_marshaller_type_name ();
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
) {
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
);
61 if (predefined_marshal_set
.contains (signature
)) {
62 prefix
= "g_cclosure_marshal";
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) {
73 foreach (Parameter p
in params
) {
74 ret
= "%s_%s".printf (ret
, get_marshaller_type_name_for_parameter (p
).replace (",", "_"));
81 private string?
get_value_type_name_from_type_reference (DataType t
) {
82 if (t is PointerType
|| t
.type_parameter
!= null) {
84 } else if (t is VoidType
) {
86 } else if (t
.data_type
== string_type
.data_type
) {
88 } else if (t
.data_type is Class
|| t
.data_type is Interface
) {
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 ();
97 } else if (t
.data_type is Enum
) {
99 } else if (t is ArrayType
) {
101 } else if (t is ErrorType
) {
108 private string?
get_value_type_name_from_parameter (Parameter p
) {
109 if (p
.direction
!= ParameterDirection
.IN
) {
112 return get_value_type_name_from_type_reference (p
.variable_type
);
116 private string get_marshaller_signature (List
<Parameter
> params
, DataType return_type
) {
119 signature
= "%s:".printf (get_marshaller_type_name (return_type
));
120 if (params
== null || params
.size
== 0) {
121 signature
= signature
+ "VOID";
124 foreach (Parameter p
in params
) {
126 signature
= signature
+ get_marshaller_type_name_for_parameter (p
);
129 signature
= "%s,%s".printf (signature
, get_marshaller_type_name_for_parameter (p
));
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
)) {
144 Report
.error (detail_expr
.source_reference
, "only string details are supported");
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
) {
171 Report
.error (sig
.source_reference
, "Signals are not supported in compact classes");
176 foreach (DataType base_type
in cl
.get_base_types ()) {
177 if (SemanticAnalyzer
.symbol_lookup_inherited (base_type
.data_type
, sig
.name
) is Signal
) {
179 Report
.error (sig
.source_reference
, "Signals with the same name as a signal in a base type are not supported");
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
) {
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
)) {
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"));
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
)));
225 if (p
.variable_type
.is_array ()) {
226 callback_decl
.add_parameter (new
CCodeParameter ("arg_%d".printf (n_params
), "gint"));
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"));
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";
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";
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
);
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
);
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"));
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"));
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
));
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";
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";
371 flags
+= "G_SIGNAL_ACTION";
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"));
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"));
404 csignew
.add_argument (new
CCodeConstant (sig
.return_type
.data_type
.get_type_id ()));
408 foreach (Parameter param
in params
) {
410 if (param
.variable_type
.is_array ()) {
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"));
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"));
429 csignew
.add_argument (new
CCodeConstant (param
.variable_type
.data_type
.get_type_id ()));
433 marshal_arg
.name
= marshaller
;
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
);
454 base.visit_element_access (expr
);
458 bool in_gobject_instance (Method m
) {
460 if (m
.binding
== MemberBinding
.INSTANCE
) {
461 result
= m
.this_parameter
.variable_type
.data_type
.is_subtype_of (gobject_type
);
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
) {
473 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
477 assignment
.error
= true;
478 Report
.error (assignment
.source_reference
, "Specified compound assignment type for signals not supported.");
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;
492 emit_signal_assignment (assignment
);
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
));
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
);
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
);
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
);
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
) {
560 var m
= (Method
) handler
.symbol_reference
;
564 if (sig is DynamicSignal
) {
566 connect_func
= get_dynamic_signal_connect_wrapper_name ((DynamicSignal
) sig
);
568 connect_func
= get_dynamic_signal_connect_after_wrapper_name ((DynamicSignal
) sig
);
571 connect_func
= "g_signal_connect_data";
572 } else if (in_gobject_instance (m
)) {
573 connect_func
= "g_signal_connect_object";
575 connect_func
= "g_signal_connect";
577 connect_func
= "g_signal_connect_after";
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
);
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
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) {
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
));
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
);
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"));
632 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
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"));
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"));
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"));
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
683 ccall
.add_argument (new
CCodeConstant ("0"));
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
));
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
707 ccall
.add_argument (new
CCodeConstant ("0"));
709 ccall
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
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
);
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
);