From 5da90d7c5bfe9a977720221717c774300c24484c Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Fri, 7 Aug 2020 18:54:51 +0200 Subject: [PATCH] codegen: Support non-virtual signals with default handler Fixes https://gitlab.gnome.org/GNOME/vala/issues/1056 --- codegen/valaccodeattribute.vala | 2 +- codegen/valagsignalmodule.vala | 11 +++++++-- codegen/valagtypemodule.vala | 22 ++++++++++++++---- tests/Makefile.am | 1 + .../signals-default-class-handler.vala | 23 +++++++++++++++++++ vala/valasignal.vala | 13 +++-------- 6 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 tests/objects/signals-default-class-handler.vala diff --git a/codegen/valaccodeattribute.vala b/codegen/valaccodeattribute.vala index 935810d2a..c73d124c0 100644 --- a/codegen/valaccodeattribute.vala +++ b/codegen/valaccodeattribute.vala @@ -1437,7 +1437,7 @@ public class Vala.CCodeAttribute : AttributeCache { } } else if (sym is Method) { unowned Method m = (Method) sym; - if (m.base_method != null || m.base_interface_method != null) { + if (m.base_method != null || m.base_interface_method != null || m.signal_reference != null) { string m_name; if (m.signal_reference != null) { m_name = get_ccode_lower_case_name (m.signal_reference); diff --git a/codegen/valagsignalmodule.vala b/codegen/valagsignalmodule.vala index 108622815..e005f6b38 100644 --- a/codegen/valagsignalmodule.vala +++ b/codegen/valagsignalmodule.vala @@ -347,7 +347,12 @@ public class Vala.GSignalModule : GObjectModule { } public override CCodeExpression get_signal_creation (Signal sig, TypeSymbol type) { - var csignew = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_new")); + 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]; @@ -383,7 +388,7 @@ public class Vala.GSignalModule : GObjectModule { if (sig.default_handler == null) { csignew.add_argument (new CCodeConstant ("0")); - } else { + } else if (sig.is_virtual) { var struct_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET")); if (type is Class) { struct_offset.add_argument (new CCodeIdentifier ("%sClass".printf (get_ccode_name (type)))); @@ -393,6 +398,8 @@ public class Vala.GSignalModule : GObjectModule { } 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")); diff --git a/codegen/valagtypemodule.vala b/codegen/valagtypemodule.vala index 8b2c6c03d..88a1cd14b 100644 --- a/codegen/valagtypemodule.vala +++ b/codegen/valagtypemodule.vala @@ -271,7 +271,11 @@ public class Vala.GTypeModule : GErrorModule { } else if (s is Signal) { var sig = (Signal) s; if (sig.default_handler != null) { - generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct); + if (sig.is_virtual) { + generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct); + } else { + generate_method_declaration (sig.default_handler, cfile); + } } } else if (s is Property) { var prop = (Property) s; @@ -291,7 +295,11 @@ public class Vala.GTypeModule : GErrorModule { foreach (Signal sig in cl.get_signals ()) { if (sig.default_handler != null) { - generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct); + if (sig.is_virtual) { + generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct); + } else { + generate_method_declaration (sig.default_handler, cfile); + } } } @@ -1281,7 +1289,7 @@ public class Vala.GTypeModule : GErrorModule { /* connect default signal handlers */ foreach (Signal sig in cl.get_signals ()) { - if (sig.default_handler == null) { + if (sig.default_handler == null || !sig.is_virtual) { continue; } generate_method_declaration (sig.default_handler, cfile); @@ -2118,7 +2126,11 @@ public class Vala.GTypeModule : GErrorModule { generate_struct_method_declaration (iface, m, instance_struct, type_struct, decl_space, ref has_struct_member); } else if ((sig = sym as Signal) != null) { if (sig.default_handler != null) { - generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct); + if (sig.is_virtual) { + generate_virtual_method_declaration (sig.default_handler, decl_space, type_struct); + } else { + generate_method_declaration (sig.default_handler, cfile); + } } } else if ((prop = sym as Property) != null) { generate_struct_property_declaration (iface, prop, instance_struct, type_struct, decl_space, ref has_struct_member); @@ -2222,7 +2234,7 @@ public class Vala.GTypeModule : GErrorModule { /* connect default signal handlers */ foreach (Signal sig in iface.get_signals ()) { - if (sig.default_handler == null) { + if (sig.default_handler == null || !sig.is_virtual) { continue; } var cname = get_ccode_real_name (sig.default_handler); diff --git a/tests/Makefile.am b/tests/Makefile.am index b28a2a45f..e98e4dca6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -436,6 +436,7 @@ TESTS = \ objects/sealed-class.test \ objects/sealed-compact-class.test \ objects/signals.vala \ + objects/signals-default-class-handler.vala \ objects/signals-enum-marshal.vala \ objects/signals-delegate.vala \ objects/signals-delegate-parameter.vala \ diff --git a/tests/objects/signals-default-class-handler.vala b/tests/objects/signals-default-class-handler.vala new file mode 100644 index 000000000..aff938726 --- /dev/null +++ b/tests/objects/signals-default-class-handler.vala @@ -0,0 +1,23 @@ +bool success = false; +bool success2 = false; + +class Foo { + public signal void foo () { + success = true; + } + + [HasEmitter] + public signal void foo_with_emitter () { + success2 = true; + } +} + +void main () { + var foo = new Foo (); + + foo.foo (); + assert (success); + + foo.foo_with_emitter (); + assert (success2); +} diff --git a/vala/valasignal.vala b/vala/valasignal.vala index 392b31489..df7d76199 100644 --- a/vala/valasignal.vala +++ b/vala/valasignal.vala @@ -222,24 +222,17 @@ public class Vala.Signal : Symbol, Callable { } } - if (!is_virtual && body != null) { - error = true; - Report.error (source_reference, "Only virtual signals can have a default signal handler body"); - } - - - if (is_virtual) { + if (body != null || (is_virtual && external_package)) { default_handler = new Method (name, return_type, source_reference); default_handler.owner = owner; - default_handler.access = access; + default_handler.access = (is_virtual ? access : SymbolAccessibility.PRIVATE); default_handler.external = external; default_handler.hides = hides; - default_handler.is_virtual = true; + default_handler.is_virtual = is_virtual; default_handler.signal_reference = this; default_handler.body = body; - foreach (Parameter param in parameters) { default_handler.add_parameter (param); } -- 2.47.2