GAsync: Various fixes for temp variables in coroutines
[vala-lang.git] / codegen / valagsignalmodule.vala
blob34d23eedaad3fcdbe94bf24f5607d3b1fb788c2a
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using Gee;
27 internal class Vala.GSignalModule : GObjectModule {
28 public GSignalModule (CCodeGenerator codegen, CCodeModule? next) {
29 base (codegen, next);
32 private string get_marshaller_type_name (DataType t, bool dbus = false) {
33 if (t is PointerType || t.type_parameter != null) {
34 return ("POINTER");
35 } else if (t is ErrorType) {
36 return ("POINTER");
37 } else if (t is ArrayType) {
38 if (dbus) {
39 return ("BOXED");
40 } else {
41 if (((ArrayType) t).element_type.data_type == string_type.data_type) {
42 return ("BOXED_INT");
43 } else {
44 return ("POINTER_INT");
47 } else if (t is VoidType) {
48 return ("VOID");
49 } else if (dbus && DBusModule.get_type_signature (t).has_prefix ("(")) {
50 return ("BOXED");
51 } else if (t.data_type is Enum) {
52 var en = (Enum) t.data_type;
53 if (dbus) {
54 if (en.is_flags) {
55 return ("UINT");
56 } else {
57 return ("INT");
59 } else {
60 return en.get_marshaller_type_name ();
62 } else {
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) {
69 return ("POINTER");
70 } else {
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);
77 string ret;
79 if (prefix == null) {
80 if (predefined_marshal_set.contains (signature)) {
81 prefix = "g_cclosure_marshal";
82 } else {
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) {
90 ret = ret + "_VOID";
91 } else {
92 foreach (FormalParameter p in params) {
93 ret = "%s_%s".printf (ret, get_marshaller_type_name_for_parameter (p, dbus));
97 return ret;
100 private string? get_value_type_name_from_type_reference (DataType t) {
101 if (t is PointerType || t.type_parameter != null) {
102 return "gpointer";
103 } else if (t is VoidType) {
104 return "void";
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) {
108 return "gpointer";
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 ();
113 } else {
114 return "gpointer";
116 } else if (t.data_type is Enum) {
117 return "gint";
118 } else if (t is ArrayType) {
119 return "gpointer";
120 } else if (t is ErrorType) {
121 return "gpointer";
124 return null;
127 private string? get_value_type_name_from_parameter (FormalParameter p) {
128 if (p.direction != ParameterDirection.IN) {
129 return "gpointer";
130 } else {
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) {
136 string signature;
138 signature = "%s:".printf (get_marshaller_type_name (return_type, dbus));
139 if (params == null || params.size == 0) {
140 signature = signature + "VOID";
141 } else {
142 bool first = true;
143 foreach (FormalParameter p in params) {
144 if (first) {
145 signature = signature + get_marshaller_type_name_for_parameter (p, dbus);
146 first = false;
147 } else {
148 signature = "%s,%s".printf (signature, get_marshaller_type_name_for_parameter (p, dbus));
153 return signature;
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) {
161 sig.error = true;
162 Report.error (sig.source_reference, "Signals are not supported in compact classes");
163 return;
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) {
177 string signature;
178 int n_params, i;
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)) {
183 return;
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"));
202 n_params = 1;
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)));
205 n_params++;
206 if (p.parameter_type.is_array () && !dbus) {
207 callback_decl.add_parameter (new CCodeFormalParameter ("arg_%d".printf (n_params), "gint"));
208 n_params++;
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"));
263 i = 1;
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) {
270 if (dbus) {
271 get_value_function = "g_value_get_boxed";
272 } else {
273 if (((ArrayType) p.parameter_type).element_type.data_type == string_type.data_type) {
274 get_value_function = "g_value_get_boxed";
275 } else {
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;
287 if (en.is_flags) {
288 get_value_function = "g_value_get_uint";
289 } else {
290 get_value_function = "g_value_get_int";
292 } else {
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);
298 i++;
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);
303 i++;
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 ()) {
313 if (dbus) {
314 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
315 } else {
316 if (((ArrayType) return_type).element_type.data_type == string_type.data_type) {
317 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
318 } else {
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;
334 if (en.is_flags) {
335 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_uint"));
336 } else {
337 set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_int"));
339 } else {
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));
346 } else {
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"));
364 } else {
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"));
385 } else {
386 csignew.add_argument (new CCodeConstant (sig.return_type.data_type.get_type_id ()));
389 int params_len = 0;
390 foreach (FormalParameter param in params) {
391 params_len++;
392 if (param.parameter_type.is_array ()) {
393 params_len++;
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"));
402 } else {
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"));
410 } else {
411 csignew.add_argument (new CCodeConstant (param.parameter_type.data_type.get_type_id ()));
415 marshal_arg.name = marshaller;
417 return csignew;
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;
439 } else {
440 base.visit_element_access (expr);
444 bool in_gobject_instance (Method m) {
445 bool result = false;
446 if (m.binding == MemberBinding.INSTANCE) {
447 result = m.this_parameter.parameter_type.data_type.is_subtype_of (gobject_type);
449 return result;
452 CCodeExpression? emit_signal_assignment (Assignment assignment) {
453 var sig = (Signal) assignment.left.symbol_reference;
455 var m = (Method) assignment.right.symbol_reference;
457 string connect_func;
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);
463 } else {
464 if (in_gobject_instance (m)) {
465 connect_func = "g_signal_connect_object";
466 } else {
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);
473 } else {
474 connect_func = "g_signal_handlers_disconnect_matched";
476 disconnect = true;
477 } else {
478 assignment.error = true;
479 Report.error (assignment.source_reference, "Specified compound assignment type for signals not supported.");
480 return null;
483 var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
485 string signal_detail = null;
487 // first argument: instance of sender
488 MemberAccess ma;
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");
496 return null;
498 signal_detail = detail_expr.eval ();
499 } else {
500 ma = (MemberAccess) assignment.left;
502 if (ma.inner != null) {
503 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
504 } else {
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));
518 } else {
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"));
524 } else {
525 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
528 // get signal id
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"));
539 } else {
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);
569 } else {
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"));
582 } else {
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"));
590 return ccall;
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;
599 return;
602 assignment.ccodenode = emit_signal_assignment (assignment);
603 } else {
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);
628 return;
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;
636 } else {
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;
644 } else {
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);
655 return;
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;
667 string connect_func;
668 bool disconnect = (method_type.method_symbol.name == "disconnect");
670 if (!disconnect) {
671 // connect
672 if (sig is DynamicSignal) {
673 connect_func = head.get_dynamic_signal_connect_wrapper_name ((DynamicSignal) sig);
674 } else {
675 if (in_gobject_instance (m)) {
676 connect_func = "g_signal_connect_object";
677 } else {
678 connect_func = "g_signal_connect";
681 } else {
682 // disconnect
683 if (sig is DynamicSignal) {
684 connect_func = head.get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal) sig);
685 } else {
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
695 MemberAccess ma;
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) {
701 expr.error = true;
702 Report.error (detail_expr.source_reference, "internal error: only literal string details supported");
703 return;
705 signal_detail = detail_expr.eval ();
706 } else {
707 ma = (MemberAccess) signal_access;
709 if (ma.inner != null) {
710 ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
711 } else {
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));
725 } else {
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"));
731 } else {
732 ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
735 // get signal id
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"));
746 } else {
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);
776 } else {
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"));
789 } else {
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;