/* valagsignalmodule.vala * * Copyright (C) 2006-2010 Jürg Billeter * Copyright (C) 2006-2008 Raffaele Sandrini * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Author: * Jürg Billeter * Raffaele Sandrini */ public class Vala.GSignalModule : GObjectModule { string get_marshaller_function (Signal sig, List params, DataType return_type, string? prefix = null) { var signature = get_marshaller_signature (sig, params, return_type); string ret; if (prefix == null) { if (predefined_marshal_set.contains (signature)) { prefix = "g_cclosure_marshal"; } else { prefix = "g_cclosure_user_marshal"; } } ret = "%s_%s_".printf (prefix, get_ccode_marshaller_type_name (return_type)); foreach (Parameter p in params) { ret = "%s_%s".printf (ret, get_ccode_marshaller_type_name (p).replace (",", "_")); } if (sig.return_type.is_real_non_null_struct_type ()) { ret = ret + "_POINTER"; } else if (params.size == 0) { ret = ret + "_VOID"; } return ret; } private string? get_value_type_name_from_type_reference (DataType t) { if (t is PointerType || t is GenericType) { return "gpointer"; } else if (t is VoidType) { return "void"; } else if (get_ccode_type_id (t) == get_ccode_type_id (string_type)) { return "const char*"; } else if (t.type_symbol is Class || t.type_symbol is Interface) { return "gpointer"; } else if (t is ValueType && t.nullable) { return "gpointer"; } else if (t.type_symbol is Struct) { unowned Struct st = (Struct) t.type_symbol; if (st.is_simple_type ()) { return get_ccode_name (t.type_symbol); } else { return "gpointer"; } } else if (t.type_symbol is Enum) { unowned Enum en = (Enum) t.type_symbol; if (en.is_flags) { return "guint"; } else { return "gint"; } } else if (t is ArrayType) { return "gpointer"; } else if (t is DelegateType) { return "gpointer"; } else if (t is ErrorType) { return "gpointer"; } return null; } private string? get_value_type_name_from_parameter (Parameter p) { if (p.direction != ParameterDirection.IN) { return "gpointer"; } else { return get_value_type_name_from_type_reference (p.variable_type); } } private string get_marshaller_signature (Signal sig, List params, DataType return_type) { string signature; signature = "%s:".printf (get_ccode_marshaller_type_name (return_type)); bool first = true; foreach (Parameter p in params) { if (first) { signature = signature + get_ccode_marshaller_type_name (p); first = false; } else { signature = "%s,%s".printf (signature, get_ccode_marshaller_type_name (p)); } } if (sig.return_type.is_real_non_null_struct_type ()) { signature = signature + (first ? "POINTER" : ",POINTER"); } else if (params.size == 0) { signature = signature + "VOID"; } return signature; } private CCodeExpression get_signal_name_cexpression (Signal sig, Expression? detail_expr, CodeNode node) { if (detail_expr == null) { return get_signal_canonical_constant (sig); } if (detail_expr is StringLiteral) { return get_signal_canonical_constant (sig, ((StringLiteral) detail_expr).eval ()); } var detail_value = create_temp_value (detail_expr.value_type, false, node, true); temp_ref_values.insert (0, detail_value); var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_strconcat")); ccall.add_argument (get_signal_canonical_constant (sig, "")); ccall.add_argument (get_cvalue (detail_expr)); ccall.add_argument (new CCodeConstant ("NULL")); ccode.add_assignment (get_cvalue_ (detail_value), ccall); return get_cvalue_ (detail_value); } private CCodeExpression get_signal_id_cexpression (Signal sig) { var cl = (TypeSymbol) sig.parent_symbol; var signal_array = new CCodeIdentifier ("%s_signals".printf (get_ccode_lower_case_name (cl))); var signal_enum_value = new CCodeIdentifier ("%s_%s_SIGNAL".printf (get_ccode_upper_case_name (cl), get_ccode_upper_case_name (sig))); return new CCodeElementAccess (signal_array, signal_enum_value); } private CCodeExpression get_detail_cexpression (Expression detail_expr, CodeNode node) { var detail_cexpr = get_cvalue (detail_expr); CCodeFunctionCall detail_ccall; if (is_constant_ccode_expression (detail_cexpr)) { detail_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string")); } else { detail_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string")); } detail_ccall.add_argument (detail_cexpr); return detail_ccall; } public override void visit_signal (Signal sig) { if (signal_enum != null && sig.parent_symbol is TypeSymbol) { 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)))); } sig.accept_children (this); // declare parameter type unowned List params = sig.get_parameters (); foreach (Parameter p in params) { generate_parameter (p, cfile, new HashMap (), null); } if (sig.return_type.is_real_non_null_struct_type ()) { generate_marshaller (sig, params, new VoidType ()); } else { generate_marshaller (sig, params, sig.return_type); } } void generate_marshaller (Signal sig, List params, DataType return_type) { string signature; int n_params, i; /* check whether a signal with the same signature already exists for this source file (or predefined) */ signature = get_marshaller_signature (sig, params, return_type); if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) { return; } var signal_marshaller = new CCodeFunction (get_marshaller_function (sig, params, return_type, null), "void"); signal_marshaller.modifiers = CCodeModifiers.STATIC; signal_marshaller.add_parameter (new CCodeParameter ("closure", "GClosure *")); signal_marshaller.add_parameter (new CCodeParameter ("return_value", "GValue *")); signal_marshaller.add_parameter (new CCodeParameter ("n_param_values", "guint")); signal_marshaller.add_parameter (new CCodeParameter ("param_values", "const GValue *")); signal_marshaller.add_parameter (new CCodeParameter ("invocation_hint", "gpointer")); signal_marshaller.add_parameter (new CCodeParameter ("marshal_data", "gpointer")); push_function (signal_marshaller); var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (sig, params, return_type, "GMarshalFunc")); callback_decl.add_parameter (new CCodeParameter ("data1", "gpointer")); n_params = 1; foreach (Parameter p in params) { callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), get_value_type_name_from_parameter (p))); n_params++; if (p.variable_type is ArrayType) { var array_type = (ArrayType) p.variable_type; var length_ctype = get_ccode_array_length_type (p); for (var j = 0; j < array_type.rank; j++) { callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), length_ctype)); n_params++; } } else if (p.variable_type is DelegateType) { unowned DelegateType delegate_type = (DelegateType) p.variable_type; if (delegate_type.delegate_symbol.has_target) { callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), get_ccode_name (delegate_target_type))); n_params++; if (delegate_type.is_disposable ()) { callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), get_ccode_name (delegate_target_destroy_type))); n_params++; } } } } if (sig.return_type.is_real_non_null_struct_type ()) { callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), "gpointer")); n_params++; } callback_decl.add_parameter (new CCodeParameter ("data2", "gpointer")); ccode.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type), callback_decl)); ccode.add_declaration (get_marshaller_function (sig, params, return_type, "GMarshalFunc"), new CCodeVariableDeclarator ("callback"), CCodeModifiers.REGISTER); ccode.add_declaration ("GCClosure *", new CCodeVariableDeclarator ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")), CCodeModifiers.REGISTER); ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("data1"), CCodeModifiers.REGISTER); ccode.add_declaration ("gpointer", new CCodeVariableDeclarator ("data2"), CCodeModifiers.REGISTER); CCodeFunctionCall fc; if (return_type.type_symbol != null || return_type is ArrayType) { ccode.add_declaration (get_value_type_name_from_type_reference (return_type), new CCodeVariableDeclarator ("v_return")); fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail")); fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("return_value"), new CCodeConstant ("NULL"))); ccode.add_expression (fc); } fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail")); fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("n_param_values"), new CCodeConstant (n_params.to_string()))); ccode.add_expression (fc); var data = new CCodeMemberAccess (new CCodeIdentifier ("closure"), "data", true); var param = new CCodeMemberAccess (new CCodeMemberAccess (new CCodeIdentifier ("param_values"), "data[0]", true), "v_pointer"); var cond = new CCodeFunctionCall (new CCodeConstant ("G_CCLOSURE_SWAP_DATA")); cond.add_argument (new CCodeIdentifier ("closure")); ccode.open_if (cond); ccode.add_assignment (new CCodeIdentifier ("data1"), data); ccode.add_assignment (new CCodeIdentifier ("data2"), param); ccode.add_else (); ccode.add_assignment (new CCodeIdentifier ("data1"), param); ccode.add_assignment (new CCodeIdentifier ("data2"), data); ccode.close (); 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 (sig, params, return_type, "GMarshalFunc")); ccode.add_assignment (new CCodeIdentifier ("callback"), c_assign_rhs); fc = new CCodeFunctionCall (new CCodeIdentifier ("callback")); fc.add_argument (new CCodeIdentifier ("data1")); i = 1; foreach (Parameter p in params) { CCodeFunctionCall inner_fc; if (p.direction != ParameterDirection.IN) { inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer")); } else if (p.variable_type is ValueType && p.variable_type.nullable) { inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer")); } else { inner_fc = new CCodeFunctionCall (get_value_getter_function (p.variable_type)); } inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ()))); fc.add_argument (inner_fc); i++; if (p.variable_type is ArrayType) { var array_type = (ArrayType) p.variable_type; var length_value_function = get_ccode_get_value_function (array_type.length_type.type_symbol); assert (length_value_function != null && length_value_function != ""); for (var j = 0; j < array_type.rank; j++) { inner_fc = new CCodeFunctionCall (new CCodeIdentifier (length_value_function)); inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ()))); fc.add_argument (inner_fc); i++; } } else if (p.variable_type is DelegateType) { unowned DelegateType delegate_type = (DelegateType) p.variable_type; if (delegate_type.delegate_symbol.has_target) { inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer")); inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ()))); fc.add_argument (inner_fc); i++; if (delegate_type.is_disposable ()) { inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer")); inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ()))); fc.add_argument (inner_fc); i++; } } } } if (sig.return_type.is_real_non_null_struct_type ()) { var inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer")); inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ()))); fc.add_argument (inner_fc); i++; } fc.add_argument (new CCodeIdentifier ("data2")); if (return_type.type_symbol != null || return_type is ArrayType) { ccode.add_assignment (new CCodeIdentifier ("v_return"), fc); CCodeFunctionCall set_fc; if (return_type is ValueType) { if (return_type.nullable) { set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_pointer")); } else { set_fc = new CCodeFunctionCall (get_value_setter_function (return_type)); } } else { set_fc = new CCodeFunctionCall (get_value_taker_function (return_type)); } set_fc.add_argument (new CCodeIdentifier ("return_value")); set_fc.add_argument (new CCodeIdentifier ("v_return")); ccode.add_expression (set_fc); } else { ccode.add_expression (fc); } pop_function (); cfile.add_function_declaration (signal_marshaller); cfile.add_function (signal_marshaller); user_marshal_set.add (signature); } public override CCodeExpression get_signal_creation (Signal sig, ObjectTypeSymbol type) { CCodeFunctionCall csignew; if (sig.default_handler == null || sig.is_virtual) { csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new")); } else { csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new_class_handler")); } csignew.add_argument (new CCodeConstant ("\"%s\"".printf (get_ccode_name (sig)))); csignew.add_argument (new CCodeIdentifier (get_ccode_type_id (type))); string[] flags = new string[0]; var run_type = sig.get_attribute_string ("Signal", "run"); if (run_type == "first") { flags += "G_SIGNAL_RUN_FIRST"; } else if (run_type == "cleanup") { flags += "G_SIGNAL_RUN_CLEANUP"; } else { flags += "G_SIGNAL_RUN_LAST"; } if (sig.get_attribute_bool ("Signal", "detailed")) { flags += "G_SIGNAL_DETAILED"; } if (sig.get_attribute_bool ("Signal", "no_recurse")) { flags += "G_SIGNAL_NO_RECURSE"; } if (sig.get_attribute_bool ("Signal", "action")) { flags += "G_SIGNAL_ACTION"; } if (sig.get_attribute_bool ("Signal", "no_hooks")) { flags += "G_SIGNAL_NO_HOOKS"; } if (sig.version.deprecated) { flags += "G_SIGNAL_DEPRECATED"; } csignew.add_argument (new CCodeConstant (string.joinv (" | ", flags))); if (sig.default_handler == null) { csignew.add_argument (new CCodeConstant ("0")); } else if (sig.is_virtual) { var struct_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET")); struct_offset.add_argument (new CCodeIdentifier (get_ccode_type_name (type))); struct_offset.add_argument (new CCodeIdentifier (get_ccode_vfunc_name (sig.default_handler))); csignew.add_argument (struct_offset); } else { csignew.add_argument (new CCodeCastExpression (new CCodeIdentifier (get_ccode_real_name (sig.default_handler)), "GCallback")); } csignew.add_argument (new CCodeConstant ("NULL")); csignew.add_argument (new CCodeConstant ("NULL")); unowned List params = sig.get_parameters (); string marshaller; if (sig.return_type.is_real_non_null_struct_type ()) { marshaller = get_marshaller_function (sig, params, new VoidType ()); } else { marshaller = get_marshaller_function (sig, params, sig.return_type); } var marshal_arg = new CCodeIdentifier (marshaller); csignew.add_argument (marshal_arg); if (sig.return_type is PointerType || sig.return_type is GenericType) { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } else if (sig.return_type is ErrorType) { csignew.add_argument (new CCodeConstant ("G_TYPE_ERROR")); } else if (sig.return_type is ValueType && sig.return_type.nullable) { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } else if (sig.return_type.type_symbol == null) { csignew.add_argument (new CCodeConstant ("G_TYPE_NONE")); } else if (sig.return_type.is_real_non_null_struct_type ()) { csignew.add_argument (new CCodeConstant ("G_TYPE_NONE")); } else { csignew.add_argument (new CCodeConstant (get_ccode_type_id (sig.return_type.type_symbol))); } int params_len = 0; foreach (Parameter param in params) { params_len++; if (param.variable_type is ArrayType) { params_len += ((ArrayType) param.variable_type).rank; } else if (param.variable_type is DelegateType) { unowned DelegateType delegate_type = (DelegateType) param.variable_type; if (delegate_type.delegate_symbol.has_target) { params_len++; if (delegate_type.is_disposable ()) { params_len++; } } } } if (sig.return_type.is_real_non_null_struct_type ()) { params_len++; } csignew.add_argument (new CCodeConstant ("%d".printf (params_len))); foreach (Parameter param in params) { if (param.variable_type is ArrayType) { var array_type = (ArrayType) param.variable_type; if (array_type.element_type.type_symbol == string_type.type_symbol) { csignew.add_argument (new CCodeConstant ("G_TYPE_STRV")); } else { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } assert (get_ccode_has_type_id (array_type.length_type.type_symbol)); var length_type_id = get_ccode_type_id (array_type.length_type.type_symbol); for (var i = 0; i < array_type.rank; i++) { csignew.add_argument (new CCodeConstant (length_type_id)); } } else if (param.variable_type is DelegateType) { unowned DelegateType delegate_type = (DelegateType) param.variable_type; csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); if (delegate_type.delegate_symbol.has_target) { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); if (delegate_type.is_disposable ()) { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } } } else if (param.variable_type is PointerType || param.variable_type is GenericType || param.direction != ParameterDirection.IN) { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } else if (param.variable_type is ErrorType) { csignew.add_argument (new CCodeConstant ("G_TYPE_ERROR")); } else if (param.variable_type is ValueType && param.variable_type.nullable) { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } else { csignew.add_argument (new CCodeConstant (get_ccode_type_id (param.variable_type.type_symbol))); } } if (sig.return_type.is_real_non_null_struct_type ()) { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } marshal_arg.name = marshaller; return new CCodeAssignment (get_signal_id_cexpression (sig), csignew); } public override void visit_element_access (ElementAccess expr) { if (!(expr.container is MemberAccess && expr.container.symbol_reference is Signal)) { base.visit_element_access (expr); return; } if (expr.parent_node is MethodCall) { // detailed signal emission unowned Signal sig = (Signal) expr.symbol_reference; unowned MemberAccess ma = (MemberAccess) expr.container; var detail_expr = expr.get_indices ().get (0); set_cvalue (expr, emit_signal (sig, ma, detail_expr)); } else { // signal connect or disconnect } } bool in_gobject_instance (Method m) { bool result = false; if (m.binding == MemberBinding.INSTANCE) { result = m.this_parameter.variable_type.type_symbol.is_subtype_of (gobject_type); } return result; } public override void visit_member_access (MemberAccess expr) { if (!(expr.symbol_reference is Signal)) { base.visit_member_access (expr); return; } unowned Signal sig = (Signal) expr.symbol_reference; set_cvalue (expr, emit_signal (sig, expr)); } CCodeExpression emit_signal (Signal sig, MemberAccess expr, Expression? detail_expr = null) { CCodeExpression pub_inst = null; if (expr.inner != null) { pub_inst = get_cvalue (expr.inner); } if (expr.inner is BaseAccess && sig.is_virtual) { var m = sig.default_handler; var base_class = (Class) m.parent_symbol; var vcast = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_class_type_function (base_class))); vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (get_ccode_lower_case_name (current_class)))); return new CCodeMemberAccess.pointer (vcast, m.name); } if (!sig.external_package && expr.source_reference.file == sig.source_reference.file && !(sig is DynamicSignal)) { var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit")); ccall.add_argument (pub_inst); ccall.add_argument (get_signal_id_cexpression (sig)); if (detail_expr == null) { ccall.add_argument (new CCodeConstant ("0")); } else { ccall.add_argument (get_detail_cexpression (detail_expr, expr)); } return ccall; } else if (get_ccode_has_emitter (sig)) { string emitter_func; if (sig.emitter != null) { if (!sig.external_package && expr.source_reference.file != sig.source_reference.file) { generate_method_declaration (sig.emitter, cfile); } emitter_func = get_ccode_lower_case_name (sig.emitter); } else { unowned TypeSymbol sym = (TypeSymbol) sig.parent_symbol; emitter_func = "%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_lower_case_name (sig)); } var ccall = new CCodeFunctionCall (new CCodeIdentifier (emitter_func)); ccall.add_argument (pub_inst); return ccall; } else { var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name")); ccall.add_argument (pub_inst); if (detail_expr == null) { ccall.add_argument (get_signal_canonical_constant (sig)); } else { ccall.add_argument (get_signal_name_cexpression (sig, detail_expr, expr)); } return ccall; } } public override void visit_method_call (MethodCall expr) { var method_type = expr.call.value_type as MethodType; if (method_type == null || !(method_type.method_symbol.parent_symbol is Signal)) { // no signal connect/disconnect call base.visit_method_call (expr); return; } var sig = (Signal) method_type.method_symbol.parent_symbol; var signal_access = ((MemberAccess) expr.call).inner; var handler = expr.get_argument_list ().get (0); bool disconnect = (method_type.method_symbol.name == "disconnect"); bool after = (method_type.method_symbol.name == "connect_after"); var cexpr = connect_signal (sig, signal_access, handler, disconnect, after, expr); set_cvalue (expr, cexpr); } CCodeExpression? connect_signal (Signal sig, Expression signal_access, Expression handler, bool disconnect, bool after, CodeNode expr) { string connect_func; DelegateType? dt = null; if (handler.symbol_reference is Variable) { dt = ((Variable) handler.symbol_reference).variable_type as DelegateType; if (dt != null && !context.experimental) { Report.warning (handler.source_reference, "Connecting delegates to signals is experimental"); } // Use actual lambda expression if available for proper target/destroy handling if (((Variable) handler.symbol_reference).initializer is LambdaExpression) { handler = ((Variable) handler.symbol_reference).initializer; dt = null; } } var m = handler.symbol_reference as Method; if (!disconnect) { // connect if (!(sig is DynamicSignal) && ((m != null && m.closure) || (dt != null && dt.value_owned))) { connect_func = "g_signal_connect_data"; } else if (m != null && in_gobject_instance (m)) { connect_func = "g_signal_connect_object"; } else if (!after) { connect_func = "g_signal_connect"; } else { connect_func = "g_signal_connect_after"; } } else { // disconnect if (sig is DynamicSignal) { connect_func = "VALA_UNSUPPORTED"; } else { connect_func = "g_signal_handlers_disconnect_matched"; } } var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func)); CCodeExpression signal_name_cexpr = null; // first argument: instance of sender MemberAccess ma; if (signal_access is ElementAccess) { var ea = (ElementAccess) signal_access; ma = (MemberAccess) ea.container; var detail_expr = ea.get_indices ().get (0); signal_name_cexpr = get_signal_name_cexpression (sig, detail_expr, expr); } else { ma = (MemberAccess) signal_access; signal_name_cexpr = get_signal_name_cexpression (sig, null, expr); } if (ma.inner != null) { ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner)); } else { ccall.add_argument (get_this_cexpression ()); } if (sig is DynamicSignal) { // dynamic_signal_connect or dynamic_signal_disconnect // second argument: signal name ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_ccode_name (sig)))); } else if (!disconnect) { // g_signal_connect_object or g_signal_connect // second argument: signal name ccall.add_argument (signal_name_cexpr); } else { // g_signal_handlers_disconnect_matched // second argument: mask if (!(signal_access is ElementAccess)) { ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA")); } else { ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA")); } // get signal id var temp_decl = get_temp_variable (uint_type); emit_temp_var (temp_decl); var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name")); parse_call.add_argument (signal_name_cexpr); var decl_type = (TypeSymbol) sig.parent_symbol; parse_call.add_argument (new CCodeIdentifier (get_ccode_type_id (decl_type))); parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (temp_decl.name))); LocalVariable? detail_temp_decl = null; if (!(signal_access is ElementAccess)) { parse_call.add_argument (new CCodeConstant ("NULL")); parse_call.add_argument (new CCodeConstant ("FALSE")); } else { detail_temp_decl = get_temp_variable (gquark_type); emit_temp_var (detail_temp_decl); parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression (detail_temp_decl.name))); parse_call.add_argument (new CCodeConstant ("TRUE")); } ccode.add_expression (parse_call); // third argument: signal_id ccall.add_argument (get_variable_cexpression (temp_decl.name)); // fourth argument: detail if (detail_temp_decl == null) { ccall.add_argument (new CCodeConstant ("0")); } else { ccall.add_argument (get_variable_cexpression (detail_temp_decl.name)); } // fifth argument: closure ccall.add_argument (new CCodeConstant ("NULL")); } // third resp. sixth argument: handler ccall.add_argument (new CCodeCastExpression (get_cvalue (handler), "GCallback")); if (m != null && m.closure) { // g_signal_connect_data // fourth argument: user_data CCodeExpression handler_destroy_notify; ccall.add_argument (get_delegate_target_cexpression (handler, out handler_destroy_notify)); // fifth argument: destroy_notify ccall.add_argument (new CCodeCastExpression (handler_destroy_notify, "GClosureNotify")); // sixth argument: connect_flags if (!after) ccall.add_argument (new CCodeConstant ("0")); else ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER")); } else if (m != null && m.binding == MemberBinding.INSTANCE) { // g_signal_connect_object or g_signal_handlers_disconnect_matched // or dynamic_signal_connect or dynamic_signal_disconnect // fourth resp. seventh argument: object/user_data if (handler is MemberAccess) { var right_ma = (MemberAccess) handler; if (right_ma.inner != null) { ccall.add_argument (get_cvalue (right_ma.inner)); } else { ccall.add_argument (get_this_cexpression ()); } } else if (handler is LambdaExpression) { ccall.add_argument (get_this_cexpression ()); } if (!disconnect && in_gobject_instance (m)) { // g_signal_connect_object // fifth argument: connect_flags if (!after) ccall.add_argument (new CCodeConstant ("0")); else ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER")); } } else if (dt != null && dt.delegate_symbol.has_target) { // fourth argument: user_data CCodeExpression handler_destroy_notify; ccall.add_argument (get_delegate_target_cexpression (handler, out handler_destroy_notify)); if (!disconnect && dt.value_owned) { // fifth argument: destroy_notify //FIXME handler_destroy_notify is NULL ccall.add_argument (new CCodeCastExpression (handler_destroy_notify, "GClosureNotify")); // sixth argument: connect_flags if (!after) ccall.add_argument (new CCodeConstant ("0")); else ccall.add_argument (new CCodeConstant ("G_CONNECT_AFTER")); } } else { // g_signal_connect or g_signal_connect_after or g_signal_handlers_disconnect_matched // or dynamic_signal_connect or dynamic_signal_disconnect // fourth resp. seventh argument: user_data ccall.add_argument (new CCodeConstant ("NULL")); } if (disconnect || expr.parent_node is ExpressionStatement) { ccode.add_expression (ccall); return null; } else { var temp_var = get_temp_variable (ulong_type); var temp_ref = get_variable_cexpression (temp_var.name); emit_temp_var (temp_var); ccode.add_assignment (temp_ref, ccall); return temp_ref; } } }