]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
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 4bb8dfe77bd3b247999a04715c4aaac5826674fe..99c43f32949308ab8034df26e6a135a50dbd0900 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 c63fa94c524affddd5f4260047e7aa0d787d1e33..765fca151697a6b85a9e62a759f117b5618b6cad 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 776dd0d5f385d5fa9a45249322f80048b114a425..4719bd54aa624d82ab77a42ace3d6a67bd1bc73c 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 b38a82a90c07a3becba0d515416020b2bb2822f6..97d0fdb2959a6501a1e444a30a96101babf2e663 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 40ff0804b90d342544e576ef798db418f5fc5ea3..c04bb1517f9769ac1a60dfb16671342e4d0d7c8c 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 922e37a7ea41306e90de74465d8f3bd08aeb5d77..b35440ed1d0e1a76f99078f384572ce12fecf587 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 7995452a7e37caafcdfa01b7497bd5f4914af531..a05edcf2d7c2b906956eb32d6ffb7bcf3e9558a7 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 f22015c9e1742191fab3ef0ee74a65fab623df9b..17304e43304056e8f8cea408fe916e65ed8d8e49 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 69d148e039d184e7c42fd8b5d138c019ea6bfdf8..28e48e1933b85e855a8c4b6ffcd4ebfa8cf559ce 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, ...);
        }