create wrapper functions for signal handlers to support public signal
authorJuerg Billeter <j@bitron.ch>
Wed, 6 Feb 2008 23:18:01 +0000 (23:18 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Wed, 6 Feb 2008 23:18:01 +0000 (23:18 +0000)
2008-02-07  Juerg Billeter  <j@bitron.ch>

* vala/valasemanticanalyzer.vala, vala/valasignal.vala,
  gobject/valaccodeassignmentbinding.vala,
  gobject/valaccodegenerator.vala,
  gobject/valaccodegeneratorinvocationexpression.vala,
  gobject/valaccodegeneratorsourcefile.vala,
  tests/classes-properties.vala, vapi/glib-2.0.vapi: create wrapper
  functions for signal handlers to support public signal handlers,
  fixes bug 508834

svn path=/trunk/; revision=983

ChangeLog
gobject/valaccodeassignmentbinding.vala
gobject/valaccodegenerator.vala
gobject/valaccodegeneratorinvocationexpression.vala
gobject/valaccodegeneratorsourcefile.vala
tests/classes-properties.vala
vala/valasemanticanalyzer.vala
vala/valasignal.vala
vapi/glib-2.0.vapi

index 4bb8dfe..99c43f3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2008-02-07  Jürg Billeter  <j@bitron.ch>
+
+       * vala/valasemanticanalyzer.vala, vala/valasignal.vala,
+         gobject/valaccodeassignmentbinding.vala,
+         gobject/valaccodegenerator.vala,
+         gobject/valaccodegeneratorinvocationexpression.vala,
+         gobject/valaccodegeneratorsourcefile.vala,
+         tests/classes-properties.vala, vapi/glib-2.0.vapi: create wrapper
+         functions for signal handlers to support public signal handlers,
+         fixes bug 508834
+
 2008-02-06  Jürg Billeter  <j@bitron.ch>
 
        * vala/parser.y, vala/valaarrayresizemethod.vala,
index c63fa94..765fca1 100644 (file)
@@ -195,7 +195,7 @@ public class Vala.CCodeAssignmentBinding : CCodeExpressionBinding {
                }
 
                // third resp. sixth argument: handler
-               ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (m.get_cname ()), "GCallback"));
+               ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier (generate_signal_handler_wrapper (m, sig)), "GCallback"));
 
                if (m.instance) {
                        // g_signal_connect_object or g_signal_handlers_disconnect_matched
@@ -296,6 +296,109 @@ public class Vala.CCodeAssignmentBinding : CCodeExpressionBinding {
                }
        }
 
+       private string generate_signal_handler_wrapper (Method m, Signal sig) {
+               string wrapper_name = "_%s_%s%s".printf (m.get_cname (), sig.parent_symbol.get_lower_case_cprefix (), sig.get_cname ());
+
+               if (!codegen.add_wrapper (wrapper_name)) {
+                       // wrapper already defined
+                       return wrapper_name;
+               }
+
+               // declaration
+
+               var function = new CCodeFunction (wrapper_name, m.return_type.get_cname ());
+               function.modifiers = CCodeModifiers.STATIC;
+               m.ccodenode = function;
+
+               var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+
+               var cparam = new CCodeFormalParameter ("self", "gpointer");
+               cparam_map.set (codegen.get_param_pos (-1), cparam);
+
+               cparam = new CCodeFormalParameter ("sender", ((Typesymbol) sig.parent_symbol).get_cname () + "*");
+               cparam_map.set (codegen.get_param_pos (0), cparam);
+
+               var sig_params = sig.get_parameters ();
+               foreach (FormalParameter param in sig_params) {
+                       // ensure that C code node has been generated
+                       param.accept (codegen);
+
+                       cparam_map.set (codegen.get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
+               }
+
+               // append C parameters in the right order
+               int last_pos = -1;
+               int min_pos;
+               while (true) {
+                       min_pos = -1;
+                       foreach (int pos in cparam_map.get_keys ()) {
+                               if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+                                       min_pos = pos;
+                               }
+                       }
+                       if (min_pos == -1) {
+                               break;
+                       }
+                       function.add_parameter (cparam_map.get (min_pos));
+                       last_pos = min_pos;
+               }
+
+
+               // definition
+
+               var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+
+               if (m.instance) {
+                       carg_map.set (codegen.get_param_pos (m.cinstance_parameter_position), new CCodeIdentifier ("self"));
+               }
+
+               int i = -1;
+               foreach (FormalParameter param in m.get_parameters ()) {
+                       CCodeExpression arg;
+                       if (i < 0) {
+                               arg = new CCodeIdentifier ("sender");
+                       } else {
+                               arg = new CCodeIdentifier (sig_params.get (i).name);
+                       }
+                       carg_map.set (codegen.get_param_pos (param.cparameter_position), arg);
+                       i++;
+               }
+
+               var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
+
+               // append C arguments in the right order
+               last_pos = -1;
+               while (true) {
+                       min_pos = -1;
+                       foreach (int pos in carg_map.get_keys ()) {
+                               if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+                                       min_pos = pos;
+                               }
+                       }
+                       if (min_pos == -1) {
+                               break;
+                       }
+                       ccall.add_argument (carg_map.get (min_pos));
+                       last_pos = min_pos;
+               }
+
+               var block = new CCodeBlock ();
+               if (m.return_type is VoidType) {
+                       block.add_statement (new CCodeExpressionStatement (ccall));
+               } else {
+                       block.add_statement (new CCodeReturnStatement (ccall));
+               }
+
+               // append to file
+
+               codegen.source_type_member_declaration.append (function.copy ());
+
+               function.block = block;
+               codegen.source_type_member_definition.append (function);
+
+               return wrapper_name;
+       }
+
        private void emit_non_array_element_access () {
                // custom element access
                CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
index 776dd0d..4719bd5 100644 (file)
@@ -45,9 +45,9 @@ public class Vala.CCodeGenerator : CodeGenerator {
        CCodeFragment header_type_member_declaration;
        CCodeFragment source_begin;
        CCodeFragment source_include_directives;
-       CCodeFragment source_type_member_declaration;
+       public CCodeFragment source_type_member_declaration;
        CCodeFragment source_signal_marshaller_declaration;
-       CCodeFragment source_type_member_definition;
+       public CCodeFragment source_type_member_definition;
        CCodeFragment class_init_fragment;
        CCodeFragment instance_init_fragment;
        CCodeFragment instance_dispose_fragment;
@@ -121,6 +121,8 @@ public class Vala.CCodeGenerator : CodeGenerator {
        private bool requires_array_move;
        private bool requires_strcmp0;
 
+       private Set<string> wrappers;
+
        public CCodeGenerator () {
        }
        
@@ -3108,6 +3110,10 @@ public class Vala.CCodeGenerator : CodeGenerator {
                return ccomma;
        }
 
+       public bool add_wrapper (string wrapper_name) {
+               return wrappers.add (wrapper_name);
+       }
+
        public override CodeBinding create_namespace_binding (Namespace! node) {
                return null;
        }
index b38a82a..97d0fdb 100644 (file)
@@ -539,7 +539,7 @@ public class Vala.CCodeGenerator {
                return carray_type;
        }
 
-       private int get_param_pos (double param_pos, bool ellipsis = false) {
+       public int get_param_pos (double param_pos, bool ellipsis = false) {
                if (!ellipsis) {
                        if (param_pos >= 0) {
                                return (int) (param_pos * 1000);
index 40ff080..c04bb15 100644 (file)
@@ -193,7 +193,9 @@ public class Vala.CCodeGenerator {
                requires_array_free = false;
                requires_array_move = false;
                requires_strcmp0 = false;
-               
+
+               wrappers = new HashSet<string> (str_hash, str_equal);
+
                header_begin.append (new CCodeIncludeDirective ("glib.h"));
                header_begin.append (new CCodeIncludeDirective ("glib-object.h"));
                if (context.basedir != null || context.library != null) {
index 922e37a..b35440e 100644 (file)
@@ -1,18 +1,13 @@
 using GLib;
 
 public class Sample : Object {
-       private string automatic {
-               get; set;
-       }
+       private string automatic { get; set; }
 
        private string _name;
+       [Notify]
        public string name {
                get { return _name; }
-
-               set {
-                       _name = value;
-                       notify("name");
-               }
+               set { _name = value; }
        }
 
        private string _read_only;
@@ -30,12 +25,8 @@ public class Sample : Object {
 
        public void run() {
                notify += (s, p) => {
-                       /* FIXME Cast needed as signatures conflict for the 
-                        * notify method and the notify signal of GObject.
-                        * See Bug 473804.
-                        */
                        stdout.printf("property `%s' has changed!\n",
-                                     ((ParamSpec) p).name);
+                                     p.name);
                };
 
 
index 7995452..a05edcf 100644 (file)
@@ -2768,26 +2768,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                                        Report.error (a.right.source_reference, "unsupported expression for signal handler");
                                        return;
                                }
-
-                               var m = (Method) a.right.symbol_reference;
-
-                               if (m.instance && m.access != SymbolAccessibility.PRIVATE) {
-                                       /* TODO: generate wrapper function */
-
-                                       ma.error = true;
-                                       Report.error (a.right.source_reference, "public instance methods not yet supported as signal handlers");
-                                       return;
-                               }
-
-                               if (m.instance) {
-                                       /* instance signal handlers must have the self
-                                        * parameter at the end
-                                        * do not use G_CONNECT_SWAPPED as this would
-                                        * rearrange the parameters for instance
-                                        * methods and non-instance methods
-                                        */
-                                       m.cinstance_parameter_position = -1;
-                               }
                        } else if (ma.symbol_reference is Property) {
                                var prop = (Property) ma.symbol_reference;
 
index f22015c..17304e4 100644 (file)
@@ -69,12 +69,15 @@ public class Vala.Signal : Member, Lockable {
         * @param param a formal parameter
         */
        public void add_parameter (FormalParameter! param) {
+               // default C parameter position
+               param.cparameter_position = parameters.size + 1;
+
                parameters.add (param);
                scope.add (param.name, param);
        }
 
-       public Collection<FormalParameter> get_parameters () {
-               return new ReadOnlyCollection<FormalParameter> (parameters);
+       public Gee.List<FormalParameter> get_parameters () {
+               return new ReadOnlyList<FormalParameter> (parameters);
        }
 
        /**
index 69d148e..28e48e1 100644 (file)
@@ -735,13 +735,7 @@ namespace GLib {
                public virtual void finalize ();
                public virtual void constructed ();
 
-               /* FIXME The notify passes a ParamSpec where the
-                * wrapper expects a string. Fortunatly Vala doesn't
-                * verify signatures of signal handlers yet.
-                * See Bug 473804.
-                */
-               [HasEmitter]
-               public signal void notify(string! property_name);
+               public signal void notify (ParamSpec pspec);
 
                public weak Object connect (string! signal_spec, ...);
        }