From 3dc782adc709644a5fe4b94f427c24757989023b Mon Sep 17 00:00:00 2001 From: Rico Tzschichholz Date: Thu, 22 Oct 2020 11:02:57 +0200 Subject: gtkmodule: Support "binding" to bind GtkCallback to class of given property Fixes https://gitlab.gnome.org/GNOME/vala/issues/1093 --- codegen/valagtkmodule.vala | 46 ++++++++++++++++++++++++++++++++++++-- tests/gtktemplate/gtktemplate.ui | 11 +++++++++ tests/gtktemplate/gtktemplate.vala | 7 ++++++ 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/codegen/valagtkmodule.vala b/codegen/valagtkmodule.vala index 2f3431653..f78b39203 100644 --- a/codegen/valagtkmodule.vala +++ b/codegen/valagtkmodule.vala @@ -30,6 +30,8 @@ public class Vala.GtkModule : GSignalModule { /* GResource name to real file name mapping */ private HashMap gresource_to_file_map = null; /* GtkBuilder xml handler to Vala signal mapping */ + private HashMap current_handler_to_property_map = new HashMap(str_hash, str_equal); + /* GtkBuilder xml handler to Vala signal mapping */ private HashMap current_handler_to_signal_map = new HashMap(str_hash, str_equal); /* GtkBuilder xml child to Vala class mapping */ private HashMap current_child_to_class_map = new HashMap(str_hash, str_equal); @@ -145,6 +147,7 @@ public class Vala.GtkModule : GSignalModule { MarkupReader reader = new MarkupReader (ui_file); Class current_class = null; + Property? current_property = null; bool template_tag_found = false; MarkupTokenType current_token = reader.read_token (null, null); @@ -199,6 +202,35 @@ public class Vala.GtkModule : GSignalModule { current_handler_to_signal_map.set (handler_name, sig); } } + } else if (current_class != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "binding") { + var property_name = reader.get_attribute ("name"); + if (property_name == null) { + Report.error (node.source_reference, "Invalid binding in ui file `%s'".printf (ui_file)); + current_token = reader.read_token (null, null); + continue; + } + + property_name = property_name.replace ("-", "_"); + current_property = SemanticAnalyzer.symbol_lookup_inherited (current_class, property_name) as Property; + if (current_property == null) { + Report.error (node.source_reference, "Unknown property `%s:%s' for binding in ui file `%s'".printf (current_class.get_full_name (), property_name, ui_file)); + current_token = reader.read_token (null, null); + continue; + } + } else if (current_class != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "closure") { + var handler_name = reader.get_attribute ("function"); + + if (current_property != null) { + if (handler_name == null) { + Report.error (node.source_reference, "Invalid closure in ui file `%s'".printf (ui_file)); + current_token = reader.read_token (null, null); + continue; + } + + //TODO Retrieve signature declaration? c-type to vala-type? + current_handler_to_property_map.set (handler_name, current_property); + current_property = null; + } } current_token = reader.read_token (null, null); } @@ -337,8 +369,9 @@ public class Vala.GtkModule : GSignalModule { /* Handler name as defined in the gtkbuilder xml */ var handler_name = m.get_attribute_string ("GtkCallback", "name", m.name); var sig = current_handler_to_signal_map.get (handler_name); - if (sig == null) { - Report.error (m.source_reference, "could not find signal for handler `%s'".printf (handler_name)); + var prop = current_handler_to_property_map.get (handler_name); + if (sig == null && prop == null) { + Report.error (m.source_reference, "could not find signal or property for handler `%s'".printf (handler_name)); return; } @@ -361,6 +394,15 @@ public class Vala.GtkModule : GSignalModule { ccode.add_expression (call); } } + if (prop != null) { + prop.check (context); + //TODO Perform signature check + var call = new CCodeFunctionCall (new CCodeIdentifier ("gtk_widget_class_bind_template_callback_full")); + call.add_argument (new CCodeIdentifier ("GTK_WIDGET_CLASS (klass)")); + call.add_argument (new CCodeConstant ("\"%s\"".printf (handler_name))); + call.add_argument (new CCodeIdentifier ("G_CALLBACK(%s)".printf (get_ccode_name (m)))); + ccode.add_expression (call); + } pop_context (); } diff --git a/tests/gtktemplate/gtktemplate.ui b/tests/gtktemplate/gtktemplate.ui index 1546d9472..df9ca019d 100644 --- a/tests/gtktemplate/gtktemplate.ui +++ b/tests/gtktemplate/gtktemplate.ui @@ -42,6 +42,17 @@ 1 + + + + + some string + 42 + GtkTemplateTest + + + + diff --git a/tests/gtktemplate/gtktemplate.vala b/tests/gtktemplate/gtktemplate.vala index fa6317ff0..5f66ccc21 100644 --- a/tests/gtktemplate/gtktemplate.vala +++ b/tests/gtktemplate/gtktemplate.vala @@ -6,6 +6,8 @@ public class GtkTemplate : Gtk.ApplicationWindow { [GtkChild (internal = true)] public Gtk.Button button1; + public bool boolean0 { get; set; } + [GtkCallback] void on_clicked_cb (Gtk.Button button) { } @@ -13,4 +15,9 @@ public class GtkTemplate : Gtk.ApplicationWindow { [GtkCallback (name = "on_activate_cb")] void on_something_cb (Gtk.Button button) { } + + [GtkCallback] + string on_enabled_cb (string s, int i, bool val) { + return "%s:%i".printf (s, i); + } } -- cgit v1.2.1