1 /* valagsignalmodule.vala
3 * Copyright (C) 2006-2009 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>
27 internal class Vala
.GSignalModule
: GObjectModule
{
28 public GSignalModule (CCodeGenerator codegen
, CCodeModule? next
) {
32 private string get_marshaller_type_name (DataType t
, bool dbus
= false) {
33 if (t is PointerType
|| t
.type_parameter
!= null) {
35 } else if (t is ErrorType
) {
37 } else if (t is ArrayType
) {
41 if (((ArrayType
) t
).element_type
.data_type
== string_type
.data_type
) {
44 return ("POINTER_INT");
47 } else if (t is VoidType
) {
49 } else if (dbus
&& DBusModule
.get_type_signature (t
).has_prefix ("(")) {
51 } else if (t
.data_type is Enum
) {
52 var en
= (Enum
) t
.data_type
;
60 return en
.get_marshaller_type_name ();
63 return t
.data_type
.get_marshaller_type_name ();
67 private string get_marshaller_type_name_for_parameter (FormalParameter param
, bool dbus
= false) {
68 if (param
.direction
!= ParameterDirection
.IN
) {
71 return get_marshaller_type_name (param
.parameter_type
, dbus
);
75 public override string get_marshaller_function (Gee
.List
<FormalParameter
> params
, DataType return_type
, string? prefix
= null, bool dbus
= false) {
76 var signature
= get_marshaller_signature (params
, return_type
, dbus
);
80 if (predefined_marshal_set
.contains (signature
)) {
81 prefix
= "g_cclosure_marshal";
83 prefix
= "g_cclosure_user_marshal";
87 ret
= "%s_%s_".printf (prefix
, get_marshaller_type_name (return_type
, dbus
));
89 if (params
== null || params
.size
== 0) {
92 foreach (FormalParameter p
in params
) {
93 ret
= "%s_%s".printf (ret
, get_marshaller_type_name_for_parameter (p
, dbus
));
100 private string?
get_value_type_name_from_type_reference (DataType t
) {
101 if (t is PointerType
|| t
.type_parameter
!= null) {
103 } else if (t is VoidType
) {
105 } else if (t
.data_type
== string_type
.data_type
) {
106 return "const char*";
107 } else if (t
.data_type is Class
|| t
.data_type is Interface
) {
109 } else if (t
.data_type is Struct
) {
110 var st
= (Struct
) t
.data_type
;
111 if (st
.is_simple_type ()) {
112 return t
.data_type
.get_cname ();
116 } else if (t
.data_type is Enum
) {
118 } else if (t is ArrayType
) {
120 } else if (t is ErrorType
) {
127 private string?
get_value_type_name_from_parameter (FormalParameter p
) {
128 if (p
.direction
!= ParameterDirection
.IN
) {
131 return get_value_type_name_from_type_reference (p
.parameter_type
);
135 private string get_marshaller_signature (Gee
.List
<FormalParameter
> params
, DataType return_type
, bool dbus
= false) {
138 signature
= "%s:".printf (get_marshaller_type_name (return_type
, dbus
));
139 if (params
== null || params
.size
== 0) {
140 signature
= signature
+ "VOID";
143 foreach (FormalParameter p
in params
) {
145 signature
= signature
+ get_marshaller_type_name_for_parameter (p
, dbus
);
148 signature
= "%s,%s".printf (signature
, get_marshaller_type_name_for_parameter (p
, dbus
));
156 public override void visit_signal (Signal sig
) {
157 // parent_symbol may be null for dynamic signals
159 var cl
= sig
.parent_symbol as Class
;
160 if (cl
!= null && cl
.is_compact
) {
162 Report
.error (sig
.source_reference
, "Signals are not supported in compact classes");
166 sig
.accept_children (codegen
);
168 // declare parameter type
169 foreach (FormalParameter p
in sig
.get_parameters ()) {
170 generate_parameter (p
, source_declarations
, new HashMap
<int,CCodeFormalParameter
> (), null);
173 generate_marshaller (sig
.get_parameters (), sig
.return_type
);
176 public override void generate_marshaller (Gee
.List
<FormalParameter
> params
, DataType return_type
, bool dbus
= false) {
180 /* check whether a signal with the same signature already exists for this source file (or predefined) */
181 signature
= get_marshaller_signature (params
, return_type
, dbus
);
182 if (predefined_marshal_set
.contains (signature
) || user_marshal_set
.contains (signature
)) {
186 var signal_marshaller
= new
CCodeFunction (get_marshaller_function (params
, return_type
, null, dbus
), "void");
187 signal_marshaller
.modifiers
= CCodeModifiers
.STATIC
;
189 signal_marshaller
.add_parameter (new
CCodeFormalParameter ("closure", "GClosure *"));
190 signal_marshaller
.add_parameter (new
CCodeFormalParameter ("return_value", "GValue *"));
191 signal_marshaller
.add_parameter (new
CCodeFormalParameter ("n_param_values", "guint"));
192 signal_marshaller
.add_parameter (new
CCodeFormalParameter ("param_values", "const GValue *"));
193 signal_marshaller
.add_parameter (new
CCodeFormalParameter ("invocation_hint", "gpointer"));
194 signal_marshaller
.add_parameter (new
CCodeFormalParameter ("marshal_data", "gpointer"));
196 source_signal_marshaller_declaration
.append (signal_marshaller
.copy ());
198 var marshaller_body
= new
CCodeBlock ();
200 var callback_decl
= new
CCodeFunctionDeclarator (get_marshaller_function (params
, return_type
, "GMarshalFunc", dbus
));
201 callback_decl
.add_parameter (new
CCodeFormalParameter ("data1", "gpointer"));
203 foreach (FormalParameter p
in params
) {
204 callback_decl
.add_parameter (new
CCodeFormalParameter ("arg_%d".printf (n_params
), get_value_type_name_from_parameter (p
)));
206 if (p
.parameter_type
.is_array () && !dbus
) {
207 callback_decl
.add_parameter (new
CCodeFormalParameter ("arg_%d".printf (n_params
), "gint"));
211 callback_decl
.add_parameter (new
CCodeFormalParameter ("data2", "gpointer"));
212 marshaller_body
.add_statement (new
CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type
), callback_decl
));
214 var var_decl
= new
CCodeDeclaration (get_marshaller_function (params
, return_type
, "GMarshalFunc", dbus
));
215 var_decl
.modifiers
= CCodeModifiers
.REGISTER
;
216 var_decl
.add_declarator (new
CCodeVariableDeclarator ("callback"));
217 marshaller_body
.add_statement (var_decl
);
219 var_decl
= new
CCodeDeclaration ("GCClosure *");
220 var_decl
.modifiers
= CCodeModifiers
.REGISTER
;
221 var_decl
.add_declarator (new
CCodeVariableDeclarator ("cc", new
CCodeCastExpression (new
CCodeIdentifier ("closure"), "GCClosure *")));
222 marshaller_body
.add_statement (var_decl
);
224 var_decl
= new
CCodeDeclaration ("gpointer");
225 var_decl
.modifiers
= CCodeModifiers
.REGISTER
;
226 var_decl
.add_declarator (new
CCodeVariableDeclarator ("data1"));
227 var_decl
.add_declarator (new
CCodeVariableDeclarator ("data2"));
228 marshaller_body
.add_statement (var_decl
);
230 CCodeFunctionCall fc
;
232 if (return_type
.data_type
!= null || return_type
.is_array ()) {
233 var_decl
= new
CCodeDeclaration (get_value_type_name_from_type_reference (return_type
));
234 var_decl
.add_declarator (new
CCodeVariableDeclarator ("v_return"));
235 marshaller_body
.add_statement (var_decl
);
237 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_return_if_fail"));
238 fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.INEQUALITY
, new
CCodeIdentifier ("return_value"), new
CCodeConstant ("NULL")));
239 marshaller_body
.add_statement (new
CCodeExpressionStatement (fc
));
242 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_return_if_fail"));
243 fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.EQUALITY
, new
CCodeIdentifier ("n_param_values"), new
CCodeConstant (n_params
.to_string())));
244 marshaller_body
.add_statement (new
CCodeExpressionStatement (fc
));
246 var data
= new
CCodeMemberAccess (new
CCodeIdentifier ("closure"), "data", true);
247 var param
= new
CCodeMemberAccess (new
CCodeMemberAccess (new
CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
248 var cond
= new
CCodeFunctionCall (new
CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
249 cond
.add_argument (new
CCodeIdentifier ("closure"));
250 var true_block
= new
CCodeBlock ();
251 true_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data1"), data
)));
252 true_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data2"), param
)));
253 var false_block
= new
CCodeBlock ();
254 false_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data1"), param
)));
255 false_block
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("data2"), data
)));
256 marshaller_body
.add_statement (new
CCodeIfStatement (cond
, true_block
, false_block
));
258 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
)));
259 marshaller_body
.add_statement (new
CCodeExpressionStatement (c_assign
));
261 fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("callback"));
262 fc
.add_argument (new
CCodeIdentifier ("data1"));
264 foreach (FormalParameter p
in params
) {
265 string get_value_function
;
266 bool is_array
= p
.parameter_type
.is_array ();
267 if (p
.direction
!= ParameterDirection
.IN
) {
268 get_value_function
= "g_value_get_pointer";
269 } else if (is_array
) {
271 get_value_function
= "g_value_get_boxed";
273 if (((ArrayType
) p
.parameter_type
).element_type
.data_type
== string_type
.data_type
) {
274 get_value_function
= "g_value_get_boxed";
276 get_value_function
= "g_value_get_pointer";
279 } else if (p
.parameter_type is PointerType
|| p
.parameter_type
.type_parameter
!= null) {
280 get_value_function
= "g_value_get_pointer";
281 } else if (p
.parameter_type is ErrorType
) {
282 get_value_function
= "g_value_get_pointer";
283 } else if (dbus
&& DBusModule
.get_type_signature (p
.parameter_type
).has_prefix ("(")) {
284 get_value_function
= "g_value_get_boxed";
285 } else if (dbus
&& p
.parameter_type
.data_type is Enum
) {
286 var en
= (Enum
) p
.parameter_type
.data_type
;
288 get_value_function
= "g_value_get_uint";
290 get_value_function
= "g_value_get_int";
293 get_value_function
= p
.parameter_type
.data_type
.get_get_value_function ();
295 var inner_fc
= new
CCodeFunctionCall (new
CCodeIdentifier (get_value_function
));
296 inner_fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("param_values"), new
CCodeIdentifier (i
.to_string ())));
297 fc
.add_argument (inner_fc
);
299 if (is_array
&& !dbus
) {
300 inner_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_get_int"));
301 inner_fc
.add_argument (new
CCodeBinaryExpression (CCodeBinaryOperator
.PLUS
, new
CCodeIdentifier ("param_values"), new
CCodeIdentifier (i
.to_string ())));
302 fc
.add_argument (inner_fc
);
306 fc
.add_argument (new
CCodeIdentifier ("data2"));
308 if (return_type
.data_type
!= null || return_type
.is_array ()) {
309 marshaller_body
.add_statement (new
CCodeExpressionStatement (new
CCodeAssignment (new
CCodeIdentifier ("v_return"), fc
)));
311 CCodeFunctionCall set_fc
;
312 if (return_type
.is_array ()) {
314 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
316 if (((ArrayType
) return_type
).element_type
.data_type
== string_type
.data_type
) {
317 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
319 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
322 } else if (return_type
.type_parameter
!= null) {
323 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
324 } else if (return_type is ErrorType
) {
325 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_pointer"));
326 } else if (return_type
.data_type
== string_type
.data_type
) {
327 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_string"));
328 } else if (return_type
.data_type is Class
|| return_type
.data_type is Interface
) {
329 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_object"));
330 } else if (dbus
&& DBusModule
.get_type_signature (return_type
).has_prefix ("(")) {
331 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_take_boxed"));
332 } else if (dbus
&& return_type
.data_type is Enum
) {
333 var en
= (Enum
) return_type
.data_type
;
335 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_uint"));
337 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_value_set_int"));
340 set_fc
= new
CCodeFunctionCall (new
CCodeIdentifier (return_type
.data_type
.get_set_value_function ()));
342 set_fc
.add_argument (new
CCodeIdentifier ("return_value"));
343 set_fc
.add_argument (new
CCodeIdentifier ("v_return"));
345 marshaller_body
.add_statement (new
CCodeExpressionStatement (set_fc
));
347 marshaller_body
.add_statement (new
CCodeExpressionStatement (fc
));
350 signal_marshaller
.block
= marshaller_body
;
352 source_signal_marshaller_definition
.append (signal_marshaller
);
353 user_marshal_set
.add (signature
);
356 public override CCodeFunctionCall
get_signal_creation (Signal sig
, TypeSymbol type
) {
357 var csignew
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_new"));
358 var cl
= sig
.parent_symbol as Class
;
359 csignew
.add_argument (new
CCodeConstant ("\"%s\"".printf (sig
.get_cname ())));
360 csignew
.add_argument (new
CCodeIdentifier (type
.get_type_id ()));
361 csignew
.add_argument (new
CCodeConstant ("G_SIGNAL_RUN_LAST"));
362 if (sig
.default_handler
== null) {
363 csignew
.add_argument (new
CCodeConstant ("0"));
365 var struct_offset
= new
CCodeFunctionCall (new
CCodeIdentifier ("G_STRUCT_OFFSET"));
366 struct_offset
.add_argument (new
CCodeIdentifier ("%sClass".printf (cl
.get_cname ())));
367 struct_offset
.add_argument (new
CCodeIdentifier (sig
.default_handler
.vfunc_name
));
368 csignew
.add_argument (struct_offset
);
370 csignew
.add_argument (new
CCodeConstant ("NULL"));
371 csignew
.add_argument (new
CCodeConstant ("NULL"));
373 string marshaller
= head
.get_marshaller_function (sig
.get_parameters (), sig
.return_type
);
375 var marshal_arg
= new
CCodeIdentifier (marshaller
);
376 csignew
.add_argument (marshal_arg
);
378 var params
= sig
.get_parameters ();
379 if (sig
.return_type is PointerType
|| sig
.return_type
.type_parameter
!= null) {
380 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
381 } else if (sig
.return_type is ErrorType
) {
382 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
383 } else if (sig
.return_type
.data_type
== null) {
384 csignew
.add_argument (new
CCodeConstant ("G_TYPE_NONE"));
386 csignew
.add_argument (new
CCodeConstant (sig
.return_type
.data_type
.get_type_id ()));
390 foreach (FormalParameter param
in params
) {
392 if (param
.parameter_type
.is_array ()) {
397 csignew
.add_argument (new
CCodeConstant ("%d".printf (params_len
)));
398 foreach (FormalParameter param
in params
) {
399 if (param
.parameter_type
.is_array ()) {
400 if (((ArrayType
) param
.parameter_type
).element_type
.data_type
== string_type
.data_type
) {
401 csignew
.add_argument (new
CCodeConstant ("G_TYPE_STRV"));
403 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
405 csignew
.add_argument (new
CCodeConstant ("G_TYPE_INT"));
406 } else if (param
.parameter_type is PointerType
|| param
.parameter_type
.type_parameter
!= null || param
.direction
!= ParameterDirection
.IN
) {
407 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
408 } else if (param
.parameter_type is ErrorType
) {
409 csignew
.add_argument (new
CCodeConstant ("G_TYPE_POINTER"));
411 csignew
.add_argument (new
CCodeConstant (param
.parameter_type
.data_type
.get_type_id ()));
415 marshal_arg
.name
= marshaller
;
420 public virtual CCodeExpression
get_dbus_g_type (DataType data_type
) {
421 return new
CCodeConstant (data_type
.data_type
.get_type_id ());
424 public override void visit_element_access (ElementAccess expr
) {
425 if (expr
.container is MemberAccess
&& expr
.container
.symbol_reference is Signal
) {
426 // detailed signal emission
427 var sig
= (Signal
) expr
.symbol_reference
;
428 var ma
= (MemberAccess
) expr
.container
;
429 expr
.accept_children (codegen
);
431 var detail_expr
= expr
.get_indices ().get (0) as StringLiteral
;
432 string signal_detail
= detail_expr
.eval ();
434 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_emit_by_name"));
435 ccall
.add_argument ((CCodeExpression
) ma
.inner
.ccodenode
);
436 ccall
.add_argument (sig
.get_canonical_cconstant (signal_detail
));
438 expr
.ccodenode
= ccall
;
440 base.visit_element_access (expr
);
444 bool in_gobject_instance (Method m
) {
446 if (m
.binding
== MemberBinding
.INSTANCE
) {
447 result
= m
.this_parameter
.parameter_type
.data_type
.is_subtype_of (gobject_type
);
452 CCodeExpression?
emit_signal_assignment (Assignment assignment
) {
453 var sig
= (Signal
) assignment
.left
.symbol_reference
;
455 var m
= (Method
) assignment
.right
.symbol_reference
;
458 bool disconnect
= false;
460 if (assignment
.operator
== AssignmentOperator
.ADD
) {
461 if (sig is DynamicSignal
) {
462 connect_func
= head
.get_dynamic_signal_connect_wrapper_name ((DynamicSignal
) sig
);
464 if (in_gobject_instance (m
)) {
465 connect_func
= "g_signal_connect_object";
467 connect_func
= "g_signal_connect";
470 } else if (assignment
.operator
== AssignmentOperator
.SUB
) {
471 if (sig is DynamicSignal
) {
472 connect_func
= head
.get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal
) sig
);
474 connect_func
= "g_signal_handlers_disconnect_matched";
478 assignment
.error
= true;
479 Report
.error (assignment
.source_reference
, "Specified compound assignment type for signals not supported.");
483 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (connect_func
));
485 string signal_detail
= null;
487 // first argument: instance of sender
489 if (assignment
.left is ElementAccess
) {
490 var ea
= (ElementAccess
) assignment
.left
;
491 ma
= (MemberAccess
) ea
.container
;
492 var detail_expr
= ea
.get_indices ().get (0) as StringLiteral
;
493 if (detail_expr
== null) {
494 assignment
.error
= true;
495 Report
.error (detail_expr
.source_reference
, "internal error: only literal string details supported");
498 signal_detail
= detail_expr
.eval ();
500 ma
= (MemberAccess
) assignment
.left
;
502 if (ma
.inner
!= null) {
503 ccall
.add_argument ((CCodeExpression
) get_ccodenode (ma
.inner
));
505 ccall
.add_argument (new
CCodeIdentifier ("self"));
508 if (sig is DynamicSignal
) {
509 // dynamic_signal_connect or dynamic_signal_disconnect
511 // second argument: signal name
512 ccall
.add_argument (new
CCodeConstant ("\"%s\"".printf (sig
.name
)));
513 } else if (!disconnect
) {
514 // g_signal_connect_object or g_signal_connect
516 // second argument: signal name
517 ccall
.add_argument (sig
.get_canonical_cconstant (signal_detail
));
519 // g_signal_handlers_disconnect_matched
521 // second argument: mask
522 if (signal_detail
== null) {
523 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
525 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
529 var ccomma
= new
CCodeCommaExpression ();
530 var temp_decl
= get_temp_variable (uint_type
);
531 temp_vars
.insert (0, temp_decl
);
532 var parse_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_parse_name"));
533 parse_call
.add_argument (sig
.get_canonical_cconstant (signal_detail
));
534 var decl_type
= (TypeSymbol
) sig
.parent_symbol
;
535 parse_call
.add_argument (new
CCodeIdentifier (decl_type
.get_type_id ()));
536 parse_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_decl
.name
)));
537 if (signal_detail
== null) {
538 parse_call
.add_argument (new
CCodeConstant ("NULL"));
540 var detail_temp_decl
= get_temp_variable (gquark_type
);
541 temp_vars
.insert (0, detail_temp_decl
);
542 parse_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (detail_temp_decl
.name
)));
544 parse_call
.add_argument (new
CCodeConstant ("FALSE"));
545 ccomma
.append_expression (parse_call
);
546 ccomma
.append_expression (get_variable_cexpression (temp_decl
.name
));
548 // third argument: signal_id
549 ccall
.add_argument (ccomma
);
551 // fourth argument: detail
552 ccall
.add_argument (new
CCodeConstant ("0"));
553 // fifth argument: closure
554 ccall
.add_argument (new
CCodeConstant ("NULL"));
557 // third resp. sixth argument: handler
558 ccall
.add_argument (new
CCodeCastExpression ((CCodeExpression
) assignment
.right
.ccodenode
, "GCallback"));
560 if (m
.binding
== MemberBinding
.INSTANCE
) {
561 // g_signal_connect_object or g_signal_handlers_disconnect_matched
562 // or dynamic_signal_connect or dynamic_signal_disconnect
564 // fourth resp. seventh argument: object/user_data
565 if (assignment
.right is MemberAccess
) {
566 var right_ma
= (MemberAccess
) assignment
.right
;
567 if (right_ma
.inner
!= null) {
568 ccall
.add_argument ((CCodeExpression
) right_ma
.inner
.ccodenode
);
570 ccall
.add_argument (new
CCodeIdentifier ("self"));
572 } else if (assignment
.right is LambdaExpression
) {
573 ccall
.add_argument (new
CCodeIdentifier ("self"));
575 if (!disconnect
&& !(sig is DynamicSignal
)
576 && in_gobject_instance (m
)) {
577 // g_signal_connect_object
579 // fifth argument: connect_flags
580 ccall
.add_argument (new
CCodeConstant ("0"));
583 // g_signal_connect or g_signal_handlers_disconnect_matched
584 // or dynamic_signal_connect or dynamic_signal_disconnect
586 // fourth resp. seventh argument: user_data
587 ccall
.add_argument (new
CCodeConstant ("NULL"));
593 public override void visit_assignment (Assignment assignment
) {
594 if (assignment
.left
.symbol_reference is Signal
) {
595 assignment
.right
.accept (codegen
);
597 if (assignment
.left
.error
|| assignment
.right
.error
) {
598 assignment
.error
= true;
602 assignment
.ccodenode
= emit_signal_assignment (assignment
);
604 base.visit_assignment (assignment
);
608 public override void visit_member_access (MemberAccess expr
) {
609 if (expr
.symbol_reference is Signal
) {
610 expr
.accept_children (codegen
);
612 CCodeExpression pub_inst
= null;
614 if (expr
.inner
!= null) {
615 pub_inst
= (CCodeExpression
) expr
.inner
.ccodenode
;
618 var sig
= (Signal
) expr
.symbol_reference
;
619 var cl
= (TypeSymbol
) sig
.parent_symbol
;
621 if (expr
.inner is BaseAccess
&& sig
.is_virtual
) {
622 var m
= sig
.default_handler
;
623 var base_class
= (Class
) m
.parent_symbol
;
624 var vcast
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_CLASS".printf (base_class
.get_upper_case_cname (null))));
625 vcast
.add_argument (new
CCodeIdentifier ("%s_parent_class".printf (current_class
.get_lower_case_cname (null))));
627 expr
.ccodenode
= new CCodeMemberAccess
.pointer (vcast
, m
.name
);
631 if (sig
.has_emitter
) {
632 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("%s_%s".printf (cl
.get_lower_case_cname (null), sig
.name
)));
634 ccall
.add_argument (pub_inst
);
635 expr
.ccodenode
= ccall
;
637 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_emit_by_name"));
638 ccall
.add_argument (pub_inst
);
640 ccall
.add_argument (sig
.get_canonical_cconstant ());
642 expr
.ccodenode
= ccall
;
645 base.visit_member_access (expr
);
649 public override void visit_method_call (MethodCall expr
) {
650 var method_type
= expr
.call
.value_type as MethodType
;
652 if (method_type
== null || !(method_type
.method_symbol
.parent_symbol is Signal
)) {
653 // no signal connect/disconnect call
654 base.visit_method_call (expr
);
658 var sig
= (Signal
) method_type
.method_symbol
.parent_symbol
;
659 var signal_access
= ((MemberAccess
) expr
.call
).inner
;
660 var handler
= expr
.get_argument_list ().get (0);
662 signal_access
.accept (codegen
);
663 handler
.accept (codegen
);
665 var m
= (Method
) handler
.symbol_reference
;
668 bool disconnect
= (method_type
.method_symbol
.name
== "disconnect");
672 if (sig is DynamicSignal
) {
673 connect_func
= head
.get_dynamic_signal_connect_wrapper_name ((DynamicSignal
) sig
);
675 if (in_gobject_instance (m
)) {
676 connect_func
= "g_signal_connect_object";
678 connect_func
= "g_signal_connect";
683 if (sig is DynamicSignal
) {
684 connect_func
= head
.get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal
) sig
);
686 connect_func
= "g_signal_handlers_disconnect_matched";
690 var ccall
= new
CCodeFunctionCall (new
CCodeIdentifier (connect_func
));
692 string signal_detail
= null;
694 // first argument: instance of sender
696 if (signal_access is ElementAccess
) {
697 var ea
= (ElementAccess
) signal_access
;
698 ma
= (MemberAccess
) ea
.container
;
699 var detail_expr
= ea
.get_indices ().get (0) as StringLiteral
;
700 if (detail_expr
== null) {
702 Report
.error (detail_expr
.source_reference
, "internal error: only literal string details supported");
705 signal_detail
= detail_expr
.eval ();
707 ma
= (MemberAccess
) signal_access
;
709 if (ma
.inner
!= null) {
710 ccall
.add_argument ((CCodeExpression
) get_ccodenode (ma
.inner
));
712 ccall
.add_argument (new
CCodeIdentifier ("self"));
715 if (sig is DynamicSignal
) {
716 // dynamic_signal_connect or dynamic_signal_disconnect
718 // second argument: signal name
719 ccall
.add_argument (new
CCodeConstant ("\"%s\"".printf (sig
.name
)));
720 } else if (!disconnect
) {
721 // g_signal_connect_object or g_signal_connect
723 // second argument: signal name
724 ccall
.add_argument (sig
.get_canonical_cconstant (signal_detail
));
726 // g_signal_handlers_disconnect_matched
728 // second argument: mask
729 if (signal_detail
== null) {
730 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
732 ccall
.add_argument (new
CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
736 var ccomma
= new
CCodeCommaExpression ();
737 var temp_decl
= get_temp_variable (uint_type
);
738 temp_vars
.insert (0, temp_decl
);
739 var parse_call
= new
CCodeFunctionCall (new
CCodeIdentifier ("g_signal_parse_name"));
740 parse_call
.add_argument (sig
.get_canonical_cconstant (signal_detail
));
741 var decl_type
= (TypeSymbol
) sig
.parent_symbol
;
742 parse_call
.add_argument (new
CCodeIdentifier (decl_type
.get_type_id ()));
743 parse_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, get_variable_cexpression (temp_decl
.name
)));
744 if (signal_detail
== null) {
745 parse_call
.add_argument (new
CCodeConstant ("NULL"));
747 var detail_temp_decl
= get_temp_variable (gquark_type
);
748 temp_vars
.insert (0, detail_temp_decl
);
749 parse_call
.add_argument (new
CCodeUnaryExpression (CCodeUnaryOperator
.ADDRESS_OF
, new
CCodeIdentifier (detail_temp_decl
.name
)));
751 parse_call
.add_argument (new
CCodeConstant ("FALSE"));
752 ccomma
.append_expression (parse_call
);
753 ccomma
.append_expression (get_variable_cexpression (temp_decl
.name
));
755 // third argument: signal_id
756 ccall
.add_argument (ccomma
);
758 // fourth argument: detail
759 ccall
.add_argument (new
CCodeConstant ("0"));
760 // fifth argument: closure
761 ccall
.add_argument (new
CCodeConstant ("NULL"));
764 // third resp. sixth argument: handler
765 ccall
.add_argument (new
CCodeCastExpression ((CCodeExpression
) handler
.ccodenode
, "GCallback"));
767 if (m
.binding
== MemberBinding
.INSTANCE
) {
768 // g_signal_connect_object or g_signal_handlers_disconnect_matched
769 // or dynamic_signal_connect or dynamic_signal_disconnect
771 // fourth resp. seventh argument: object/user_data
772 if (handler is MemberAccess
) {
773 var right_ma
= (MemberAccess
) handler
;
774 if (right_ma
.inner
!= null) {
775 ccall
.add_argument ((CCodeExpression
) right_ma
.inner
.ccodenode
);
777 ccall
.add_argument (new
CCodeIdentifier ("self"));
779 } else if (handler is LambdaExpression
) {
780 ccall
.add_argument (new
CCodeIdentifier ("self"));
782 if (!disconnect
&& !(sig is DynamicSignal
)
783 && in_gobject_instance (m
)) {
784 // g_signal_connect_object
786 // fifth argument: connect_flags
787 ccall
.add_argument (new
CCodeConstant ("0"));
790 // g_signal_connect or g_signal_handlers_disconnect_matched
791 // or dynamic_signal_connect or dynamic_signal_disconnect
793 // fourth resp. seventh argument: user_data
794 ccall
.add_argument (new
CCodeConstant ("NULL"));
797 expr
.ccodenode
= ccall
;