Release 0.6.0
[vala-lang.git] / gobject / valagsignalmodule.vala
blobc073a24995cdec7043e5898b6af34199bc4ccdb3
1 /* valagsignalmodule.vala
3 * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <raffaele@sandrini.ch>
24 using GLib;
26 internal class Vala.GSignalModule : GObjectModule {
27 public GSignalModule (CCodeGenerator codegen, CCodeModule? next) {
28 base (codegen, next);
31 private string get_marshaller_type_name (DataType t, bool dbus = false) {
32 if (t is PointerType || t.type_parameter != null) {
33 return ("POINTER");
34 } else if (t is ErrorType) {
35 return ("POINTER");
36 } else if (t is ArrayType) {
37 if (dbus) {
38 return ("BOXED");
39 } else {
40 if (((ArrayType) t).element_type.data_type == string_type.data_type) {
41 return ("BOXED_INT");
42 } else {
43 return ("POINTER_INT");
46 } else if (t is VoidType) {
47 return ("VOID");
48 } else if (dbus && t.get_type_signature ().has_prefix ("(")) {
49 return ("BOXED");
50 } else if (t.data_type is Enum) {
51 var en = (Enum) t.data_type;
52 if (dbus) {
53 if (en.is_flags) {
54 return ("UINT");
55 } else {
56 return ("INT");
58 } else {
59 return en.get_marshaller_type_name ();
61 } else {
62 return t.data_type.get_marshaller_type_name ();
66 private string get_marshaller_type_name_for_parameter (FormalParameter param, bool dbus = false) {
67 if (param.direction != ParameterDirection.IN) {
68 return ("POINTER");
69 } else {
70 return get_marshaller_type_name (param.parameter_type, dbus);
74 public override string get_marshaller_function (Gee.List<FormalParameter> params, DataType return_type, string? prefix = null, bool dbus = false) {
75 var signature = get_marshaller_signature (params, return_type, dbus);
76 string ret;
78 if (prefix == null) {
79 if (predefined_marshal_set.contains (signature)) {
80 prefix = "g_cclosure_marshal";
81 } else {
82 prefix = "g_cclosure_user_marshal";
86 ret = "%s_%s_".printf (prefix, get_marshaller_type_name (return_type, dbus));
88 if (params == null || params.size == 0) {
89 ret = ret + "_VOID";
90 } else {
91 foreach (FormalParameter p in params) {
92 ret = "%s_%s".printf (ret, get_marshaller_type_name_for_parameter (p, dbus));
96 return ret;
99 private string? get_value_type_name_from_type_reference (DataType t) {
100 if (t is PointerType || t.type_parameter != null) {
101 return "gpointer";
102 } else if (t is VoidType) {
103 return "void";
104 } else if (t.data_type == string_type.data_type) {
105 return "const char*";
106 } else if (t.data_type is Class || t.data_type is Interface) {
107 return "gpointer";
108 } else if (t.data_type is Struct) {
109 var st = (Struct) t.data_type;
110 if (st.is_simple_type ()) {
111 return t.data_type.get_cname ();
112 } else {
113 return "gpointer";
115 } else if (t.data_type is Enum) {
116 return "gint";
117 } else if (t is ArrayType) {
118 return "gpointer";
119 } else if (t is ErrorType) {
120 return "gpointer";
123 return null;
126 private string? get_value_type_name_from_parameter (FormalParameter p) {
127 if (p.direction != ParameterDirection.IN) {
128 return "gpointer";
129 } else {
130 return get_value_type_name_from_type_reference (p.parameter_type);
134 private string get_marshaller_signature (Gee.List<FormalParameter> params, DataType return_type, bool dbus = false) {
135 string signature;
137 signature = "%s:".printf (get_marshaller_type_name (return_type, dbus));
138 if (params == null || params.size == 0) {
139 signature = signature + "VOID";
140 } else {
141 bool first = true;
142 foreach (FormalParameter p in params) {
143 if (first) {
144 signature = signature + get_marshaller_type_name_for_parameter (p, dbus);
145 first = false;
146 } else {
147 signature = "%s,%s".printf (signature, get_marshaller_type_name_for_parameter (p, dbus));
152 return signature;
155 public override void visit_signal (Signal sig) {
156 // parent_symbol may be null for dynamic signals
158 var cl = sig.parent_symbol as Class;
159 if (cl != null && cl.is_compact) {
160 sig.error = true;
161 Report.error (sig.source_reference, "Signals are not supported in compact classes");
162 return;
165 sig.accept_children (codegen);
167 generate_marshaller (sig.get_parameters (), sig.return_type);
170 public override void generate_marshaller (Gee.List<FormalParameter> params, DataType return_type, bool dbus = false) {
171 string signature;
172 int n_params, i;
174 /* check whether a signal with the same signature already exists for this source file (or predefined) */
175 signature = get_marshaller_signature (params, return_type, dbus);
176 if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) {
177 return;
180 var signal_marshaller = new CCodeFunction (get_marshaller_function (params, return_type, null, dbus), "void");
181 signal_marshaller.modifiers = CCodeModifiers.STATIC;
183 signal_marshaller.add_parameter (new CCodeFormalParameter ("closure", "GClosure *"));
184 signal_marshaller.add_parameter (new CCodeFormalParameter ("return_value", "GValue *"));
185 signal_marshaller.add_parameter (new CCodeFormalParameter ("n_param_values", "guint"));
186 signal_marshaller.add_parameter (new CCodeFormalParameter ("param_values", "const GValue *"));
187 signal_marshaller.add_parameter (new CCodeFormalParameter ("invocation_hint", "gpointer"));
188 signal_marshaller.add_parameter (new CCodeFormalParameter ("marshal_data", "gpointer"));
190 source_signal_marshaller_declaration.append (signal_marshaller.copy ());
192 var marshaller_body = new CCodeBlock ();
194 var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (params, return_type, "GMarshalFunc", dbus));
195 callback_decl.add_parameter (new CCodeFormalParameter ("data1", "gpointer"));
196 n_params = 1;
197 foreach (FormalParameter p in params) {
198 callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), get_value_type_name_from_parameter (p)));
199 n_params++;
200 if (p.parameter_type.is_array () && !dbus) {
201 callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), "gint"));
202 n_params++;
205 callback_decl.add_parameter (new CCodeFormalParameter ("data2", "gpointer"));
206 marshaller_body.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type), callback_decl));
208 var var_decl = new CCodeDeclaration (get_marshaller_function (params, return_type, "GMarshalFunc", dbus));
209 var_decl.modifiers = CCodeModifiers.REGISTER;
210 var_decl.add_declarator (new CCodeVariableDeclarator ("callback"));
211 marshaller_body.add_statement (var_decl);
213 var_decl = new CCodeDeclaration ("GCClosure *");
214 var_decl.modifiers = CCodeModifiers.REGISTER;
215 var_decl.add_declarator (new CCodeVariableDeclarator ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")));
216 marshaller_body.add_statement (var_decl);
218 var_decl = new CCodeDeclaration ("gpointer");
219 var_decl.modifiers = CCodeModifiers.REGISTER;
220 var_decl.add_declarator (new CCodeVariableDeclarator ("data1"));
221 var_decl.add_declarator (new CCodeVariableDeclarator ("data2"));
222 marshaller_body.add_statement (var_decl);
224 CCodeFunctionCall fc;
226 if (return_type.data_type != null || return_type.is_array ()) {
227 var_decl = new CCodeDeclaration (get_value_type_name_from_type_reference (return_type));
228 var_decl.add_declarator (new CCodeVariableDeclarator ("v_return"));
229 marshaller_body.add_statement (var_decl);
231 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
232 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL")));
233 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
236 fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail"));
237 fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string())));
238 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
240 var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true);
241 var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer");
242 var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA"));
243 cond.add_argument (new CCodeIdentifier ("closure"));
244 var true_block = new CCodeBlock ();
245 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), data)));
246 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), param)));
247 var false_block = new CCodeBlock ();
248 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data1"), param)));
249 false_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("data2"), data)));
250 marshaller_body.add_statement (new CCodeIfStatement (cond, true_block, false_block));
252 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)));
253 marshaller_body.add_statement (new CCodeExpressionStatement (c_assign));
255 fc = new CCodeFunctionCall (new CCodeIdentifier ("callback"));
256 fc.add_argument (new CCodeIdentifier ("data1"));
257 i = 1;
258 foreach (FormalParameter p in params) {
259 string get_value_function;
260 bool is_array = p.parameter_type.is_array ();
261 if (p.direction != ParameterDirection.IN) {
262 get_value_function = "g_value_get_pointer";
263 } else if (is_array) {
264 if (dbus) {
265 get_value_function = "g_value_get_boxed";
266 } else {
267 if (((ArrayType) p.parameter_type).element_type.data_type == string_type.data_type) {
268 get_value_function = "g_value_get_boxed";
269 } else {
270 get_value_function = "g_value_get_pointer";
273 } else if (p.parameter_type is PointerType || p.parameter_type.type_parameter != null) {
274 get_value_function = "g_value_get_pointer";
275 } else if (p.parameter_type is ErrorType) {
276 get_value_function = "g_value_get_pointer";
277 } else if (dbus && p.parameter_type.get_type_signature ().has_prefix ("(")) {
278 get_value_function = "g_value_get_boxed";
279 } else if (dbus && p.parameter_type.data_type is Enum) {
280 var en = (Enum) p.parameter_type.data_type;
281 if (en.is_flags) {
282 get_value_function = "g_value_get_uint";
283 } else {
284 get_value_function = "g_value_get_int";
286 } else {
287 get_value_function = p.parameter_type.data_type.get_get_value_function ();
289 var inner_fc = new CCodeFunctionCall (new CCodeIdentifier (get_value_function));
290 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
291 fc.add_argument (inner_fc);
292 i++;
293 if (is_array && !dbus) {
294 inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_int"));
295 inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ())));
296 fc.add_argument (inner_fc);
297 i++;
300 fc.add_argument (new CCodeIdentifier ("data2"));
302 if (return_type.data_type != null || return_type.is_array ()) {
303 marshaller_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("v_return"), fc)));
305 CCodeFunctionCall set_fc;
306 if (return_type.is_array ()) {
307 if (dbus) {
308 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
309 } else {
310 if (((ArrayType) return_type).element_type.data_type == string_type.data_type) {
311 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
312 } else {
313 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
316 } else if (return_type.type_parameter != null) {
317 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
318 } else if (return_type is ErrorType) {
319 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer"));
320 } else if (return_type.data_type == string_type.data_type) {
321 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_string"));
322 } else if (return_type.data_type is Class || return_type.data_type is Interface) {
323 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object"));
324 } else if (dbus && return_type.get_type_signature ().has_prefix ("(")) {
325 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
326 } else if (dbus && return_type.data_type is Enum) {
327 var en = (Enum) return_type.data_type;
328 if (en.is_flags) {
329 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_uint"));
330 } else {
331 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_int"));
333 } else {
334 set_fc = new CCodeFunctionCall (new CCodeIdentifier (return_type.data_type.get_set_value_function ()));
336 set_fc.add_argument (new CCodeIdentifier ("return_value"));
337 set_fc.add_argument (new CCodeIdentifier ("v_return"));
339 marshaller_body.add_statement (new CCodeExpressionStatement (set_fc));
340 } else {
341 marshaller_body.add_statement (new CCodeExpressionStatement (fc));
344 signal_marshaller.block = marshaller_body;
346 source_signal_marshaller_definition.append (signal_marshaller);
347 user_marshal_set.add (signature);
350 public override CCodeFunctionCall get_signal_creation (Signal sig, TypeSymbol type) {
351 var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new"));
352 csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.get_cname ())));
353 csignew.add_argument (new CCodeIdentifier (type.get_type_id ()));
354 csignew.add_argument (new CCodeConstant ("G_SIGNAL_RUN_LAST"));
355 csignew.add_argument (new CCodeConstant ("0"));
356 csignew.add_argument (new CCodeConstant ("NULL"));
357 csignew.add_argument (new CCodeConstant ("NULL"));
359 string marshaller = head.get_marshaller_function (sig.get_parameters (), sig.return_type);
361 var marshal_arg = new CCodeIdentifier (marshaller);
362 csignew.add_argument (marshal_arg);
364 var params = sig.get_parameters ();
365 if (sig.return_type is PointerType || sig.return_type.type_parameter != null) {
366 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
367 } else if (sig.return_type is ErrorType) {
368 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
369 } else if (sig.return_type.data_type == null) {
370 csignew.add_argument (new CCodeConstant ("G_TYPE_NONE"));
371 } else {
372 csignew.add_argument (new CCodeConstant (sig.return_type.data_type.get_type_id ()));
375 int params_len = 0;
376 foreach (FormalParameter param in params) {
377 params_len++;
378 if (param.parameter_type.is_array ()) {
379 params_len++;
383 csignew.add_argument (new CCodeConstant ("%d".printf (params_len)));
384 foreach (FormalParameter param in params) {
385 if (param.parameter_type.is_array ()) {
386 if (((ArrayType) param.parameter_type).element_type.data_type == string_type.data_type) {
387 csignew.add_argument (new CCodeConstant ("G_TYPE_STRV"));
388 } else {
389 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
391 csignew.add_argument (new CCodeConstant ("G_TYPE_INT"));
392 } else if (param.parameter_type is PointerType || param.parameter_type.type_parameter != null || param.direction != ParameterDirection.IN) {
393 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
394 } else if (param.parameter_type is ErrorType) {
395 csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER"));
396 } else {
397 csignew.add_argument (new CCodeConstant (param.parameter_type.data_type.get_type_id ()));
401 marshal_arg.name = marshaller;
403 return csignew;
406 public virtual CCodeExpression get_dbus_g_type (DataType data_type) {
407 return new CCodeConstant (data_type.data_type.get_type_id ());
410 public override void visit_element_access (ElementAccess expr) {
411 if (expr.container is MemberAccess && expr.container.symbol_reference is Signal) {
412 // detailed signal emission
413 var sig = (Signal) expr.symbol_reference;
414 var ma = (MemberAccess) expr.container;
415 expr.accept_children (codegen);
417 var detail_expr = expr.get_indices ().get (0) as StringLiteral;
418 string signal_detail = detail_expr.eval ();
420 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
421 ccall.add_argument ((CCodeExpression) ma.inner.ccodenode);
422 ccall.add_argument (sig.get_canonical_cconstant (signal_detail));
424 expr.ccodenode = ccall;
425 } else {
426 base.visit_element_access (expr);
430 CCodeExpression? emit_signal_assignment (Assignment assignment) {
431 var sig = (Signal) assignment.left.symbol_reference;
433 var m = (Method) assignment.right.symbol_reference;
434 var target_type_symbol = m.parent_symbol as TypeSymbol;
436 string connect_func;
437 bool disconnect = false;
439 if (assignment.operator == AssignmentOperator.ADD) {
440 if (sig is DynamicSignal) {
441 connect_func = head.get_dynamic_signal_connect_wrapper_name ((DynamicSignal) sig);
442 } else {
443 if (m.binding == MemberBinding.INSTANCE) {
444 if (target_type_symbol != null && target_type_symbol.is_subtype_of (gobject_type)) {
445 connect_func = "g_signal_connect_object";
446 } else {
447 connect_func = "g_signal_connect";
449 } else {
450 connect_func = "g_signal_connect";
453 } else if (assignment.operator == AssignmentOperator.SUB) {
454 if (sig is DynamicSignal) {
455 connect_func = head.get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal) sig);
456 } else {
457 connect_func = "g_signal_handlers_disconnect_matched";
459 disconnect = true;
460 } else {
461 assignment.error = true;
462 Report.error (assignment.source_reference, "Specified compound assignment type for signals not supported.");
463 return null;
466 var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
468 string signal_detail = null;
470 // first argument: instance of sender
471 MemberAccess ma;
472 if (assignment.left is ElementAccess) {
473 var ea = (ElementAccess) assignment.left;
474 ma = (MemberAccess) ea.container;
475 var detail_expr = ea.get_indices ().get (0) as StringLiteral;
476 if (detail_expr == null) {
477 assignment.error = true;
478 Report.error (detail_expr.source_reference, "internal error: only literal string details supported");
479 return null;
481 signal_detail = detail_expr.eval ();
482 } else {
483 ma = (MemberAccess) assignment.left;
485 if (ma.inner != null) {
486 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
487 } else {
488 ccall.add_argument (new CCodeIdentifier ("self"));
491 if (sig is DynamicSignal) {
492 // dynamic_signal_connect or dynamic_signal_disconnect
494 // second argument: signal name
495 ccall.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
496 } else if (!disconnect) {
497 // g_signal_connect_object or g_signal_connect
499 // second argument: signal name
500 ccall.add_argument (sig.get_canonical_cconstant (signal_detail));
501 } else {
502 // g_signal_handlers_disconnect_matched
504 // second argument: mask
505 if (signal_detail == null) {
506 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
507 } else {
508 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
511 // get signal id
512 var ccomma = new CCodeCommaExpression ();
513 var temp_decl = get_temp_variable (uint_type);
514 temp_vars.insert (0, temp_decl);
515 var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
516 parse_call.add_argument (sig.get_canonical_cconstant (signal_detail));
517 var decl_type = (TypeSymbol) sig.parent_symbol;
518 parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
519 parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
520 if (signal_detail == null) {
521 parse_call.add_argument (new CCodeConstant ("NULL"));
522 } else {
523 var detail_temp_decl = get_temp_variable (gquark_type);
524 temp_vars.insert (0, detail_temp_decl);
525 parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (detail_temp_decl.name)));
527 parse_call.add_argument (new CCodeConstant ("FALSE"));
528 ccomma.append_expression (parse_call);
529 ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
531 // third argument: signal_id
532 ccall.add_argument (ccomma);
534 // fourth argument: detail
535 ccall.add_argument (new CCodeConstant ("0"));
536 // fifth argument: closure
537 ccall.add_argument (new CCodeConstant ("NULL"));
540 // third resp. sixth argument: handler
541 ccall.add_argument (new CCodeCastExpression ((CCodeExpression) assignment.right.ccodenode, "GCallback"));
543 if (m.binding == MemberBinding.INSTANCE) {
544 // g_signal_connect_object or g_signal_handlers_disconnect_matched
545 // or dynamic_signal_connect or dynamic_signal_disconnect
547 // fourth resp. seventh argument: object/user_data
548 if (assignment.right is MemberAccess) {
549 var right_ma = (MemberAccess) assignment.right;
550 if (right_ma.inner != null) {
551 ccall.add_argument ((CCodeExpression) right_ma.inner.ccodenode);
552 } else {
553 ccall.add_argument (new CCodeIdentifier ("self"));
555 } else if (assignment.right is LambdaExpression) {
556 ccall.add_argument (new CCodeIdentifier ("self"));
558 if (!disconnect && !(sig is DynamicSignal)
559 && target_type_symbol != null && target_type_symbol.is_subtype_of (gobject_type)) {
560 // g_signal_connect_object
562 // fifth argument: connect_flags
563 ccall.add_argument (new CCodeConstant ("0"));
565 } else {
566 // g_signal_connect or g_signal_handlers_disconnect_matched
567 // or dynamic_signal_connect or dynamic_signal_disconnect
569 // fourth resp. seventh argument: user_data
570 ccall.add_argument (new CCodeConstant ("NULL"));
573 return ccall;
576 public override void visit_assignment (Assignment assignment) {
577 if (assignment.left.symbol_reference is Signal) {
578 assignment.right.accept (codegen);
580 if (assignment.left.error || assignment.right.error) {
581 assignment.error = true;
582 return;
585 assignment.ccodenode = emit_signal_assignment (assignment);
586 } else {
587 base.visit_assignment (assignment);
591 public override void visit_member_access (MemberAccess expr) {
592 if (expr.symbol_reference is Signal) {
593 expr.accept_children (codegen);
595 CCodeExpression pub_inst = null;
597 if (expr.inner != null) {
598 pub_inst = (CCodeExpression) expr.inner.ccodenode;
601 var sig = (Signal) expr.symbol_reference;
602 var cl = (TypeSymbol) sig.parent_symbol;
604 if (expr.inner is BaseAccess && sig.is_virtual) {
605 var m = sig.get_method_handler ();
606 var base_class = (Class) m.parent_symbol;
607 var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
608 vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
610 expr.ccodenode = new CCodeMemberAccess.pointer (vcast, m.name);
611 return;
614 if (sig.has_emitter) {
615 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name)));
617 ccall.add_argument (pub_inst);
618 expr.ccodenode = ccall;
619 } else {
620 var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
621 ccall.add_argument (pub_inst);
623 ccall.add_argument (sig.get_canonical_cconstant ());
625 expr.ccodenode = ccall;
627 } else {
628 base.visit_member_access (expr);