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 string get_marshaller_function (List
<Parameter
> params
, DataType return_type
, string? prefix
= null) {
28 var signature
= get_marshaller_signature (params
, return_type
);
32 if (predefined_marshal_set
.contains (signature
)) {
33 prefix
= "g_cclosure_marshal";
35 prefix
= "g_cclosure_user_marshal";
39 ret
= "%s_%s_".printf (prefix
, get_ccode_marshaller_type_name (return_type
));
41 if (params
== null || params
.size
== 0) {
44 foreach (Parameter p
in params
) {
45 ret
= "%s_%s".printf (ret
, get_ccode_marshaller_type_name (p
).replace (",", "_"));
52 private string?
get_value_type_name_from_type_reference (DataType t
) {
53 if (t is PointerType
|| t is GenericType
) {
55 } else if (t is VoidType
) {
57 } else if (get_ccode_type_id (t
) == get_ccode_type_id (string_type
)) {
59 } else if (t
.data_type is Class
|| t
.data_type is Interface
) {
61 } else if (t is ValueType
&& t
.nullable
) {
63 } else if (t
.data_type is Struct
) {
64 var st
= (Struct
) t
.data_type
;
65 if (st
.is_simple_type ()) {
66 return get_ccode_name (t
.data_type
);
70 } else if (t
.data_type is Enum
) {
72 } else if (t is ArrayType
) {
74 } else if (t is ErrorType
) {
81 private string?
get_value_type_name_from_parameter (Parameter p
) {
82 if (p
.direction
!= ParameterDirection
.IN
) {
85 return get_value_type_name_from_type_reference (p
.variable_type
);
89 private string get_marshaller_signature (List
<Parameter
> params
, DataType return_type
) {
92 signature
= "%s:".printf (get_ccode_marshaller_type_name (return_type
));
93 if (params
== null || params
.size
== 0) {
94 signature
= signature
+ "VOID";
97 foreach (Parameter p
in params
) {
99 signature
= signature
+ get_ccode_marshaller_type_name (p
);
102 signature
= "%s,%s".printf (signature
, get_ccode_marshaller_type_name (p
));
110 private CCodeExpression?
get_signal_name_cexpression (Signal sig
, Expression? detail_expr
, CodeNode node
) {
111 if (detail_expr
== null) {
112 return get_signal_canonical_constant (sig
);
115 if (detail_expr
.value_type is NullType
|| !detail_expr
.value_type
.compatible (string_type
)) {
117 Report
.error (detail_expr
.source_reference
, "only string details are supported");
121 if (detail_expr is StringLiteral
) {
122 return get_signal_canonical_constant (sig
, ((StringLiteral
) detail_expr
).eval ());
125 var detail_value
= create_temp_value (detail_expr
.value_type
, false, node
, true);
126 temp_ref_values
.insert (0, detail_value
);
128 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_strconcat"));
129 ccall
.add_argument (get_signal_canonical_constant (sig
, ""));
130 ccall
.add_argument (get_cvalue (detail_expr
));
131 ccall
.add_argument (new
CCodeConstant ("NULL"));
133 ccode
.add_assignment (get_cvalue_ (detail_value
), ccall
);
134 return get_cvalue_ (detail_value
);
137 private CCodeExpression
get_signal_id_cexpression (Signal sig
) {
138 var cl
= (TypeSymbol
) sig
.parent_symbol
;
139 var signal_array
= new
CCodeIdentifier ("%s_signals".printf (get_ccode_lower_case_name (cl
)));
140 var signal_enum_value
= new
CCodeIdentifier ("%s_%s_SIGNAL".printf (get_ccode_upper_case_name (cl
), get_ccode_upper_case_name (sig
)));
142 return new
CCodeElementAccess (signal_array
, signal_enum_value
);
145 private CCodeExpression?
get_detail_cexpression (Expression detail_expr
, CodeNode node
) {
146 if (detail_expr
.value_type is NullType
|| !detail_expr
.value_type
.compatible (string_type
)) {
148 Report
.error (detail_expr
.source_reference
, "only string details are supported");
152 var detail_cexpr
= get_cvalue (detail_expr
);
153 CCodeFunctionCall detail_ccall
;
154 if (is_constant_ccode_expression (detail_cexpr
)) {
155 detail_ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_static_string"));
157 detail_ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_quark_from_string"));
159 detail_ccall
.add_argument (detail_cexpr
);
164 public override void visit_signal (Signal sig
) {
165 // parent_symbol may be null for dynamic signals
167 var cl
= sig
.parent_symbol as Class
;
168 if (cl
!= null && cl
.is_compact
) {
170 Report
.error (sig
.source_reference
, "Signals are not supported in compact classes");
175 foreach (DataType base_type
in cl
.get_base_types ()) {
176 if (SemanticAnalyzer
.symbol_lookup_inherited (base_type
.data_type
, sig
.name
) is Signal
) {
178 Report
.error (sig
.source_reference
, "Signals with the same name as a signal in a base type are not supported");
184 signal_enum
.add_value (new
CCodeEnumValue ("%s_%s_SIGNAL".printf (get_ccode_upper_case_name ((TypeSymbol
)sig
.parent_symbol
), get_ccode_upper_case_name (sig
))));
186 sig
.accept_children (this
);
188 // declare parameter type
189 foreach (Parameter p
in sig
.get_parameters ()) {
190 generate_parameter (p
, cfile
, new HashMap
<int,CCodeParameter
> (), null);
193 generate_marshaller (sig
.get_parameters (), sig
.return_type
);
196 void generate_marshaller (List
<Parameter
> params
, DataType return_type
) {
200 /* check whether a signal with the same signature already exists for this source file (or predefined) */
201 signature
= get_marshaller_signature (params
, return_type
);
202 if (predefined_marshal_set
.contains (signature
) || user_marshal_set
.contains (signature
)) {
206 var signal_marshaller
= new
CCodeFunction (get_marshaller_function (params
, return_type
, null), "void");
207 signal_marshaller
.modifiers
= CCodeModifiers
.STATIC
;
209 signal_marshaller
.add_parameter (new
CCodeParameter ("closure", "GClosure *"));
210 signal_marshaller
.add_parameter (new
CCodeParameter ("return_value", "GValue *"));
211 signal_marshaller
.add_parameter (new
CCodeParameter ("n_param_values", "guint"));
212 signal_marshaller
.add_parameter (new
CCodeParameter ("param_values", "const GValue *"));
213 signal_marshaller
.add_parameter (new
CCodeParameter ("invocation_hint", "gpointer"));
214 signal_marshaller
.add_parameter (new
CCodeParameter ("marshal_data", "gpointer"));
216 push_function (signal_marshaller
);
218 var callback_decl
= new
CCodeFunctionDeclarator (get_marshaller_function (params
, return_type
, "GMarshalFunc"));
219 callback_decl
.add_parameter (new
CCodeParameter ("data1", "gpointer"));
221 foreach (Parameter p
in params
) {
222 callback_decl
.add_parameter (new
CCodeParameter ("arg_%d".printf (n_params
), get_value_type_name_from_parameter (p
)));
224 if (p
.variable_type
.is_array ()) {
225 for (var j
= 0; j
< ((ArrayType
) p
.variable_type
).rank
; j
++) {
226 callback_decl
.add_parameter (new
CCodeParameter ("arg_%d".printf (n_params
), "gint"));
231 callback_decl
.add_parameter (new
CCodeParameter ("data2", "gpointer"));
232 ccode
.add_statement (new
CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type
), callback_decl
));
234 ccode
.add_declaration (get_marshaller_function (params
, return_type
, "GMarshalFunc"), new
CCodeVariableDeclarator ("callback"), CCodeModifiers
.REGISTER
);
236 ccode
.add_declaration ("GCClosure *", new
CCodeVariableDeclarator ("cc", new
CCodeCastExpression (new
CCodeIdentifier ("closure"), "GCClosure *")), CCodeModifiers
.REGISTER
);
238 ccode
.add_declaration ("gpointer", new
CCodeVariableDeclarator ("data1"), CCodeModifiers
.REGISTER
);
239 ccode
.add_declaration ("gpointer", new
CCodeVariableDeclarator ("data2"), CCodeModifiers
.REGISTER
);
241 CCodeFunctionCall fc
;
243 if (return_type
.data_type
!= null || return_type
.is_array ()) {
244 ccode
.add_declaration (get_value_type_name_from_type_reference (return_type
), new
CCodeVariableDeclarator ("v_return"));
246 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_return_if_fail"));
247 fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("return_value"), new
CCodeConstant ("NULL")));
248 ccode
.add_expression (fc
);
251 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_return_if_fail"));
252 fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("n_param_values"), new
CCodeConstant (n_params
.to_string())));
253 ccode
.add_expression (fc
);
255 var data
= new
CCodeMemberAccess (new
CCodeIdentifier ("closure"), "data", true);
256 var param
= new
CCodeMemberAccess (new
CCodeMemberAccess (new
CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
257 var cond
= new
CCodeFunctionCall (new
CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
258 cond
.add_argument (new
CCodeIdentifier ("closure"));
259 ccode
.open_if (cond
);
260 ccode
.add_assignment (new
CCodeIdentifier ("data1"), data
);
261 ccode
.add_assignment (new
CCodeIdentifier ("data2"), param
);
263 ccode
.add_assignment (new
CCodeIdentifier ("data1"), param
);
264 ccode
.add_assignment (new
CCodeIdentifier ("data2"), data
);
267 var c_assign_rhs
= 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"));
268 ccode
.add_assignment (new
CCodeIdentifier ("callback"), c_assign_rhs
);
270 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("callback"));
271 fc
.add_argument (new
CCodeIdentifier ("data1"));
273 foreach (Parameter p
in params
) {
274 string get_value_function
;
275 bool is_array
= p
.variable_type
.is_array ();
276 if (p
.direction
!= ParameterDirection
.IN
) {
277 get_value_function
= "g_value_get_pointer";
278 } else if (is_array
) {
279 if (((ArrayType
) p
.variable_type
).element_type
.data_type
== string_type
.data_type
) {
280 get_value_function
= "g_value_get_boxed";
282 get_value_function
= "g_value_get_pointer";
284 } else if (p
.variable_type is PointerType
|| p
.variable_type is GenericType
) {
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 (p
.variable_type is ValueType
&& p
.variable_type
.nullable
) {
289 get_value_function
= "g_value_get_pointer";
291 get_value_function
= get_ccode_get_value_function (p
.variable_type
.data_type
);
293 var inner_fc
= new
CCodeFunctionCall (new
CCodeIdentifier (get_value_function
));
294 inner_fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("param_values"), new
CCodeIdentifier (i
.to_string ())));
295 fc
.add_argument (inner_fc
);
298 for (var j
= 0; j
< ((ArrayType
) p
.variable_type
).rank
; j
++) {
299 inner_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_int"));
300 inner_fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("param_values"), new
CCodeIdentifier (i
.to_string ())));
301 fc
.add_argument (inner_fc
);
306 fc
.add_argument (new
CCodeIdentifier ("data2"));
308 if (return_type
.data_type
!= null || return_type
.is_array ()) {
309 ccode
.add_assignment (new
CCodeIdentifier ("v_return"), fc
);
311 CCodeFunctionCall set_fc
;
312 if (return_type
.is_array ()) {
313 if (((ArrayType
) return_type
).element_type
.data_type
== string_type
.data_type
) {
314 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
316 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
318 } else if (return_type is GenericType
) {
319 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
320 } else if (return_type is ErrorType
) {
321 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
322 } else if (return_type
.data_type
== string_type
.data_type
) {
323 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_string"));
324 } else if (return_type
.data_type is Class
|| return_type
.data_type is Interface
) {
325 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_object"));
326 } else if (return_type is ValueType
&& return_type
.nullable
) {
327 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
329 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier (get_ccode_set_value_function (return_type
.data_type
)));
331 set_fc
.add_argument (new
CCodeIdentifier ("return_value"));
332 set_fc
.add_argument (new
CCodeIdentifier ("v_return"));
334 ccode
.add_expression (set_fc
);
336 ccode
.add_expression (fc
);
341 cfile
.add_function_declaration (signal_marshaller
);
342 cfile
.add_function (signal_marshaller
);
343 user_marshal_set
.add (signature
);
346 public override CCodeExpression
get_signal_creation (Signal sig
, TypeSymbol type
) {
347 var csignew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_new"));
348 csignew
.add_argument (new
CCodeConstant ("\"%s\"".printf (get_ccode_name (sig
))));
349 csignew
.add_argument (new
CCodeIdentifier (get_ccode_type_id (type
)));
350 string[] flags
= new
string[0];
351 var run_type
= sig
.get_attribute_string ("Signal", "run");
352 if (run_type
== "first") {
353 flags
+= "G_SIGNAL_RUN_FIRST";
354 } else if (run_type
== "cleanup") {
355 flags
+= "G_SIGNAL_RUN_CLEANUP";
357 flags
+= "G_SIGNAL_RUN_LAST";
359 if (sig
.get_attribute_bool ("Signal", "detailed")) {
360 flags
+= "G_SIGNAL_DETAILED";
363 if (sig
.get_attribute_bool ("Signal", "no_recurse")) {
364 flags
+= "G_SIGNAL_NO_RECURSE";
367 if (sig
.get_attribute_bool ("Signal", "action")) {
368 flags
+= "G_SIGNAL_ACTION";
371 if (sig
.get_attribute_bool ("Signal", "no_hooks")) {
372 flags
+= "G_SIGNAL_NO_HOOKS";
375 if (sig
.version
.deprecated
) {
376 flags
+= "G_SIGNAL_DEPRECATED";
379 csignew
.add_argument (new
CCodeConstant (string.joinv (" | ", flags
)));
381 if (sig
.default_handler
== null) {
382 csignew
.add_argument (new
CCodeConstant ("0"));
384 var struct_offset
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_STRUCT_OFFSET"));
386 struct_offset
.add_argument (new
CCodeIdentifier ("%sClass".printf (get_ccode_name (type
))));
389 struct_offset
.add_argument (new
CCodeIdentifier (get_ccode_type_name ((Interface
) type
)));
391 struct_offset
.add_argument (new
CCodeIdentifier (get_ccode_vfunc_name (sig
.default_handler
)));
392 csignew
.add_argument (struct_offset
);
394 csignew
.add_argument (new
CCodeConstant ("NULL"));
395 csignew
.add_argument (new
CCodeConstant ("NULL"));
397 string marshaller
= get_marshaller_function (sig
.get_parameters (), sig
.return_type
);
399 var marshal_arg
= new
CCodeIdentifier (marshaller
);
400 csignew
.add_argument (marshal_arg
);
402 var params
= sig
.get_parameters ();
403 if (sig
.return_type is PointerType
|| sig
.return_type is GenericType
) {
404 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
405 } else if (sig
.return_type is ErrorType
) {
406 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
407 } else if (sig
.return_type is ValueType
&& sig
.return_type
.nullable
) {
408 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
409 } else if (sig
.return_type
.data_type
== null) {
410 csignew
.add_argument (new
CCodeConstant ("G_TYPE_NONE"));
412 csignew
.add_argument (new
CCodeConstant (get_ccode_type_id (sig
.return_type
.data_type
)));
416 foreach (Parameter param
in params
) {
418 if (param
.variable_type
.is_array ()) {
419 params_len
+= ((ArrayType
) param
.variable_type
).rank
;
423 csignew
.add_argument (new
CCodeConstant ("%d".printf (params_len
)));
424 foreach (Parameter param
in params
) {
425 if (param
.variable_type
.is_array ()) {
426 if (((ArrayType
) param
.variable_type
).element_type
.data_type
== string_type
.data_type
) {
427 csignew
.add_argument (new
CCodeConstant ("G_TYPE_STRV"));
429 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
431 for (var i
= 0; i
< ((ArrayType
) param
.variable_type
).rank
; i
++) {
432 csignew
.add_argument (new
CCodeConstant ("G_TYPE_INT"));
434 } else if (param
.variable_type is PointerType
|| param
.variable_type is GenericType
|| param
.direction
!= ParameterDirection
.IN
) {
435 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
436 } else if (param
.variable_type is ErrorType
) {
437 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
438 } else if (param
.variable_type is ValueType
&& param
.variable_type
.nullable
) {
439 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
441 csignew
.add_argument (new
CCodeConstant (get_ccode_type_id (param
.variable_type
.data_type
)));
445 marshal_arg
.name
= marshaller
;
447 return new
CCodeAssignment (get_signal_id_cexpression (sig
), csignew
);
450 public override void visit_element_access (ElementAccess expr
) {
451 if (expr
.container is MemberAccess
&& expr
.container
.symbol_reference is Signal
) {
452 if (expr
.parent_node is MethodCall
) {
453 // detailed signal emission
454 var sig
= (Signal
) expr
.symbol_reference
;
455 var ma
= (MemberAccess
) expr
.container
;
457 var detail_expr
= expr
.get_indices ().get (0);
459 CCodeFunctionCall ccall
;
460 if (!sig
.external_package
&& expr
.source_reference
.file
== sig
.source_reference
.file
) {
461 var detail_cexpr
= get_detail_cexpression (detail_expr
, expr
);
463 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_emit"));
464 ccall
.add_argument (get_cvalue (ma
.inner
));
465 ccall
.add_argument (get_signal_id_cexpression (sig
));
466 if (detail_cexpr
!= null) {
467 ccall
.add_argument (detail_cexpr
);
470 var signal_name_cexpr
= get_signal_name_cexpression (sig
, detail_expr
, expr
);
472 ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_emit_by_name"));
473 ccall
.add_argument (get_cvalue (ma
.inner
));
474 if (signal_name_cexpr
!= null) {
475 ccall
.add_argument (signal_name_cexpr
);
479 set_cvalue (expr
, ccall
);
481 // signal connect or disconnect
484 base.visit_element_access (expr
);
488 bool in_gobject_instance (Method m
) {
490 if (m
.binding
== MemberBinding
.INSTANCE
) {
491 result
= m
.this_parameter
.variable_type
.data_type
.is_subtype_of (gobject_type
);
496 void emit_signal_assignment (Assignment assignment
) {
497 var sig
= (Signal
) assignment
.left
.symbol_reference
;
499 bool disconnect
= false;
501 if (assignment
.operator
== AssignmentOperator
.ADD
) {
503 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
507 assignment
.error
= true;
508 Report
.error (assignment
.source_reference
, "Specified compound assignment type for signals not supported.");
512 connect_signal (sig
, assignment
.left
, assignment
.right
, disconnect
, false, assignment
);
515 public override void visit_assignment (Assignment assignment
) {
516 if (assignment
.left
.symbol_reference is Signal
) {
517 if (assignment
.left
.error
|| assignment
.right
.error
) {
518 assignment
.error
= true;
522 emit_signal_assignment (assignment
);
524 base.visit_assignment (assignment
);
528 public override void visit_member_access (MemberAccess expr
) {
529 if (expr
.symbol_reference is Signal
) {
530 CCodeExpression pub_inst
= null;
532 if (expr
.inner
!= null) {
533 pub_inst
= get_cvalue (expr
.inner
);
536 var sig
= (Signal
) expr
.symbol_reference
;
537 var cl
= (TypeSymbol
) sig
.parent_symbol
;
539 if (expr
.inner is BaseAccess
&& sig
.is_virtual
) {
540 var m
= sig
.default_handler
;
541 var base_class
= (Class
) m
.parent_symbol
;
542 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (get_ccode_upper_case_name (base_class
, null))));
543 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class
))));
545 set_cvalue (expr
, new CCodeMemberAccess
.pointer (vcast
, m
.name
));
549 if (!sig
.external_package
&& expr
.source_reference
.file
== sig
.source_reference
.file
) {
550 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_emit"));
551 ccall
.add_argument (pub_inst
);
552 ccall
.add_argument (get_signal_id_cexpression (sig
));
553 ccall
.add_argument (new
CCodeConstant ("0"));
555 set_cvalue (expr
, ccall
);
556 } else if (get_signal_has_emitter (sig
)) {
558 if (sig
.emitter
!= null) {
559 if (!sig
.external_package
&& expr
.source_reference
.file
!= sig
.source_reference
.file
) {
560 generate_method_declaration (sig
.emitter
, cfile
);
562 emitter_func
= get_ccode_lower_case_name (sig
.emitter
);
564 emitter_func
= "%s_%s".printf (get_ccode_lower_case_name (cl
), get_ccode_lower_case_name (sig
));
566 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (emitter_func
));
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 (get_signal_canonical_constant (sig
));
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 var cexpr
= connect_signal (sig
, signal_access
, handler
, disconnect
, after
, expr
);
600 set_cvalue (expr
, cexpr
);
603 CCodeExpression?
connect_signal (Signal sig
, Expression signal_access
, Expression handler
, bool disconnect
, bool after
, CodeNode expr
) {
606 DelegateType? dt
= null;
607 var p
= handler
.symbol_reference as Parameter
;
609 dt
= p
.variable_type as DelegateType
;
610 if (dt
!= null && !context
.experimental
) {
611 Report
.warning (dt
.source_reference
, "Connecting delegates to signals is experimental");
614 var m
= handler
.symbol_reference as Method
;
618 if (sig is DynamicSignal
) {
620 connect_func
= get_dynamic_signal_connect_wrapper_name ((DynamicSignal
) sig
);
622 connect_func
= get_dynamic_signal_connect_after_wrapper_name ((DynamicSignal
) sig
);
624 if ((m
!= null && m
.closure
) || (dt
!= null && dt
.value_owned
)) {
625 connect_func
= "g_signal_connect_data";
626 } else if (m
!= null && in_gobject_instance (m
)) {
627 connect_func
= "g_signal_connect_object";
629 connect_func
= "g_signal_connect";
631 connect_func
= "g_signal_connect_after";
635 if (handler is LambdaExpression
) {
636 Report
.error (handler
.source_reference
, "Cannot disconnect lambda expression from signal. Use Object.disconnect.");
638 if (sig is DynamicSignal
) {
639 connect_func
= get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal
) sig
);
641 connect_func
= "g_signal_handlers_disconnect_matched";
645 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (connect_func
));
647 CCodeExpression signal_name_cexpr
= null;
649 // first argument: instance of sender
651 if (signal_access is ElementAccess
) {
652 var ea
= (ElementAccess
) signal_access
;
653 ma
= (MemberAccess
) ea
.container
;
654 var detail_expr
= ea
.get_indices ().get (0);
655 signal_name_cexpr
= get_signal_name_cexpression (sig
, detail_expr
, expr
);
656 if (signal_name_cexpr
== null) {
660 ma
= (MemberAccess
) signal_access
;
661 signal_name_cexpr
= get_signal_name_cexpression (sig
, null, expr
);
663 if (ma
.inner
!= null) {
664 ccall
.add_argument ((CCodeExpression
) get_ccodenode (ma
.inner
));
666 ccall
.add_argument (get_result_cexpression ("self"));
669 if (sig is DynamicSignal
) {
670 // dynamic_signal_connect or dynamic_signal_disconnect
672 // second argument: signal name
673 ccall
.add_argument (new
CCodeConstant ("\"%s\"".printf (get_ccode_name (sig
))));
674 } else if (!disconnect
) {
675 // g_signal_connect_object or g_signal_connect
677 // second argument: signal name
678 ccall
.add_argument (signal_name_cexpr
);
680 // g_signal_handlers_disconnect_matched
682 // second argument: mask
683 if (!(signal_access is ElementAccess
)) {
684 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
686 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
690 var temp_decl
= get_temp_variable (uint_type
);
691 emit_temp_var (temp_decl
);
692 var parse_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_parse_name"));
693 parse_call
.add_argument (signal_name_cexpr
);
694 var decl_type
= (TypeSymbol
) sig
.parent_symbol
;
695 parse_call
.add_argument (new
CCodeIdentifier (get_ccode_type_id (decl_type
)));
696 parse_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_decl
.name
)));
697 LocalVariable? detail_temp_decl
= null;
698 if (!(signal_access is ElementAccess
)) {
699 parse_call
.add_argument (new
CCodeConstant ("NULL"));
700 parse_call
.add_argument (new
CCodeConstant ("FALSE"));
702 detail_temp_decl
= get_temp_variable (gquark_type
);
703 emit_temp_var (detail_temp_decl
);
704 parse_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (detail_temp_decl
.name
)));
705 parse_call
.add_argument (new
CCodeConstant ("TRUE"));
707 ccode
.add_expression (parse_call
);
709 // third argument: signal_id
710 ccall
.add_argument (get_variable_cexpression (temp_decl
.name
));
712 // fourth argument: detail
713 if (detail_temp_decl
== null) {
714 ccall
.add_argument (new
CCodeConstant ("0"));
716 ccall
.add_argument (get_variable_cexpression (detail_temp_decl
.name
));
718 // fifth argument: closure
719 ccall
.add_argument (new
CCodeConstant ("NULL"));
722 // third resp. sixth argument: handler
723 ccall
.add_argument (new
CCodeCastExpression (get_cvalue (handler
), "GCallback"));
725 if (m
!= null && m
.closure
) {
726 // g_signal_connect_data
728 // fourth argument: user_data
729 CCodeExpression handler_destroy_notify
;
730 ccall
.add_argument (get_delegate_target_cexpression (handler
, out handler_destroy_notify
));
732 // fifth argument: destroy_notify
733 ccall
.add_argument (new
CCodeCastExpression (handler_destroy_notify
, "GClosureNotify"));
735 // sixth argument: connect_flags
737 ccall
.add_argument (new
CCodeConstant ("0"));
739 ccall
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
740 } else if (m
!= null && m
.binding
== MemberBinding
.INSTANCE
) {
741 // g_signal_connect_object or g_signal_handlers_disconnect_matched
742 // or dynamic_signal_connect or dynamic_signal_disconnect
744 // fourth resp. seventh argument: object/user_data
745 if (handler is MemberAccess
) {
746 var right_ma
= (MemberAccess
) handler
;
747 if (right_ma
.inner
!= null) {
748 ccall
.add_argument (get_cvalue (right_ma
.inner
));
750 ccall
.add_argument (get_result_cexpression ("self"));
752 } else if (handler is LambdaExpression
) {
753 ccall
.add_argument (get_result_cexpression ("self"));
755 if (!disconnect
&& !(sig is DynamicSignal
)
756 && in_gobject_instance (m
)) {
757 // g_signal_connect_object
759 // fifth argument: connect_flags
761 ccall
.add_argument (new
CCodeConstant ("0"));
763 ccall
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
765 } else if (dt
!= null && dt
.delegate_symbol
.has_target
) {
766 // fourth argument: user_data
767 CCodeExpression handler_destroy_notify
;
768 ccall
.add_argument (get_delegate_target_cexpression (handler
, out handler_destroy_notify
));
769 if (!disconnect
&& dt
.value_owned
) {
770 // fifth argument: destroy_notify
771 //FIXME handler_destroy_notify is NULL
772 ccall
.add_argument (new
CCodeCastExpression (handler_destroy_notify
, "GClosureNotify"));
773 // sixth argument: connect_flags
775 ccall
.add_argument (new
CCodeConstant ("0"));
777 ccall
.add_argument (new
CCodeConstant ("G_CONNECT_AFTER"));
780 // g_signal_connect or g_signal_connect_after or g_signal_handlers_disconnect_matched
781 // or dynamic_signal_connect or dynamic_signal_disconnect
783 // fourth resp. seventh argument: user_data
784 ccall
.add_argument (new
CCodeConstant ("NULL"));
787 if (disconnect
|| expr
.parent_node is ExpressionStatement
) {
788 ccode
.add_expression (ccall
);
791 var temp_var
= get_temp_variable (ulong_type
);
792 var temp_ref
= get_variable_cexpression (temp_var
.name
);
794 emit_temp_var (temp_var
);
796 ccode
.add_assignment (temp_ref
, ccall
);