From: Jürg Billeter Date: Tue, 28 Jul 2009 15:20:37 +0000 (+0200) Subject: Support virtual default handler for signals X-Git-Tag: 0.7.5~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9b37307b035e75c858ed648728db83a8bc70a4c8;p=thirdparty%2Fvala.git Support virtual default handler for signals Based on patch by Yu Feng, fixes part of 571685. --- diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala index 8fc87db1b..4cf641d4e 100644 --- a/codegen/valaccodemethodcallmodule.vala +++ b/codegen/valaccodemethodcallmodule.vala @@ -53,7 +53,7 @@ internal class Vala.CCodeMethodCallModule : CCodeAssignmentModule { } else if (itype is SignalType) { var sig_type = (SignalType) itype; if (ma != null && ma.inner is BaseAccess && sig_type.signal_symbol.is_virtual) { - m = sig_type.signal_symbol.get_method_handler (); + m = sig_type.signal_symbol.default_handler; } else { ccall = (CCodeFunctionCall) expr.call.ccodenode; } diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala index d76fbce16..d8342a6f1 100644 --- a/codegen/valaccodemethodmodule.vala +++ b/codegen/valaccodemethodmodule.vala @@ -599,7 +599,12 @@ internal class Vala.CCodeMethodModule : CCodeStructModule { } } - if ((m.is_abstract || m.is_virtual) && !m.coroutine) { + if ((m.is_abstract || m.is_virtual) && !m.coroutine && + /* If the method is a signal handler, the declaration + * is not needed. -- the name should be reserved for the + * emitter! */ + m.signal_reference == null) { + cparam_map = new HashMap (direct_hash, direct_equal); var carg_map = new HashMap (direct_hash, direct_equal); diff --git a/codegen/valagsignalmodule.vala b/codegen/valagsignalmodule.vala index f4ed94d70..fe7c86499 100644 --- a/codegen/valagsignalmodule.vala +++ b/codegen/valagsignalmodule.vala @@ -355,10 +355,18 @@ internal class Vala.GSignalModule : GObjectModule { public override CCodeFunctionCall get_signal_creation (Signal sig, TypeSymbol type) { var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new")); + var cl = sig.parent_symbol as Class; csignew.add_argument (new CCodeConstant ("\"%s\"".printf (sig.get_cname ()))); csignew.add_argument (new CCodeIdentifier (type.get_type_id ())); csignew.add_argument (new CCodeConstant ("G_SIGNAL_RUN_LAST")); - csignew.add_argument (new CCodeConstant ("0")); + if (sig.default_handler == null) { + csignew.add_argument (new CCodeConstant ("0")); + } else { + var struct_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET")); + struct_offset.add_argument (new CCodeIdentifier ("%sClass".printf (cl.get_cname ()))); + struct_offset.add_argument (new CCodeIdentifier (sig.default_handler.vfunc_name)); + csignew.add_argument (struct_offset); + } csignew.add_argument (new CCodeConstant ("NULL")); csignew.add_argument (new CCodeConstant ("NULL")); @@ -608,7 +616,7 @@ internal class Vala.GSignalModule : GObjectModule { var cl = (TypeSymbol) sig.parent_symbol; if (expr.inner is BaseAccess && sig.is_virtual) { - var m = sig.get_method_handler (); + var m = sig.default_handler; var base_class = (Class) m.parent_symbol; var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null)))); vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null)))); diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala index e5bf70e53..81573a690 100644 --- a/codegen/valagtypemodule.vala +++ b/codegen/valagtypemodule.vala @@ -206,6 +206,12 @@ internal class Vala.GTypeModule : GErrorModule { generate_virtual_method_declaration (m, decl_space, type_struct); } + foreach (Signal sig in cl.get_signals ()) { + if (sig.default_handler != null) { + generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct); + } + } + foreach (Property prop in cl.get_properties ()) { if (!prop.is_abstract && !prop.is_virtual) { continue; @@ -1140,6 +1146,16 @@ internal class Vala.GTypeModule : GErrorModule { init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.base_method.vfunc_name), new CCodeIdentifier (m.get_real_cname ())))); } + /* connect default signal handlers */ + foreach (Signal sig in cl.get_signals ()) { + if (sig.default_handler == null) { + continue; + } + var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null)))); + ccast.add_argument (new CCodeIdentifier ("klass")); + init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, sig.default_handler.vfunc_name), new CCodeIdentifier (sig.default_handler.get_real_cname ())))); + } + /* connect overridden properties */ foreach (Property prop in cl.get_properties ()) { if (prop.base_property == null) { diff --git a/vala/valamethod.vala b/vala/valamethod.vala index 5fa7dd08b..79e9d5c00 100644 --- a/vala/valamethod.vala +++ b/vala/valamethod.vala @@ -593,7 +593,7 @@ public class Vala.Method : Member { } else if (sym is Signal) { var sig = (Signal) sym; if (sig.is_virtual) { - var base_method = sig.get_method_handler (); + var base_method = sig.default_handler; string invalid_match; if (!compatible (base_method, out invalid_match)) { error = true; diff --git a/vala/valaparser.vala b/vala/valaparser.vala index 88dacd545..93e5cbf32 100644 --- a/vala/valaparser.vala +++ b/vala/valaparser.vala @@ -2390,7 +2390,10 @@ public class Vala.Parser : CodeVisitor { } while (accept (TokenType.COMMA)); } expect (TokenType.CLOSE_PARENS); - expect (TokenType.SEMICOLON); + if (!accept (TokenType.SEMICOLON)) { + sig.body = parse_block (); + } + return sig; } diff --git a/vala/valasignal.vala b/vala/valasignal.vala index 9b85e89b9..3a69f598f 100644 --- a/vala/valasignal.vala +++ b/vala/valasignal.vala @@ -38,6 +38,16 @@ public class Vala.Signal : Member, Lockable { } } + public Block body { + get { return _body; } + set { + _body = value; + if (_body != null) { + _body.owner = scope; + } + } + } + /** * Specifies whether this signal has an emitter wrapper function. */ @@ -49,7 +59,11 @@ public class Vala.Signal : Member, Lockable { public bool is_virtual { get; set; } private Gee.List parameters = new ArrayList (); - private Method generated_method; + /** + * Refers to the default signal handler, which is an anonymous + * function in the scope. + * */ + public Method default_handler { get; private set; } private string cname; @@ -57,6 +71,8 @@ public class Vala.Signal : Member, Lockable { private DataType _return_type; + private Block _body; + /** * Creates a new signal. * @@ -179,6 +195,9 @@ public class Vala.Signal : Member, Lockable { foreach (FormalParameter param in parameters) { param.accept (visitor); } + if (default_handler != null) { + default_handler.accept (visitor); + } } /** @@ -206,26 +225,6 @@ public class Vala.Signal : Member, Lockable { } } - public Method get_method_handler () { - assert (is_virtual); - - if (generated_method == null) { - generated_method = new Method (name, return_type, source_reference); - generated_method.access = access; - generated_method.is_virtual = true; - generated_method.vfunc_name = name; - generated_method.signal_reference = this; - - foreach (FormalParameter param in parameters) { - generated_method.add_parameter (param); - } - - parent_symbol.scope.add (null, generated_method); - } - - return generated_method; - } - public override bool check (SemanticAnalyzer analyzer) { if (checked) { return !error; @@ -241,6 +240,26 @@ public class Vala.Signal : Member, Lockable { param.check (analyzer); } + if (!is_virtual && body != null) { + Report.error (source_reference, "Only virtual signals can have a default signal handler body"); + } + + + if (is_virtual) { + default_handler = new Method (name, return_type, source_reference); + default_handler.access = access; + default_handler.is_virtual = true; + default_handler.vfunc_name = name; + default_handler.signal_reference = this; + default_handler.body = body; + + foreach (FormalParameter param in parameters) { + default_handler.add_parameter (param); + } + + parent_symbol.scope.add (null, default_handler); + default_handler.check (analyzer); + } return !error; } }