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