+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,
}
// 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
}
}
+ 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;
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;
private bool requires_array_move;
private bool requires_strcmp0;
+ private Set<string> wrappers;
+
public CCodeGenerator () {
}
return ccomma;
}
+ public bool add_wrapper (string wrapper_name) {
+ return wrappers.add (wrapper_name);
+ }
+
public override CodeBinding create_namespace_binding (Namespace! node) {
return null;
}
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);
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) {
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;
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);
};
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;
* @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);
}
/**
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, ...);
}