LCOV - code coverage report
Current view: top level - codegen - valagtkmodule.vala (source / functions) Coverage Total Hit
Test: vala 0.57.0.298-a8cae1 Lines: 85.9 % 313 269
Test Date: 2024-04-25 11:34:36 Functions: - 0 0

            Line data    Source code
       1              : /* valagtkmodule.vala
       2              :  *
       3              :  * Copyright (C) 2013  Jürg Billeter
       4              :  * Copyright (C) 2013-2014  Luca Bruno
       5              :  *
       6              :  * This library is free software; you can redistribute it and/or
       7              :  * modify it under the terms of the GNU Lesser General Public
       8              :  * License as published by the Free Software Foundation; either
       9              :  * version 2.1 of the License, or (at your option) any later version.
      10              : 
      11              :  * This library is distributed in the hope that it will be useful,
      12              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14              :  * Lesser General Public License for more details.
      15              : 
      16              :  * You should have received a copy of the GNU Lesser General Public
      17              :  * License along with this library; if not, write to the Free Software
      18              :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
      19              :  *
      20              :  * Author:
      21              :  *      Luca Bruno <lucabru@src.gnome.org>
      22              :  */
      23              : 
      24              : 
      25         5828 : public class Vala.GtkModule : GSignalModule {
      26              : 
      27            1 :         class InvalidClass : Class {
      28            3 :                 public InvalidClass (string name) {
      29            1 :                         base (name, null, null);
      30            1 :                         error = true;
      31              :                 }
      32            0 :                 public override bool check (CodeContext context) {
      33              :                         return false;
      34              :                 }
      35              :         }
      36              : 
      37            8 :         class InvalidProperty : Property {
      38          111 :                 public InvalidProperty (string name) {
      39           37 :                         base (name, null, null, null);
      40           37 :                         error = true;
      41              :                 }
      42            0 :                 public override bool check (CodeContext context) {
      43              :                         return false;
      44              :                 }
      45              :         }
      46              : 
      47              :         /* C type-func name to Vala class mapping */
      48         1457 :         private HashMap<string, Class> type_id_to_vala_map = null;
      49              :         /* C class name to Vala class mapping */
      50         1457 :         private HashMap<string, Class> cclass_to_vala_map = null;
      51              :         /* GResource name to real file name mapping */
      52         1457 :         private HashMap<string, string> gresource_to_file_map = null;
      53              :         /* GtkBuilder xml handler set */
      54         2914 :         private HashMap<string, string> handler_map = new HashMap<string, string>(str_hash, str_equal);
      55              :         /* GtkBuilder xml handler to Vala property mapping */
      56         2914 :         private HashMap<string, Property> current_handler_to_property_map = new HashMap<string, Property>(str_hash, str_equal);
      57              :         /* GtkBuilder xml handler to Vala signal mapping */
      58         2914 :         private HashMap<string, Signal> current_handler_to_signal_map = new HashMap<string, Signal>(str_hash, str_equal);
      59              :         /* GtkBuilder xml child to Vala class mapping */
      60         2914 :         private HashMap<string, Class> current_child_to_class_map = new HashMap<string, Class>(str_hash, str_equal);
      61              :         /* Required custom application-specific gtype classes to be ref'd before initializing the template */
      62         2914 :         private List<Class> current_required_app_classes = new ArrayList<Class>();
      63              : 
      64              :         /* Stack of occuring object elements in the template */
      65         2914 :         List<Class> current_object_stack = new ArrayList<Class> ();
      66         1457 :         Class? current_object;
      67              : 
      68           40 :         void push_object (Class cl) {
      69           40 :                 current_object_stack.add (current_object);
      70        11613 :                 current_object = cl;
      71              :         }
      72              : 
      73           40 :         void pop_object () {
      74           40 :                 current_object = current_object_stack.remove_at (current_object_stack.size - 1);
      75              :         }
      76              : 
      77              :         /* Stack of occuring property elements in the template */
      78         2914 :         List<Property> current_property_stack = new ArrayList<Property> ();
      79         1457 :         Property? current_property;
      80              : 
      81          168 :         void push_property (Property prop) {
      82          168 :                 current_property_stack.add (current_property);
      83          168 :                 current_property = prop;
      84              :         }
      85              : 
      86          168 :         void pop_property () {
      87          168 :                 current_property = current_property_stack.remove_at (current_property_stack.size - 1);
      88              :         }
      89              : 
      90            8 :         private void ensure_type_id_to_vala_map () {
      91              :                 // map C type-func name of gtypeinstance classes to Vala classes
      92            8 :                 if (type_id_to_vala_map != null) {
      93              :                         return;
      94              :                 }
      95            8 :                 type_id_to_vala_map = new HashMap<string, Class>(str_hash, str_equal);
      96            8 :                 recurse_type_id_to_vala_map (context.root);
      97              :         }
      98              : 
      99         5952 :         private void recurse_type_id_to_vala_map (Symbol sym) {
     100              :                 unowned List<Class> classes;
     101         5952 :                 if (sym is Namespace) {
     102         1328 :                         foreach (var inner in ((Namespace) sym).get_namespaces()) {
     103          440 :                                 recurse_type_id_to_vala_map (inner);
     104              :                         }
     105          448 :                         classes = ((Namespace) sym).get_classes ();
     106         5504 :                 } else if (sym is ObjectTypeSymbol) {
     107         5504 :                         classes = ((ObjectTypeSymbol) sym).get_classes ();
     108              :                 } else {
     109              :                         return;
     110              :                 }
     111        16960 :                 foreach (var cl in classes) {
     112         9112 :                         if (!cl.is_compact) {
     113         3608 :                                 var type_id = get_ccode_type_id (cl);
     114         3608 :                                 if (type_id == null)
     115            0 :                                         continue;
     116              : 
     117         3608 :                                 var i = type_id.index_of_char ('(');
     118         3608 :                                 if (i > 0) {
     119         3352 :                                         type_id = type_id.substring (0, i - 1).strip ();
     120              :                                 } else {
     121          256 :                                         type_id = type_id.strip ();
     122              :                                 }
     123         3608 :                                 type_id_to_vala_map.set (type_id, cl);
     124              :                         }
     125         5504 :                         recurse_type_id_to_vala_map (cl);
     126              :                 }
     127              :         }
     128              : 
     129            8 :         private void ensure_cclass_to_vala_map () {
     130              :                 // map C name of gtypeinstance classes to Vala classes
     131            8 :                 if (cclass_to_vala_map != null) {
     132              :                         return;
     133              :                 }
     134            8 :                 cclass_to_vala_map = new HashMap<string, Class>(str_hash, str_equal);
     135            8 :                 recurse_cclass_to_vala_map (context.root);
     136              :         }
     137              : 
     138         5952 :         private void recurse_cclass_to_vala_map (Symbol sym) {
     139              :                 unowned List<Class> classes;
     140         5952 :                 if (sym is Namespace) {
     141         1328 :                         foreach (var inner in ((Namespace) sym).get_namespaces()) {
     142          440 :                                 recurse_cclass_to_vala_map (inner);
     143              :                         }
     144          448 :                         classes = ((Namespace) sym).get_classes ();
     145         5504 :                 } else if (sym is ObjectTypeSymbol) {
     146         5504 :                         classes = ((ObjectTypeSymbol) sym).get_classes ();
     147              :                 } else {
     148              :                         return;
     149              :                 }
     150        16960 :                 foreach (var cl in classes) {
     151         5504 :                         if (!cl.is_compact) {
     152         3608 :                                 cclass_to_vala_map.set (get_ccode_name (cl), cl);
     153              :                         }
     154         5504 :                         recurse_cclass_to_vala_map (cl);
     155              :                 }
     156              :         }
     157              : 
     158            8 :         private void ensure_gresource_to_file_map () {
     159              :                 // map gresource paths to real file names
     160            8 :                 if (gresource_to_file_map != null) {
     161              :                         return;
     162              :                 }
     163            8 :                 gresource_to_file_map = new HashMap<string, string>(str_hash, str_equal);
     164           24 :                 foreach (var gresource in context.gresources) {
     165            8 :                         if (!FileUtils.test (gresource, FileTest.EXISTS)) {
     166            0 :                                 Report.error (null, "GResources file `%s' does not exist", gresource);
     167            0 :                                 continue;
     168              :                         }
     169              : 
     170            8 :                         MarkupReader reader = new MarkupReader (gresource);
     171              : 
     172            8 :                         int state = 0;
     173            8 :                         string prefix = null;
     174            8 :                         string alias = null;
     175              : 
     176            8 :                         MarkupTokenType current_token = reader.read_token (null, null);
     177           80 :                         while (current_token != MarkupTokenType.EOF) {
     178           72 :                                 if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "gresource") {
     179            8 :                                         prefix = reader.get_attribute ("prefix");
     180           64 :                                 } else if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "file") {
     181            8 :                                         alias = reader.get_attribute ("alias");
     182            8 :                                         state = 1;
     183           64 :                                 } else if (state == 1 && current_token == MarkupTokenType.TEXT) {
     184            8 :                                         var name = reader.content;
     185            8 :                                         var filename = context.get_gresource_path (gresource, name);
     186            8 :                                         if (alias != null) {
     187            0 :                                                 gresource_to_file_map.set (Path.build_filename (prefix, alias), filename);
     188              :                                         }
     189            8 :                                         gresource_to_file_map.set (Path.build_filename (prefix, name), filename);
     190            8 :                                         state = 0;
     191              :                                 }
     192           72 :                                 current_token = reader.read_token (null, null);
     193              :                         }
     194              :                 }
     195              :         }
     196              : 
     197           16 :         private void process_current_ui_resource (string ui_resource, CodeNode node) {
     198              :                 /* Scan a single gtkbuilder file for signal handlers in <object> elements,
     199              :                    and save an handler string -> Vala.Signal mapping for each of them */
     200            8 :                 ensure_type_id_to_vala_map ();
     201            8 :                 ensure_cclass_to_vala_map();
     202            8 :                 ensure_gresource_to_file_map();
     203              : 
     204            8 :                 current_handler_to_signal_map = null;
     205            8 :                 current_child_to_class_map = null;
     206            8 :                 var ui_file = gresource_to_file_map.get (ui_resource);
     207            8 :                 if (ui_file == null || !FileUtils.test (ui_file, FileTest.EXISTS)) {
     208            0 :                         node.error = true;
     209            0 :                         Report.error (node.source_reference, "UI resource not found: `%s'. Please make sure to specify the proper GResources xml files with --gresources and alternative search locations with --gresourcesdir.", ui_resource);
     210            0 :                         return;
     211              :                 }
     212            8 :                 handler_map = new HashMap<string, string>(str_hash, str_equal);
     213            8 :                 current_handler_to_signal_map = new HashMap<string, Signal>(str_hash, str_equal);
     214            8 :                 current_child_to_class_map = new HashMap<string, Class>(str_hash, str_equal);
     215            8 :                 current_object_stack = new ArrayList<Class> ();
     216            8 :                 current_property_stack = new ArrayList<Property> ();
     217              : 
     218            8 :                 MarkupReader reader = new MarkupReader (ui_file);
     219            8 :                 string? current_handler = null;
     220              : 
     221            8 :                 bool template_tag_found = false;
     222            8 :                 MarkupTokenType current_token = reader.read_token (null, null);
     223          880 :                 while (current_token != MarkupTokenType.EOF) {
     224          872 :                         unowned string current_name = reader.name;
     225          872 :                         if (current_token == MarkupTokenType.START_ELEMENT && (current_name == "object" || current_name == "template")) {
     226           40 :                                 Class? current_class = null;
     227              : 
     228           72 :                                 if (current_name == "object") {
     229           32 :                                         var type_id = reader.get_attribute ("type-func");
     230           32 :                                         if (type_id != null) {
     231            0 :                                                 current_class = type_id_to_vala_map.get (type_id);
     232              :                                         }
     233            8 :                                 } else if (current_name == "template") {
     234              :                                         template_tag_found = true;
     235              :                                 }
     236              : 
     237          112 :                                 if (current_class == null) {
     238           40 :                                         var class_name = reader.get_attribute ("class");
     239           40 :                                         if (class_name == null) {
     240            0 :                                                 Report.error (node.source_reference, "Invalid %s in ui file `%s'", current_name, ui_file);
     241            0 :                                                 current_token = reader.read_token (null, null);
     242            0 :                                                 continue;
     243              :                                         }
     244           40 :                                         current_class = cclass_to_vala_map.get (class_name);
     245              : 
     246           40 :                                         if (current_class == null) {
     247            1 :                                                 push_object (new InvalidClass (class_name));
     248            1 :                                                 if (current_name == "template") {
     249            1 :                                                         Report.error (node.source_reference, "Unknown template `%s' in ui file `%s'", class_name, ui_file);
     250              :                                                 } else {
     251            0 :                                                         Report.warning (node.source_reference, "Unknown object `%s' in ui file `%s'", class_name, ui_file);
     252              :                                                 }
     253              :                                         }
     254              :                                 }
     255              : 
     256           79 :                                 if (current_class != null) {
     257           39 :                                         var child_name = reader.get_attribute ("id");
     258           39 :                                         if (child_name != null) {
     259           24 :                                                 current_child_to_class_map.set (child_name, current_class);
     260              :                                         }
     261           39 :                                         push_object (current_class);
     262              :                                 }
     263          832 :                         } else if (current_token == MarkupTokenType.END_ELEMENT && (current_name == "object" || current_name == "template")) {
     264           40 :                                 pop_object ();
     265          808 :                         } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "signal") {
     266           16 :                                 var signal_name = reader.get_attribute ("name");
     267           16 :                                 var handler_name = reader.get_attribute ("handler");
     268              : 
     269           16 :                                 if (signal_name == null || handler_name == null) {
     270            0 :                                         if (signal_name != null) {
     271            0 :                                                 Report.error (node.source_reference, "Invalid signal `%s' without handler in ui file `%s'", signal_name, ui_file);
     272            0 :                                         } else if (handler_name != null) {
     273            0 :                                                 Report.error (node.source_reference, "Invalid signal without name in ui file `%s'", ui_file);
     274              :                                         } else {
     275            0 :                                                 Report.error (node.source_reference, "Invalid signal without name and handler in ui file `%s'", ui_file);
     276              :                                         }
     277            0 :                                         current_token = reader.read_token (null, null);
     278            0 :                                         continue;
     279              :                                 }
     280           16 :                                 var sep_idx = signal_name.index_of ("::");
     281           16 :                                 if (sep_idx >= 0) {
     282              :                                         // detailed signal, we don't care about the detail
     283            0 :                                         signal_name = signal_name.substring (0, sep_idx);
     284              :                                 }
     285              : 
     286           16 :                                 var sig = SemanticAnalyzer.symbol_lookup_inherited (current_object, signal_name.replace ("-", "_")) as Signal;
     287           16 :                                 if (sig != null) {
     288           16 :                                         current_handler_to_signal_map.set (handler_name, sig);
     289              :                                 } else {
     290            0 :                                         Report.error (node.source_reference, "Unknown signal `%s::%s' in ui file `%s'", current_object.get_full_name (), signal_name, ui_file);
     291            0 :                                         current_token = reader.read_token (null, null);
     292            0 :                                         continue;
     293              :                                 }
     294          907 :                         } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT && (current_name == "property" || current_name == "binding")) {
     295          168 :                                 var property_name = reader.get_attribute ("name");
     296          168 :                                 if (property_name == null) {
     297            0 :                                         Report.error (node.source_reference, "Invalid %s without name in ui file `%s'", current_name, ui_file);
     298            0 :                                         current_token = reader.read_token (null, null);
     299            0 :                                         continue;
     300              :                                 }
     301              : 
     302          168 :                                 property_name = property_name.replace ("-", "_");
     303          168 :                                 var property = SemanticAnalyzer.symbol_lookup_inherited (current_object, property_name) as Property;
     304          168 :                                 if (property != null) {
     305          131 :                                         push_property (property);
     306              :                                 } else {
     307           37 :                                         push_property (new InvalidProperty (property_name));
     308           37 :                                         if (current_name == "binding") {
     309            0 :                                                 Report.error (node.source_reference, "Unknown property `%s:%s' for binding in ui file `%s'", current_object.get_full_name (), property_name, ui_file);
     310              :                                         }
     311           37 :                                         current_token = reader.read_token (null, null);
     312           37 :                                         continue;
     313              :                                 }
     314          608 :                         } else if (current_token == MarkupTokenType.END_ELEMENT && (current_name == "property" || current_name == "binding")) {
     315          168 :                                 pop_property ();
     316          448 :                         } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT && current_name == "closure") {
     317            8 :                                 var handler_name = reader.get_attribute ("function");
     318              : 
     319            8 :                                 if (current_property != null) {
     320            8 :                                         if (handler_name == null) {
     321            0 :                                                 Report.error (node.source_reference, "Invalid %s without function in ui file `%s'", current_name, ui_file);
     322            0 :                                                 current_token = reader.read_token (null, null);
     323            0 :                                                 continue;
     324              :                                         }
     325            8 :                                         if (current_property is InvalidProperty) {
     326            0 :                                                 Report.error (node.source_reference, "Unknown property `%s:%s' for binding in ui file `%s'", current_object.get_full_name (), current_property.name, ui_file);
     327              :                                         }
     328              : 
     329              :                                         //TODO Retrieve signature declaration? c-type to vala-type?
     330            8 :                                         current_handler_to_property_map.set (handler_name, current_property);
     331           16 :                                         current_handler = handler_name;
     332            0 :                                 } else if (current_handler != null) {
     333              :                                         // Track nested closure elements
     334            0 :                                         handler_map.set (handler_name, current_handler);
     335            0 :                                         current_handler = handler_name;
     336              :                                 }
     337              :                         }
     338          835 :                         current_token = reader.read_token (null, null);
     339              :                 }
     340              : 
     341            8 :                 if (!template_tag_found) {
     342            0 :                         Report.error (node.source_reference, "ui resource `%s' does not describe a valid composite template", ui_resource);
     343              :                 }
     344              :         }
     345              : 
     346         4713 :         private bool is_gtk_template (Class cl) {
     347         4713 :                 var attr = cl.get_attribute ("GtkTemplate");
     348           38 :                 if (attr != null) {
     349           38 :                         if (gtk_widget_type == null || !cl.is_subtype_of (gtk_widget_type)) {
     350            1 :                                 if (!cl.error) {
     351            1 :                                         Report.error (attr.source_reference, "subclassing Gtk.Widget is required for using Gtk templates");
     352            1 :                                         cl.error = true;
     353              :                                 }
     354            1 :                                 return false;
     355              :                         }
     356           37 :                         return true;
     357              :                 }
     358         4713 :                 return false;
     359              :         }
     360              : 
     361          742 :         public override void generate_class_init (Class cl) {
     362          734 :                 base.generate_class_init (cl);
     363              : 
     364          734 :                 if (cl.error || !is_gtk_template (cl)) {
     365          726 :                         return;
     366              :                 }
     367              : 
     368              :                 /* Gtk builder widget template */
     369            8 :                 var ui = cl.get_attribute_string ("GtkTemplate", "ui");
     370            8 :                 if (ui == null) {
     371            0 :                         Report.error (cl.source_reference, "empty ui resource declaration for Gtk widget template");
     372            0 :                         cl.error = true;
     373            0 :                         return;
     374              :                 }
     375              : 
     376            8 :                 process_current_ui_resource (ui, cl);
     377              : 
     378            8 :                 var call = new CCodeFunctionCall (new CCodeIdentifier ("gtk_widget_class_set_template_from_resource"));
     379            8 :                 call.add_argument (new CCodeIdentifier ("GTK_WIDGET_CLASS (klass)"));
     380            8 :                 call.add_argument (new CCodeConstant ("\"%s\"".printf (ui)));
     381            8 :                 ccode.add_expression (call);
     382              : 
     383            8 :                 current_required_app_classes.clear ();
     384              :         }
     385              : 
     386          510 :         public override void visit_property (Property prop) {
     387          510 :                 if (prop.has_attribute ("GtkChild") && prop.field == null) {
     388            1 :                         Report.error (prop.source_reference, "[GtkChild] is only allowed on automatic properties");
     389              :                 }
     390              : 
     391          510 :                 base.visit_property (prop);
     392              :         }
     393              : 
     394         1626 :         public override void visit_field (Field f) {
     395         1624 :                 base.visit_field (f);
     396              : 
     397         1624 :                 var cl = current_class;
     398         1274 :                 if (cl == null || cl.error) {
     399          350 :                         return;
     400              :                 }
     401              : 
     402         1274 :                 if (f.binding != MemberBinding.INSTANCE || !f.has_attribute ("GtkChild")) {
     403         1268 :                         return;
     404              :                 }
     405              : 
     406              :                 /* If the field has a [GtkChild] attribute but its class doesn'thave a
     407              :                          [GtkTemplate] attribute, we throw an error */
     408            6 :                 if (!is_gtk_template (cl)) {
     409            1 :                         Report.error (f.source_reference, "[GtkChild] is only allowed in classes with a [GtkTemplate] attribute");
     410            1 :                         return;
     411              :                 }
     412              : 
     413            5 :                 push_context (class_init_context);
     414              : 
     415              :                 /* Map ui widget to a class field */
     416            5 :                 var gtk_name = f.get_attribute_string ("GtkChild", "name", f.name);
     417            5 :                 var child_class = current_child_to_class_map.get (gtk_name);
     418            5 :                 if (child_class == null) {
     419            2 :                         Report.error (f.source_reference, "could not find child `%s'", gtk_name);
     420            2 :                         return;
     421              :                 }
     422              : 
     423              :                 /* We allow Gtk child to have stricter type than class field */
     424            3 :                 unowned Class? field_class = f.variable_type.type_symbol as Class;
     425            3 :                 if (field_class == null || !child_class.is_subtype_of (field_class)) {
     426            1 :                         Report.error (f.source_reference, "cannot convert from Gtk child type `%s' to `%s'", child_class.get_full_name(), field_class.get_full_name());
     427            1 :                         return;
     428              :                 }
     429              : 
     430            2 :                 var internal_child = f.get_attribute_bool ("GtkChild", "internal");
     431              : 
     432              :                 CCodeExpression offset;
     433            3 :                 if (f.is_private_symbol ()) {
     434              :                         // new glib api, we add the private struct offset to get the final field offset out of the instance
     435            1 :                         var private_field_offset = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET"));
     436            1 :                         private_field_offset.add_argument (new CCodeIdentifier ("%sPrivate".printf (get_ccode_name (cl))));
     437            1 :                         private_field_offset.add_argument (new CCodeIdentifier (get_ccode_name (f)));
     438            1 :                         offset = new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("%s_private_offset".printf (get_ccode_name (cl))), private_field_offset);
     439              :                 } else {
     440            1 :                         var offset_call = new CCodeFunctionCall (new CCodeIdentifier ("G_STRUCT_OFFSET"));
     441            1 :                         offset_call.add_argument (new CCodeIdentifier (get_ccode_name (cl)));
     442            1 :                         offset_call.add_argument (new CCodeIdentifier (get_ccode_name (f)));
     443            1 :                         offset = offset_call;
     444              :                 }
     445              : 
     446            2 :                 var call = new CCodeFunctionCall (new CCodeIdentifier ("gtk_widget_class_bind_template_child_full"));
     447            2 :                 call.add_argument (new CCodeIdentifier ("GTK_WIDGET_CLASS (klass)"));
     448            2 :                 call.add_argument (new CCodeConstant ("\"%s\"".printf (gtk_name)));
     449            2 :                 call.add_argument (new CCodeConstant (internal_child ? "TRUE" : "FALSE"));
     450            2 :                 call.add_argument (offset);
     451            2 :                 ccode.add_expression (call);
     452              : 
     453            2 :                 pop_context ();
     454              : 
     455            2 :                 if (!field_class.external && !field_class.external_package) {
     456            0 :                         current_required_app_classes.add (field_class);
     457              :                 }
     458              :         }
     459              : 
     460         5072 :         public override void visit_method (Method m) {
     461         5068 :                 base.visit_method (m);
     462              : 
     463         5068 :                 var cl = current_class;
     464         3197 :                 if (cl == null || cl.error || !is_gtk_template (cl)) {
     465         5052 :                         return;
     466              :                 }
     467              : 
     468           16 :                 if (!m.has_attribute ("GtkCallback")) {
     469           11 :                         return;
     470              :                 }
     471              : 
     472              :                 /* Handler name as defined in the gtkbuilder xml */
     473            5 :                 var handler_name = m.get_attribute_string ("GtkCallback", "name", m.name);
     474            5 :                 var callback = handler_map.get (handler_name);
     475            5 :                 var sig = current_handler_to_signal_map.get (handler_name);
     476            5 :                 var prop = current_handler_to_property_map.get (handler_name);
     477            5 :                 if (callback == null && sig == null && prop == null) {
     478            1 :                         Report.error (m.source_reference, "could not find signal or property for handler `%s'", handler_name);
     479            1 :                         return;
     480              :                 }
     481              : 
     482            4 :                 push_context (class_init_context);
     483              : 
     484            7 :                 if (sig != null) {
     485            3 :                         sig.check (context);
     486            3 :                         var method_type = new MethodType (m);
     487            3 :                         var signal_type = new SignalType (sig);
     488            3 :                         var delegate_type = signal_type.get_handler_type ();
     489            5 :                         if (!method_type.compatible (delegate_type)) {
     490            1 :                                 Report.error (m.source_reference, "method `%s' is incompatible with signal `%s', expected `%s'", method_type.to_string (), delegate_type.to_string (), delegate_type.to_prototype_string (m.name));
     491              :                         } else {
     492            2 :                                 var wrapper = generate_delegate_wrapper (m, signal_type.get_handler_type (), m);
     493              : 
     494            2 :                                 var call = new CCodeFunctionCall (new CCodeIdentifier ("gtk_widget_class_bind_template_callback_full"));
     495            2 :                                 call.add_argument (new CCodeIdentifier ("GTK_WIDGET_CLASS (klass)"));
     496            2 :                                 call.add_argument (new CCodeConstant ("\"%s\"".printf (handler_name)));
     497            2 :                                 call.add_argument (new CCodeIdentifier ("G_CALLBACK(%s)".printf (wrapper)));
     498            2 :                                 ccode.add_expression (call);
     499              :                         }
     500              :                 }
     501            5 :                 if (prop != null || callback != null) {
     502            1 :                         if (prop != null) {
     503            1 :                                 prop.check (context);
     504              :                         }
     505              :                         //TODO Perform signature check
     506            1 :                         var call = new CCodeFunctionCall (new CCodeIdentifier ("gtk_widget_class_bind_template_callback_full"));
     507            1 :                         call.add_argument (new CCodeIdentifier ("GTK_WIDGET_CLASS (klass)"));
     508            1 :                         call.add_argument (new CCodeConstant ("\"%s\"".printf (handler_name)));
     509            1 :                         call.add_argument (new CCodeIdentifier ("G_CALLBACK(%s)".printf (get_ccode_name (m))));
     510            1 :                         ccode.add_expression (call);
     511              :                 }
     512              : 
     513            4 :                 pop_context ();
     514              :         }
     515              : 
     516              : 
     517          787 :         public override void end_instance_init (Class cl) {
     518          779 :                 if (cl == null || cl.error || !is_gtk_template (cl)) {
     519          771 :                         return;
     520              :                 }
     521              : 
     522            8 :                 foreach (var req in current_required_app_classes) {
     523              :                         /* ensure custom application widgets are initialized */
     524            0 :                         var call = new CCodeFunctionCall (new CCodeIdentifier ("g_type_ensure"));
     525            0 :                         call.add_argument (get_type_id_expression (SemanticAnalyzer.get_data_type_for_symbol (req)));
     526            0 :                         ccode.add_expression (call);
     527              :                 }
     528              : 
     529            8 :                 var call = new CCodeFunctionCall (new CCodeIdentifier ("gtk_widget_init_template"));
     530            8 :                 call.add_argument (new CCodeIdentifier ("GTK_WIDGET (self)"));
     531            8 :                 ccode.add_expression (call);
     532              :         }
     533              : }
     534              : 
        

Generated by: LCOV version 2.0-1