[vala/staging] gtkmodule: Support "binding" to bind GtkCallback to class of given property



commit 3dc782adc709644a5fe4b94f427c24757989023b
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Thu Oct 22 11:02:57 2020 +0200

    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<string, string> gresource_to_file_map = null;
        /* GtkBuilder xml handler to Vala signal mapping */
+       private HashMap<string, Property> current_handler_to_property_map = new HashMap<string, 
Property>(str_hash, str_equal);
+       /* GtkBuilder xml handler to Vala signal mapping */
        private HashMap<string, Signal> current_handler_to_signal_map = new HashMap<string, Signal>(str_hash, 
str_equal);
        /* GtkBuilder xml child to Vala class mapping */
        private HashMap<string, Class> current_child_to_class_map = new HashMap<string, Class>(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 @@
             <property name="position">1</property>
           </packing>
         </child>
+        <child>
+          <object class="GtkLabel" id="label0">
+            <binding name="label">
+              <closure type="gchararray" function="on_enabled_cb">
+                <constant type="gchararray">some string</constant>
+                <constant type="gint">42</constant>
+                <lookup name="boolean0">GtkTemplateTest</lookup>
+              </closure>
+            </binding>
+          </object>
+        </child>
       </object>
     </child>
   </template>
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);
+       }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]