[gobject-introspection] Bug 557383 - Virtual method support



commit fdbe3cc3e1cfaa546648a76b1dca72beead0b65b
Author: Colin Walters <walters verbum org>
Date:   Fri Feb 27 19:02:48 2009 -0500

    Bug 557383 - Virtual method support
    
    Broadly speaking, this change adds the concept of <vfunc> to the .gir.
    The typelib already had most of the infrastructure for virtual functions,
    though there is one API addition.
    
    The scanner assumes that any class callback slot that doesn't match
    a signal name is a virtual.  In the .gir, we write out *both* the <method>
    wrapper and a <vfunc>.  If we can determine an association between
    them (based on the names matching, or a new Virtual: annotation),
    then we notate that in the .gir.
    
    The typelib gains an association from the vfunc to the function, if
    it exists.  This will be useful for bindings since they already know
    how to consume FunctionInfo.
---
 girepository/ginfo.c                |  116 +++++++++++++++++++++++++++++++++++
 girepository/girepository.h         |    5 ++
 girepository/girnode.c              |   37 +++++++++++
 girepository/girnode.h              |    2 +
 girepository/girparser.c            |    6 ++-
 girepository/gtypelib.h             |    8 ++-
 giscanner/annotationparser.py       |   57 +++++++++++++----
 giscanner/ast.py                    |   36 ++++++++---
 giscanner/girwriter.py              |   47 ++++++++-------
 giscanner/glibtransformer.py        |   73 +++++++++++++++++++---
 tests/everything/everything.c       |   25 ++++++++
 tests/everything/everything.h       |    6 ++
 tests/repository/Makefile.am        |    4 +-
 tests/repository/gitestrepo.c       |   48 ++++++++++++++
 tests/scanner/foo-1.0-expected.gir  |  111 +++++++++++++++++++++++++++++----
 tests/scanner/foo-1.0-expected.tgir |   79 +++++++++++++++++++++++-
 tests/scanner/foo.c                 |   53 ++++++++++++++--
 tests/scanner/foo.h                 |   17 +++++-
 tools/generate.c                    |    9 ++-
 19 files changed, 655 insertions(+), 84 deletions(-)

diff --git a/girepository/ginfo.c b/girepository/ginfo.c
index fcc5f09..d522a56 100644
--- a/girepository/ginfo.c
+++ b/girepository/ginfo.c
@@ -1527,6 +1527,63 @@ g_object_info_get_vfunc (GIObjectInfo *info,
 				     base->typelib, offset);  
 }
 
+static GIVFuncInfo *
+find_vfunc (GIBaseInfo   *base,
+            guint32       offset,
+            gint          n_vfuncs,
+            const gchar  *name)
+{
+  /* FIXME hash */
+  Header *header = (Header *)base->typelib->data;
+  gint i;
+
+  for (i = 0; i < n_vfuncs; i++)
+    {
+      VFuncBlob *fblob = (VFuncBlob *)&base->typelib->data[offset];
+      const gchar *fname = (const gchar *)&base->typelib->data[fblob->name];
+
+      if (strcmp (name, fname) == 0)
+        return (GIVFuncInfo *) g_info_new (GI_INFO_TYPE_VFUNC, base,
+                                           base->typelib, offset);
+
+      offset += header->vfunc_blob_size;
+    }
+
+  return NULL;
+}
+
+/**
+ * g_object_info_find_vfunc:
+ * @info: An #GIObjectInfo
+ * @name: The name of a virtual function to find.
+ *
+ * Locate a virtual function slot with name @name.  Note that the namespace
+ * for virtuals is distinct from that of methods; there may or may not be
+ * a concrete method associated for a virtual.  If there is one, it may
+ * be retrieved using #g_vfunc_info_get_invoker.  See the documentation for
+ * that function for more information on invoking virtuals.
+ *
+ * Return value: (transfer full): A #GIVFuncInfo, or %NULL if none with name @name.
+ */
+GIVFuncInfo *
+g_object_info_find_vfunc (GIObjectInfo *info,
+                          const gchar  *name)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->typelib->data;
+  ObjectBlob *blob = (ObjectBlob *)&base->typelib->data[base->offset];
+
+  offset = base->offset + header->object_blob_size
+    + (blob->n_interfaces + blob->n_interfaces % 2) * 2
+    + blob->n_fields * header->field_blob_size
+    + blob->n_properties * header->property_blob_size
+    + blob->n_methods * header->function_blob_size
+    + blob->n_signals * header->signal_blob_size;
+
+  return find_vfunc (base, offset, blob->n_vfuncs, name);
+}
+
 gint
 g_object_info_get_n_constants (GIObjectInfo *info)
 {
@@ -1728,6 +1785,34 @@ g_interface_info_get_vfunc (GIInterfaceInfo *info,
 				     base->typelib, offset);  
 }
 
+/**
+ * g_interface_info_find_vfunc:
+ * @info: An #GIObjectInfo
+ * @name: The name of a virtual function to find.
+ *
+ * Locate a virtual function slot with name @name.  See the documentation
+ * for #g_object_info_find_vfunc for more information on virtuals.
+ *
+ * Return value: (transfer full): A #GIVFuncInfo, or %NULL if none with name @name.
+ */
+GIVFuncInfo *
+g_interface_info_find_vfunc (GIInterfaceInfo *info,
+                             const gchar  *name)
+{
+  gint offset;
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  Header *header = (Header *)base->typelib->data;
+  InterfaceBlob *blob = (InterfaceBlob *)&base->typelib->data[base->offset];
+
+  offset = base->offset + header->interface_blob_size
+    + (blob->n_prerequisites + blob->n_prerequisites % 2) * 2
+    + blob->n_properties * header->property_blob_size
+    + blob->n_methods * header->function_blob_size
+    + blob->n_signals * header->signal_blob_size;
+
+  return find_vfunc (base, offset, blob->n_vfuncs, name);
+}
+
 gint
 g_interface_info_get_n_constants (GIInterfaceInfo *info)
 {
@@ -1913,6 +1998,37 @@ g_vfunc_info_get_signal (GIVFuncInfo *info)
   return NULL;
 }
 
+/**
+ * g_vfunc_info_get_invoker:
+ * @info: A #GIVFuncInfo
+ *
+ * If this virtual function has an associated invoker method, this
+ * method will return it.  An invoker method is a C entry point.
+ *
+ * Not all virtuals will have invokers.
+ *
+ * Return value: (transfer full): An invoker function, or %NULL if none known
+ */
+GIFunctionInfo *
+g_vfunc_info_get_invoker (GIVFuncInfo *info)
+{
+  GIBaseInfo *base = (GIBaseInfo *)info;
+  VFuncBlob *blob = (VFuncBlob *)&base->typelib->data[base->offset];
+  GIBaseInfo *container = base->container;
+  GIInfoType parent_type;
+
+  /* 1023 = 0x3ff is the maximum of the 10 bits for invoker index */
+  if (blob->invoker == 1023)
+    return NULL;
+
+  parent_type = g_base_info_get_type (container);
+  if (parent_type == GI_INFO_TYPE_OBJECT)
+    return g_object_info_get_method ((GIObjectInfo*)container, blob->invoker);
+  else if (parent_type == GI_INFO_TYPE_INTERFACE)
+    return g_interface_info_get_method ((GIInterfaceInfo*)container, blob->invoker);
+  else
+    g_assert_not_reached ();
+}
 
 /* GIConstantInfo functions */
 GITypeInfo *
diff --git a/girepository/girepository.h b/girepository/girepository.h
index 4059adc..1058570 100644
--- a/girepository/girepository.h
+++ b/girepository/girepository.h
@@ -470,6 +470,8 @@ GISignalInfo *         g_object_info_get_signal             (GIObjectInfo    *in
 gint                   g_object_info_get_n_vfuncs           (GIObjectInfo    *info);
 GIVFuncInfo *          g_object_info_get_vfunc              (GIObjectInfo    *info,
 							     gint            n);
+GIVFuncInfo *          g_object_info_find_vfunc             (GIObjectInfo *info,
+                                                             const gchar *name);
 gint                   g_object_info_get_n_constants        (GIObjectInfo    *info);
 GIConstantInfo *       g_object_info_get_constant           (GIObjectInfo    *info,
 							     gint            n);
@@ -495,6 +497,8 @@ GISignalInfo *         g_interface_info_get_signal          (GIInterfaceInfo *in
 gint                   g_interface_info_get_n_vfuncs        (GIInterfaceInfo *info);
 GIVFuncInfo *          g_interface_info_get_vfunc           (GIInterfaceInfo *info,
 							     gint        n);
+GIVFuncInfo *          g_interface_info_find_vfunc          (GIInterfaceInfo *info,
+                                                             const gchar *name);
 gint                   g_interface_info_get_n_constants     (GIInterfaceInfo *info);
 GIConstantInfo *       g_interface_info_get_constant        (GIInterfaceInfo *info,
 							     gint        n);
@@ -527,6 +531,7 @@ typedef enum
 GIVFuncInfoFlags        g_vfunc_info_get_flags                   (GIVFuncInfo            *info);
 gint                    g_vfunc_info_get_offset                  (GIVFuncInfo            *info);
 GISignalInfo *          g_vfunc_info_get_signal                  (GIVFuncInfo            *info);
+GIFunctionInfo *        g_vfunc_info_get_invoker                 (GIVFuncInfo            *info);
 
 
 /* GIConstantInfo */
diff --git a/girepository/girnode.c b/girepository/girnode.c
index 22c0aee..01e83ac 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -265,6 +265,7 @@ g_ir_node_free (GIrNode *node)
 	GIrNodeVFunc *vfunc = (GIrNodeVFunc *)node;
 	
 	g_free (node->name);
+	g_free (vfunc->invoker);
 	for (l = vfunc->parameters; l; l = l->next)
 	  g_ir_node_free ((GIrNode *)l->data);
 	g_list_free (vfunc->parameters);
@@ -1186,6 +1187,30 @@ g_ir_find_node (GIrModule  *module,
   return node != NULL;
 }
 
+static int
+get_index_of_member_type (GIrNodeInterface *node,
+                          GIrNodeTypeId type,
+                          const char *name)
+{
+  guint index = -1;
+  GList *l;
+
+  for (l = node->members; l; l = l->next)
+    {
+      GIrNode *node = l->data;
+
+      if (node->type != type)
+        continue;
+
+      index++;
+
+      if (strcmp (node->name, name) == 0)
+        break;
+    }
+
+  return index;
+}
+
 static void
 serialize_type (GIrModule    *module, 
 		GList        *modules,
@@ -1759,6 +1784,18 @@ g_ir_node_build_typelib (GIrNode         *node,
 	blob->class_closure = 0; /* FIXME */
 	blob->reserved = 0;
 
+	if (vfunc->invoker)
+	  {
+	    int index = get_index_of_member_type ((GIrNodeInterface*)parent, G_IR_NODE_FUNCTION, vfunc->invoker);
+	    if (index == -1)
+	      {
+	        g_error ("Unknown member function %s for vfunc %s", vfunc->invoker, node->name);
+	      }
+            blob->invoker = (guint) index;
+	  }
+	else
+	  blob->invoker = 0x3ff; /* max of 10 bits */
+
 	blob->struct_offset = vfunc->offset;
 	blob->reserved2 = 0;
 	blob->signature = signature;
diff --git a/girepository/girnode.h b/girepository/girnode.h
index 2a1f6b2..238593a 100644
--- a/girepository/girnode.h
+++ b/girepository/girnode.h
@@ -214,6 +214,8 @@ struct _GIrNodeVFunc
   gboolean must_not_be_implemented;
   gboolean is_class_closure;
   
+  char *invoker;
+
   GList *parameters;
   GIrNodeParam *result;      
 
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 006ed3b..9afd858 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -2080,7 +2080,7 @@ start_vfunc (GMarkupParseContext *context,
 	     ParseContext       *ctx,
 	     GError             **error)
 {
-  if (strcmp (element_name, "vfunc") == 0 && 
+  if (strcmp (element_name, "virtual-method") == 0 &&
       (ctx->state == STATE_CLASS ||
        ctx->state == STATE_INTERFACE))
     {
@@ -2089,12 +2089,14 @@ start_vfunc (GMarkupParseContext *context,
       const gchar *override;
       const gchar *is_class_closure;
       const gchar *offset;
+      const gchar *invoker;
       
       name = find_attribute ("name", attribute_names, attribute_values);
       must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values);	  
       override = find_attribute ("override", attribute_names, attribute_values);
       is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values);
       offset = find_attribute ("offset", attribute_names, attribute_values);
+      invoker = find_attribute ("invoker", attribute_names, attribute_values);
       
       if (name == NULL)
 	MISSING_ATTRIBUTE (context, error, element_name, "name");
@@ -2138,6 +2140,8 @@ start_vfunc (GMarkupParseContext *context,
 	  else
 	    vfunc->offset = 0;
 
+	  vfunc->invoker = g_strdup (invoker);
+
 	  iface = (GIrNodeInterface *)CURRENT_NODE (ctx);
 	  iface->members = g_list_append (iface->members, vfunc);
 
diff --git a/girepository/gtypelib.h b/girepository/gtypelib.h
index db5fe11..f6ad8c9 100644
--- a/girepository/gtypelib.h
+++ b/girepository/gtypelib.h
@@ -843,9 +843,10 @@ typedef struct {
  * @class_closure: Set if this virtual function is the class closure of a signal.
  * @signal: The index of the signal in the list of signals of the object or 
  * interface to which this virtual function belongs.
- * @struct_offset:
- * The offset of the function pointer in the class struct. The value
+ * @struct_offset: The offset of the function pointer in the class struct. The value
  * 0xFFFF indicates that the struct offset is unknown.
+ * @invoker: If a method invoker for this virtual exists, this is the offset in the
+ * class structure of the method.  If no method is known, this value will be 0x3ff.
  * @signature: 
  * Offset of the SignatureBlob describing the parameter types and the 
  * return value type. 
@@ -861,7 +862,8 @@ typedef struct {
   guint16 signal;
 
   guint16 struct_offset;
-  guint16 reserved2;
+  guint16 invoker : 10; /* Number of bits matches @index in FunctionBlob */
+  guint16 reserved2 : 6;
 
   guint32 reserved3;
   guint32 signature;
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index 35300b0..f32486c 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -41,6 +41,7 @@ from .glibast import GLibBoxed
 _COMMENT_HEADER = '*\n '
 
 # Tags - annotations applyed to comment blocks
+TAG_VFUNC = 'virtual'
 TAG_SINCE = 'since'
 TAG_DEPRECATED = 'deprecated'
 TAG_RETURNS = 'returns'
@@ -298,8 +299,9 @@ class AnnotationApplier(object):
         block = self._blocks.get(class_.type_name)
         self._parse_node_common(class_, block)
         self._parse_constructors(class_.constructors)
-        self._parse_methods(class_.methods)
-        self._parse_methods(class_.static_methods)
+        self._parse_methods(class_, class_.methods)
+        self._parse_vfuncs(class_, class_.virtual_methods)
+        self._parse_methods(class_, class_.static_methods)
         self._parse_properties(class_, class_.properties)
         self._parse_signals(class_, class_.signals)
         self._parse_fields(class_, class_.fields)
@@ -309,7 +311,8 @@ class AnnotationApplier(object):
     def _parse_interface(self, interface):
         block = self._blocks.get(interface.type_name)
         self._parse_node_common(interface, block)
-        self._parse_methods(interface.methods)
+        self._parse_methods(interface, interface.methods)
+        self._parse_vfuncs(interface, interface.virtual_methods)
         self._parse_properties(interface, interface.properties)
         self._parse_signals(interface, interface.signals)
         self._parse_fields(interface, interface.fields)
@@ -320,7 +323,7 @@ class AnnotationApplier(object):
         block = self._blocks.get(record.symbol)
         self._parse_node_common(record, block)
         self._parse_constructors(record.constructors)
-        self._parse_methods(record.methods)
+        self._parse_methods(record, record.methods)
         self._parse_fields(record, record.fields)
         if block:
             record.doc = block.comment
@@ -329,7 +332,7 @@ class AnnotationApplier(object):
         block = self._blocks.get(boxed.name)
         self._parse_node_common(boxed, block)
         self._parse_constructors(boxed.constructors)
-        self._parse_methods(boxed.methods)
+        self._parse_methods(boxed, boxed.methods)
         if block:
             boxed.doc = block.comment
 
@@ -338,7 +341,7 @@ class AnnotationApplier(object):
         self._parse_node_common(union, block)
         self._parse_fields(union, union.fields)
         self._parse_constructors(union.constructors)
-        self._parse_methods(union.methods)
+        self._parse_methods(union, union.methods)
         if block:
             union.doc = block.comment
 
@@ -370,9 +373,13 @@ class AnnotationApplier(object):
         for prop in properties:
             self._parse_property(parent, prop)
 
-    def _parse_methods(self, methods):
+    def _parse_methods(self, parent, methods):
         for method in methods:
-            self._parse_function(method)
+            self._parse_method(parent, method)
+
+    def _parse_vfuncs(self, parent, vfuncs):
+        for vfunc in vfuncs:
+            self._parse_vfunc(parent, vfunc)
 
     def _parse_signals(self, parent, signals):
         for signal in signals:
@@ -392,18 +399,20 @@ class AnnotationApplier(object):
         if block:
             callback.doc = block.comment
 
+    def _parse_callable(self, callable, block):
+        self._parse_node_common(callable, block)
+        self._parse_params(callable, callable.parameters, block)
+        self._parse_return(callable, callable.retval, block)
+        if block:
+            callable.doc = block.comment
+
     def _parse_function(self, func):
         block = self._blocks.get(func.symbol)
-        self._parse_node_common(func, block)
-        self._parse_params(func, func.parameters, block)
-        self._parse_return(func, func.retval, block)
-        if block:
-            func.doc = block.comment
+        self._parse_callable(func, block)
 
     def _parse_signal(self, parent, signal):
         block = self._blocks.get('%s::%s' % (parent.type_name, signal.name))
         self._parse_node_common(signal, block)
-        self._parse_deprecated(signal, block)
         # We're only attempting to name the signal parameters if
         # the number of parameter tags (@foo) is the same or greater
         # than the number of signal parameters
@@ -426,6 +435,26 @@ class AnnotationApplier(object):
         if block:
             signal.doc = block.comment
 
+    def _parse_method(self, parent, meth):
+        block = self._blocks.get(meth.symbol)
+        self._parse_function(meth)
+        virtual = self._get_tag(block, TAG_VFUNC)
+        if virtual:
+            invoker_name = virtual.value
+            matched = False
+            for vfunc in parent.virtual_methods:
+                if vfunc.name == invoker_name:
+                    matched = True
+                    vfunc.invoker = meth.name
+                    break
+            if not matched:
+                print "warning: unmatched virtual invoker %r for method %r" % \
+                    (invoker_name, meth.symbol)
+
+    def _parse_vfunc(self, parent, vfunc):
+        key = '%s::%s' % (parent.type_name, vfunc.name)
+        self._parse_callable(vfunc, self._blocks.get(key))
+
     def _parse_field(self, parent, field):
         if isinstance(field, Callback):
             self._parse_callback(field)
diff --git a/giscanner/ast.py b/giscanner/ast.py
index d2bae87..0f0d1bb 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -196,15 +196,25 @@ class Include(Node):
     def __str__(self):
         return '%s-%s' % (self.name, self.version)
 
+class Callable(Node):
 
-class Function(Node):
-
-    def __init__(self, name, retval, parameters, symbol, throws=None):
+    def __init__(self, name, retval, parameters, throws):
         Node.__init__(self, name)
         self.retval = retval
         self.parameters = parameters
-        self.symbol = symbol
         self.throws = not not throws
+        self.doc = None
+
+    def __repr__(self):
+        return '%s(%r, %r, %r)' % (self.__class__.__name__,
+                                   self.name, self.retval,
+                                   self.parameters)
+
+class Function(Callable):
+
+    def __init__(self, name, retval, parameters, symbol, throws=None):
+        Callable.__init__(self, name, retval, parameters, throws)
+        self.symbol = symbol
         self.is_method = False
         self.doc = None
 
@@ -218,14 +228,18 @@ class Function(Node):
             if parameter.name == name:
                 return parameter
 
-    def __repr__(self):
-        return '%s(%r, %r, %r)' % (self.__class__.__name__,
-                                   self.name, self.retval,
-                                   self.parameters)
 
+class VFunction(Callable):
 
-class VFunction(Function):
-    pass
+    def __init__(self, name, retval, parameters, throws):
+        Callable.__init__(self, name, retval, parameters, throws)
+        self.invoker = None
+
+    @classmethod
+    def from_callback(cls, cb):
+        obj = cls(cb.name, cb.retval, cb.parameters[1:],
+                  cb.throws)
+        return obj
 
 
 class Type(Node):
@@ -411,6 +425,7 @@ class Class(Node):
         self.glib_type_struct = None
         self.is_abstract = is_abstract
         self.methods = []
+        self.virtual_methods = []
         self.static_methods = []
         self.interfaces = []
         self.constructors = []
@@ -430,6 +445,7 @@ class Interface(Node):
         Node.__init__(self, name)
         self.parent = parent
         self.methods = []
+        self.virtual_methods = []
         self.glib_type_struct = None
         self.properties = []
         self.fields = []
diff --git a/giscanner/girwriter.py b/giscanner/girwriter.py
index 88510b0..e30bc6b 100644
--- a/giscanner/girwriter.py
+++ b/giscanner/girwriter.py
@@ -158,18 +158,22 @@ and/or use gtk-doc annotations. ''')
             attrs.append(('c:type', alias.ctype))
         self.write_tag('alias', attrs)
 
-    def _write_function(self, func, tag_name='function'):
-        attrs = [('name', func.name),
-                 ('c:identifier', func.symbol)]
-        if func.doc:
-            attrs.append(('doc', func.doc))
-        self._append_version(func, attrs)
-        self._append_deprecated(func, attrs)
-        self._append_throws(func, attrs)
+    def _write_callable(self, callable, tag_name, extra_attrs):
+        attrs = [('name', callable.name)]
+        attrs.extend(extra_attrs)
+        if callable.doc:
+            attrs.append(('doc', callable.doc))
+        self._append_version(callable, attrs)
+        self._append_deprecated(callable, attrs)
+        self._append_throws(callable, attrs)
         with self.tagcontext(tag_name, attrs):
-            self._write_attributes(func)
-            self._write_return_type(func.retval)
-            self._write_parameters(func.parameters)
+            self._write_attributes(callable)
+            self._write_return_type(callable.retval)
+            self._write_parameters(callable.parameters)
+
+    def _write_function(self, func, tag_name='function'):
+        attrs = [('c:identifier', func.symbol)]
+        self._write_callable(func, tag_name, attrs)
 
     def _write_method(self, method):
         self._write_function(method, tag_name='method')
@@ -354,6 +358,8 @@ and/or use gtk-doc annotations. ''')
                     self._write_constructor(method)
                 for method in node.static_methods:
                     self._write_static_method(method)
+            for vfunc in node.virtual_methods:
+                self._write_vfunc(vfunc)
             for method in node.methods:
                 self._write_method(method)
             for prop in node.properties:
@@ -395,18 +401,15 @@ and/or use gtk-doc annotations. ''')
             self._write_attributes(prop)
             self._write_type(prop.type)
 
+    def _write_vfunc(self, vf):
+        attrs = []
+        if vf.invoker:
+            attrs.append(('invoker', vf.invoker))
+        self._write_callable(vf, 'virtual-method', attrs)
+
     def _write_callback(self, callback):
-        # FIXME: reuse _write_function
-        attrs = [('name', callback.name), ('c:type', callback.ctype)]
-        if callback.doc:
-            attrs.append(('doc', callback.doc))
-        self._append_version(callback, attrs)
-        self._append_deprecated(callback, attrs)
-        self._append_throws(callback, attrs)
-        with self.tagcontext('callback', attrs):
-            self._write_attributes(callback)
-            self._write_return_type(callback.retval)
-            self._write_parameters(callback.parameters)
+        attrs = [('c:type', callback.ctype)]
+        self._write_callable(callback, 'callback', attrs)
 
     def _boxed_attrs(self, boxed):
         return [('glib:type-name', boxed.type_name),
diff --git a/giscanner/glibtransformer.py b/giscanner/glibtransformer.py
index 5a7a96d..61d4cef 100644
--- a/giscanner/glibtransformer.py
+++ b/giscanner/glibtransformer.py
@@ -27,12 +27,13 @@ import subprocess
 
 from .ast import (Alias, Bitfield, Callback, Constant, Enum, Function, Member,
                   Namespace, Parameter, Property, Record, Return, Type, Union,
-                  Field, type_name_from_ctype,
+                  Field, VFunction, type_name_from_ctype,
                   default_array_types, TYPE_UINT8, PARAM_TRANSFER_FULL)
 from .transformer import Names
 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
                       GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
-                      GLibBoxedUnion, GLibBoxedOther, GLibRecord, type_names)
+                      GLibBoxedUnion, GLibBoxedOther, GLibRecord,
+                      type_names)
 from .utils import to_underscores, to_underscores_noprefix
 
 default_array_types['guchar*'] = TYPE_UINT8
@@ -159,6 +160,10 @@ class GLibTransformer(object):
             except KeyError, e:
                 print "WARNING: DELETING node %s: %s" % (node.name, e)
                 self._remove_attribute(node.name)
+        # Another pass, since we need to have the methods parsed
+        # in order to correctly modify them after class/record
+        # pairing
+        for (ns, node) in nodes:
             # associate GtkButtonClass with GtkButton
             if isinstance(node, Record):
                 self._pair_class_record(node)
@@ -167,7 +172,9 @@ class GLibTransformer(object):
         self._resolve_quarks()
         # Fourth pass: ensure all types are known
         if not self._noclosure:
-            self._validate(nodes)
+            self._resolve_types(nodes)
+
+        self._validate(nodes)
 
         # Create a new namespace with what we found
         namespace = Namespace(self._namespace_name, self._namespace_version)
@@ -573,10 +580,43 @@ class GLibTransformer(object):
         for field in maybe_class.fields:
             if isinstance(field, Field):
                 field.writable = False
-        # TODO: remove this, we should be computing vfuncs instead
-        if isinstance(pair_class, GLibInterface):
-            for field in maybe_class.fields[1:]:
-                pair_class.fields.append(field)
+
+        # Loop through fields to determine which are virtual
+        # functions and which are signal slots by
+        # assuming everything that doesn't share a name
+        # with a known signal is a virtual slot.
+        for field in maybe_class.fields:
+            if not isinstance(field, Callback):
+                continue
+            # Check the first parameter is the object
+            if len(field.parameters) == 0:
+                continue
+            firstparam_type = field.parameters[0].type
+            if firstparam_type != pair_class:
+                continue
+            # Also double check we don't have a signal with this
+            # name.
+            matched_signal = False
+            for signal in pair_class.signals:
+                if signal.name.replace('-', '_') == field.name:
+                    matched_signal = True
+                    break
+            if matched_signal:
+                continue
+            vfunc = VFunction.from_callback(field)
+            pair_class.virtual_methods.append(vfunc)
+
+        # Take the set of virtual methods we found, and try
+        # to pair up with any matching methods using the
+        # name+signature.
+        for vfunc in pair_class.virtual_methods:
+            for method in pair_class.methods:
+                if (method.name != vfunc.name or
+                    method.retval != vfunc.retval or
+                    method.parameters != vfunc.parameters):
+                    continue
+                vfunc.invoker = method.name
+
         gclass_struct = GLibRecord.from_record(class_struct)
         self._remove_attribute(class_struct.name)
         self._add_attribute(gclass_struct, True)
@@ -903,9 +943,7 @@ class GLibTransformer(object):
     def _resolve_alias(self, alias):
         alias.target = self._resolve_type_name(alias.target, alias.target)
 
-    # Validation
-
-    def _validate(self, nodes):
+    def _resolve_types(self, nodes):
         nodes = list(self._names.names.itervalues())
         i = 0
         self._validating = True
@@ -925,3 +963,18 @@ class GLibTransformer(object):
             i += 1
             self._print_statistics()
         self._validating = False
+
+    # Validation
+
+    def _validate_interface(self, iface):
+        for vfunc in iface.virtual_methods:
+            if not vfunc.invoker:
+                print ("warning: Interface %r virtual function %r " + \
+                    "has no known invoker") % (iface.name, vfunc.name)
+
+    # This function is called at the very end, before we hand back the
+    # completed namespace to the writer.  Add static analysis checks here.
+    def _validate(self, nodes):
+        for (name, node) in nodes:
+            if isinstance(node, GLibInterface):
+                self._validate_interface(node)
diff --git a/tests/everything/everything.c b/tests/everything/everything.c
index 75842bf..c597f85 100644
--- a/tests/everything/everything.c
+++ b/tests/everything/everything.c
@@ -789,6 +789,12 @@ test_obj_dispose (GObject *gobject)
   G_OBJECT_CLASS (test_obj_parent_class)->dispose (gobject);
 }
 
+static int
+test_obj_default_matrix (TestObj *obj, const char *somestr)
+{
+  return 42;
+}
+
 static void
 test_obj_class_init (TestObjClass *klass)
 {
@@ -819,6 +825,8 @@ test_obj_class_init (TestObjClass *klass)
   g_object_class_install_property (gobject_class,
                                    PROP_TEST_OBJ_BARE,
                                    pspec);
+
+  klass->matrix = test_obj_default_matrix;
 }
 
 static void
@@ -854,6 +862,23 @@ test_obj_static_method (int x)
 }
 
 /**
+ * test_obj_do_matrix:
+ * @obj: A #TestObj
+ * @somestr: Meaningless string
+ *
+ * This method is virtual.  Notably its name differs from the virtual
+ * slot name, which makes it useful for testing bindings handle this
+ * case.
+ *
+ * Virtual: matrix
+ */
+int
+test_obj_do_matrix (TestObj *obj, const char *somestr)
+{
+  return TEST_OBJ_GET_CLASS (obj)->matrix (obj, somestr);
+}
+
+/**
  * test_callback:
  * @callback: (scope call):
  *
diff --git a/tests/everything/everything.h b/tests/everything/everything.h
index dbb7995..2474566 100644
--- a/tests/everything/everything.h
+++ b/tests/everything/everything.h
@@ -178,6 +178,7 @@ gboolean   test_boxed_equals   (TestBoxed *boxed,
 #define TEST_TYPE_OBJ              (test_obj_get_type ())
 #define TEST_OBJECT(object)        (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_OBJ, TestObj))
 #define TEST_IS_OBJECT(object)     (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_OBJ))
+#define TEST_OBJ_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJ, TestObjClass))
 
 typedef struct _TestObj          TestObj;
 typedef struct _TestObjClass     TestObjClass;
@@ -197,6 +198,8 @@ struct _TestObjClass
 {
   GObjectClass parent_class;
 
+  int (*matrix) (TestObj *obj, const char *somestr);
+
   guint test_signal;
 };
 
@@ -205,6 +208,9 @@ TestObj*   test_obj_new_from_file (const char *x, GError **error);
 void       test_obj_set_bare (TestObj *obj, GObject *bare);
 double     test_obj_static_method (int x);
 
+/* virtual */
+int        test_obj_do_matrix (TestObj *obj, const char *somestr);
+
 /* callback */
 typedef int (*TestCallback) ();
 typedef int (*TestCallbackUserData) (gpointer user_data);
diff --git a/tests/repository/Makefile.am b/tests/repository/Makefile.am
index e21cff4..36f738d 100644
--- a/tests/repository/Makefile.am
+++ b/tests/repository/Makefile.am
@@ -13,5 +13,5 @@ gitestthrows_CPPFLAGS = $(GIREPO_CFLAGS) -I$(top_srcdir)/girepository
 gitestthrows_LDADD = $(top_builddir)/girepository/libgirepository-1.0.la $(GIREPO_LIBS)
 
 TESTS = gitestrepo gitestthrows
-TESTS_ENVIRONMENT=env top_builddir="$(top_builddir)" $(DEBUG) \
-   XDG_DATA_DIRS="$(top_srcdir)/gir:$(XDG_DATA_DIRS)"
+TESTS_ENVIRONMENT=env top_builddir="$(top_builddir)" \
+   XDG_DATA_DIRS="$(top_srcdir)/gir:$(XDG_DATA_DIRS)" $(DEBUG)
\ No newline at end of file
diff --git a/tests/repository/gitestrepo.c b/tests/repository/gitestrepo.c
index 0e67467..a65116b 100644
--- a/tests/repository/gitestrepo.c
+++ b/tests/repository/gitestrepo.c
@@ -73,5 +73,53 @@ main(int argc, char **argv)
   info = g_irepository_find_by_name (repo, "Gio", "ThisDoesNotExist");
   g_assert (info == NULL);
 
+  /* vfunc tests */
+  {
+    GIVFuncInfo *vfunc;
+    GIFunctionInfo *invoker;
+
+    /* Test vfunc with invoker on interface */
+    info = g_irepository_find_by_name (repo, "Gio", "File");
+    g_assert (info != NULL);
+
+    vfunc = g_interface_info_find_vfunc ((GIInterfaceInfo*)info, "read_async");
+    g_assert (vfunc != NULL);
+
+    invoker = g_vfunc_info_get_invoker (vfunc);
+    g_assert (invoker != NULL);
+
+    g_assert (strcmp (g_base_info_get_name ((GIBaseInfo*)invoker), "read_async") == 0);
+
+    /* Test vfunc with no known invoker on object */
+    info = g_irepository_find_by_name (repo, "GObject", "Object");
+    g_assert (info != NULL);
+
+    vfunc = g_object_info_find_vfunc ((GIObjectInfo*)info, "dispose");
+    g_assert (vfunc != NULL);
+
+    /* Ok, maybe we should mark g_object_run_dispose as the invoker for
+     * dispose, but...eh.  It's pretty special however you cut it.
+     */
+    invoker = g_vfunc_info_get_invoker (vfunc);
+    g_assert (invoker == NULL);
+
+    /* Test vfunc with invoker on object */
+    info = g_irepository_find_by_name (repo, "Gio", "AppLaunchContext");
+    g_assert (info != NULL);
+
+    vfunc = g_object_info_find_vfunc ((GIObjectInfo*)info, "get_display");
+    g_assert (vfunc != NULL);
+
+    invoker = g_vfunc_info_get_invoker (vfunc);
+    g_assert (invoker != NULL);
+    g_assert (strcmp (g_base_info_get_name ((GIBaseInfo*)invoker), "get_display") == 0);
+
+    /* And let's be sure we can find the method directly */
+
+    invoker = g_object_info_find_method ((GIObjectInfo*)info, "get_display");
+    g_assert (invoker != NULL);
+    g_assert (strcmp (g_base_info_get_name ((GIBaseInfo*)invoker), "get_display") == 0);
+  }
+
   exit(0);
 }
diff --git a/tests/scanner/foo-1.0-expected.gir b/tests/scanner/foo-1.0-expected.gir
index 0f6b1f1..086170e 100644
--- a/tests/scanner/foo-1.0-expected.gir
+++ b/tests/scanner/foo-1.0-expected.gir
@@ -232,16 +232,26 @@ and/or use gtk-doc annotations.  -->
                glib:type-name="FooInterface"
                glib:get-type="foo_interface_get_type"
                glib:type-struct="InterfaceIface">
-      <callback name="do_foo" c:type="do_foo">
+      <virtual-method name="do_foo" invoker="do_foo">
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
         </return-value>
         <parameters>
-          <parameter name="self" transfer-ownership="none">
-            <type name="Interface" c:type="FooInterface*"/>
+          <parameter name="x" transfer-ownership="none">
+            <type name="int" c:type="int"/>
           </parameter>
         </parameters>
-      </callback>
+      </virtual-method>
+      <method name="do_foo" c:identifier="foo_interface_do_foo">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="x" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+        </parameters>
+      </method>
     </interface>
     <record name="InterfaceIface"
             c:type="FooInterfaceIface"
@@ -257,6 +267,9 @@ and/or use gtk-doc annotations.  -->
           <parameter name="self" transfer-ownership="none">
             <type name="Interface" c:type="FooInterface*"/>
           </parameter>
+          <parameter name="x" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
         </parameters>
       </callback>
     </record>
@@ -277,6 +290,29 @@ and/or use gtk-doc annotations.  -->
           <type name="int" c:type="int"/>
         </return-value>
       </function>
+      <virtual-method name="virtual_method" invoker="virtual_method">
+        <return-value transfer-ownership="none">
+          <type name="boolean" c:type="gboolean"/>
+        </return-value>
+        <parameters>
+          <parameter name="first_param" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+        </parameters>
+      </virtual-method>
+      <virtual-method name="read_fn" invoker="read">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="offset" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+          <parameter name="length" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+        </parameters>
+      </virtual-method>
       <method name="external_type" c:identifier="foo_object_external_type">
         <return-value transfer-ownership="full">
           <type name="utility.Object" c:type="UtilityObject*"/>
@@ -359,6 +395,31 @@ and/or use gtk-doc annotations.  -->
           </parameter>
         </parameters>
       </method>
+      <method name="virtual_method" c:identifier="foo_object_virtual_method">
+        <return-value transfer-ownership="none">
+          <type name="boolean" c:type="gboolean"/>
+        </return-value>
+        <parameters>
+          <parameter name="first_param" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="read"
+              c:identifier="foo_object_read"
+              doc="Read some stuff.">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="offset" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+          <parameter name="length" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+        </parameters>
+      </method>
       <property name="string" writable="1" construct="1">
         <type name="utf8" c:type="gchararray"/>
       </property>
@@ -401,6 +462,22 @@ and/or use gtk-doc annotations.  -->
           </parameter>
         </parameters>
       </callback>
+      <callback name="read_fn" c:type="read_fn">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="object" transfer-ownership="none">
+            <type name="Object" c:type="FooObject*"/>
+          </parameter>
+          <parameter name="offset" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+          <parameter name="length" transfer-ownership="none">
+            <type name="int" c:type="int"/>
+          </parameter>
+        </parameters>
+      </callback>
     </record>
     <constant name="PIE_IS_TASTY" value="3.14159">
       <type name="double"/>
@@ -467,21 +544,21 @@ and/or use gtk-doc annotations.  -->
                glib:get-type="foo_sub_interface_get_type"
                glib:type-struct="SubInterfaceIface">
       <prerequisite name="Interface"/>
+      <virtual-method name="do_bar" invoker="do_bar">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+      </virtual-method>
       <method name="do_bar" c:identifier="foo_sub_interface_do_bar">
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
         </return-value>
       </method>
-      <callback name="do_bar" c:type="do_bar">
-        <return-value transfer-ownership="none">
+      <glib:signal name="destroy-event">
+        <return-value transfer-ownership="full">
           <type name="none" c:type="void"/>
         </return-value>
-        <parameters>
-          <parameter name="self" transfer-ownership="none">
-            <type name="SubInterface" c:type="FooSubInterface*"/>
-          </parameter>
-        </parameters>
-      </callback>
+      </glib:signal>
     </interface>
     <record name="SubInterfaceIface"
             c:type="FooSubInterfaceIface"
@@ -489,6 +566,16 @@ and/or use gtk-doc annotations.  -->
       <field name="parent_iface">
         <type name="GObject.TypeInterface" c:type="GTypeInterface"/>
       </field>
+      <callback name="destroy_event" c:type="destroy_event">
+        <return-value transfer-ownership="none">
+          <type name="none" c:type="void"/>
+        </return-value>
+        <parameters>
+          <parameter name="self" transfer-ownership="none">
+            <type name="SubInterface" c:type="FooSubInterface*"/>
+          </parameter>
+        </parameters>
+      </callback>
       <callback name="do_bar" c:type="do_bar">
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
diff --git a/tests/scanner/foo-1.0-expected.tgir b/tests/scanner/foo-1.0-expected.tgir
index f8e1ee5..1d82b6a 100644
--- a/tests/scanner/foo-1.0-expected.tgir
+++ b/tests/scanner/foo-1.0-expected.tgir
@@ -161,7 +161,28 @@
       <member name="second" value="2"/>
       <member name="third" value="4"/>
     </bitfield>
-    <interface name="Interface" glib:type-name="FooInterface" glib:get-type="foo_interface_get_type" glib:type-struct="InterfaceIface"/>
+    <interface name="Interface" glib:type-name="FooInterface" glib:get-type="foo_interface_get_type" glib:type-struct="InterfaceIface">
+      <method name="do_foo" c:identifier="foo_interface_do_foo">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+        <parameters>
+          <parameter name="x" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+        </parameters>
+      </method>
+      <virtual-method name="do_foo" offset="0" invoker="do_foo">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+        <parameters>
+          <parameter name="x" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+        </parameters>
+      </virtual-method>
+    </interface>
     <record name="InterfaceIface" glib:is-gtype-struct="1">
       <field name="parent_iface">
         <type name="GObject.TypeInterface"/>
@@ -255,6 +276,29 @@
           </parameter>
         </parameters>
       </method>
+      <method name="virtual_method" c:identifier="foo_object_virtual_method">
+        <return-value transfer-ownership="none">
+          <type name="boolean"/>
+        </return-value>
+        <parameters>
+          <parameter name="first_param" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+        </parameters>
+      </method>
+      <method name="read" c:identifier="foo_object_read">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+        <parameters>
+          <parameter name="offset" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+          <parameter name="length" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+        </parameters>
+      </method>
       <property name="string" writable="1" construct="1">
         <type name="utf8"/>
       </property>
@@ -271,6 +315,29 @@
           </parameter>
         </parameters>
       </glib:signal>
+      <virtual-method name="virtual_method" offset="0" invoker="virtual_method">
+        <return-value transfer-ownership="none">
+          <type name="boolean"/>
+        </return-value>
+        <parameters>
+          <parameter name="first_param" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+        </parameters>
+      </virtual-method>
+      <virtual-method name="read_fn" offset="0" invoker="read">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+        <parameters>
+          <parameter name="offset" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+          <parameter name="length" transfer-ownership="none">
+            <type name="int"/>
+          </parameter>
+        </parameters>
+      </virtual-method>
     </class>
     <record name="ObjectClass" glib:is-gtype-struct="1">
       <field name="parent_class">
@@ -342,6 +409,16 @@
           <type name="none"/>
         </return-value>
       </method>
+      <glib:signal name="destroy-event" when="LAST">
+        <return-value transfer-ownership="full">
+          <type name="none"/>
+        </return-value>
+      </glib:signal>
+      <virtual-method name="do_bar" offset="0" invoker="do_bar">
+        <return-value transfer-ownership="none">
+          <type name="none"/>
+        </return-value>
+      </virtual-method>
     </interface>
     <record name="SubInterfaceIface" glib:is-gtype-struct="1">
       <field name="parent_iface">
diff --git a/tests/scanner/foo.c b/tests/scanner/foo.c
index 0488260..8a9283d 100644
--- a/tests/scanner/foo.c
+++ b/tests/scanner/foo.c
@@ -1,4 +1,5 @@
 #include "foo.h"
+#include "girepository.h"
 
 /* A hidden type not exposed publicly, similar to GUPNP's XML wrapper
    object */
@@ -8,8 +9,8 @@ int foo_init_argv (int argc, char **argv);
 int foo_init_argv_address (int *argc, char ***argv);
 void foo_private_function (FooObject *foo);
 void foo_test_unsigned (unsigned int uint);
-void foo_interface_do_foo (FooInterface *self);
-void foo_do_foo (FooInterface *self);
+void foo_interface_do_foo (FooInterface *self, int x);
+void foo_do_foo (FooInterface *self, int x);
 int foo_enum_method (FooEnumType foo_enum);
 FooHidden * foo_hidden_copy (const FooHidden *boxed);
 void foo_hidden_free (FooHidden *boxed);
@@ -47,9 +48,9 @@ foo_interface_get_type (void)
   return object_type;
 }
 
-void foo_interface_do_foo (FooInterface *self)
+void foo_interface_do_foo (FooInterface *self, int x)
 {
-  FOO_INTERFACE_GET_INTERFACE(self)->do_foo (self);
+  FOO_INTERFACE_GET_INTERFACE(self)->do_foo (self, x);
 }
 
 enum {
@@ -73,6 +74,16 @@ foo_foo_interface_init (gpointer         g_iface,
   iface->do_foo = foo_do_foo;
 }
 
+enum {
+  SUBIFACE_DESTROY_EVENT,
+  SUBIFACE_LAST_SIGNAL
+};
+
+static void
+foo_sub_interface_class_init (gpointer g_class, gpointer class_data);
+
+static guint foo_subiface_signals[SUBIFACE_LAST_SIGNAL] = { 0 };
+
 GType
 foo_sub_interface_get_type (void)
 {
@@ -83,7 +94,7 @@ foo_sub_interface_get_type (void)
       object_type = g_type_register_static_simple (G_TYPE_INTERFACE,
                                                    "FooSubInterface",
                                                    sizeof (FooSubInterfaceIface),
-                                                   NULL, 0, NULL, 0);
+                                                   foo_sub_interface_class_init, 0, NULL, 0);
 
       g_type_interface_add_prerequisite (object_type, FOO_TYPE_INTERFACE);
     }
@@ -91,6 +102,20 @@ foo_sub_interface_get_type (void)
   return object_type;
 }
 
+static void
+foo_sub_interface_class_init (gpointer g_class, gpointer class_data)
+{
+  foo_subiface_signals[SUBIFACE_DESTROY_EVENT] =
+    g_signal_new ("destroy-event", FOO_TYPE_SUBINTERFACE,
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (FooSubInterfaceIface, destroy_event),
+                  NULL, NULL,
+                  gi_cclosure_marshal_generic,
+                  G_TYPE_NONE,
+                  0,
+                  G_TYPE_NONE);
+}
+
 void foo_sub_interface_do_bar (FooSubInterface *self)
 {
   FOO_SUBINTERFACE_GET_INTERFACE(self)->do_bar (self);
@@ -191,7 +216,7 @@ foo_object_take_all (FooObject *object, int x, ...)
 }
 
 void
-foo_do_foo (FooInterface *self)
+foo_do_foo (FooInterface *self, int x)
 {
 
 
@@ -214,6 +239,22 @@ foo_object_dup_name (FooObject *object)
   return g_strdup ("foo");
 }
 
+/**
+ * foo_object_read:
+ * @object: obj
+ * @offset: offset
+ * @length: length
+ *
+ * Read some stuff.
+ *
+ * Virtual: read_fn
+ */
+void
+foo_object_read (FooObject *object, int offset, int length)
+{
+
+}
+
 G_DEFINE_ABSTRACT_TYPE (FooSubobject, foo_subobject, FOO_TYPE_OBJECT);
 
 static void
diff --git a/tests/scanner/foo.h b/tests/scanner/foo.h
index da30df3..02f3cfe 100644
--- a/tests/scanner/foo.h
+++ b/tests/scanner/foo.h
@@ -48,15 +48,23 @@ struct _FooInterfaceIface
 {
   GTypeInterface parent_iface;
 
-  void (*do_foo) (FooInterface *self);
+  void (*do_foo) (FooInterface *self, int x);
 };
 
 GType                 foo_interface_get_type       (void) G_GNUC_CONST;
 
+void foo_interface_do_foo (FooInterface *iface, int x);
+
 struct _FooSubInterfaceIface
 {
   GTypeInterface parent_iface;
 
+  /* signals */
+
+  void (*destroy_event) (FooSubInterface *self);
+
+  /* virtual table */
+
   void (*do_bar) (FooSubInterface *self);
 };
 
@@ -76,6 +84,9 @@ struct _FooObjectClass
   GObjectClass parent_class;
 
   gboolean (* virtual_method) (FooObject *object, int first_param);
+
+  /* Intended to match GFile */
+  void (*read_fn) (FooObject *object, int offset, int length);
 };
 
 gint                  foo_init                     (void);
@@ -105,6 +116,10 @@ char *                foo_object_dup_name          (FooObject *object);
 
 void                  foo_object_handle_glyph      (FooObject *object, UtilityGlyph glyph);
 
+gboolean              foo_object_virtual_method    (FooObject *object, int first_param);
+
+void                  foo_object_read              (FooObject *object, int offset, int length);
+
 int                   foo_object_static_meth       ();
 
 struct _FooSubobject
diff --git a/tools/generate.c b/tools/generate.c
index c4d7291..48d7dfb 100644
--- a/tools/generate.c
+++ b/tools/generate.c
@@ -869,6 +869,7 @@ write_vfunc_info (const gchar *namespace,
 {
   GIVFuncInfoFlags flags;
   const gchar *name;
+  GIFunctionInfo *invoker;
   gboolean deprecated;
   gint offset;
 
@@ -876,8 +877,9 @@ write_vfunc_info (const gchar *namespace,
   flags = g_vfunc_info_get_flags (info);
   deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
   offset = g_vfunc_info_get_offset (info);
+  invoker = g_vfunc_info_get_invoker (info);
 
-  xml_start_element (file, "vfunc");
+  xml_start_element (file, "virtual-method");
   xml_printf (file, " name=\"%s\"", name);
 
   if (deprecated)
@@ -893,9 +895,12 @@ write_vfunc_info (const gchar *namespace,
     
   xml_printf (file, " offset=\"%d\"", offset);
 
+  if (invoker)
+    xml_printf (file, " invoker=\"%s\"", g_base_info_get_name ((GIBaseInfo*)invoker));
+
   write_callable_info (namespace, (GICallableInfo*)info, file);
 
-  xml_end_element (file, "vfunc");
+  xml_end_element (file, "virtual-method");
 }
 
 static void



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