Index: tests/test_subtype.py
===================================================================
--- tests/test_subtype.py	(revision 993)
+++ tests/test_subtype.py	(working copy)
@@ -270,3 +270,20 @@
         foo = Foo()
         d = foo.__dict__
 
+    def test_gtk_buildable_virtual_method(self):
+        """Bug 566571."""
+
+        # Currently the bug is not solved, so skip the test.
+        return
+
+        class CustomDialog(gtk.Dialog):
+            __gtype_name__ = 'CustomDialog'
+            def do_parser_finished(self, build):
+                self.built = True
+
+        builder = gtk.Builder()
+        builder.add_from_string('<interface><object class="CustomDialog" id="main"/></interface>')
+        dialog = builder.get_object('main')
+
+        self.assert_(isinstance(dialog, gtk.Buildable))
+        self.assert_(hasattr(dialog, 'built'))

Property changes on: tests/runtests.py
___________________________________________________________________
Added: svn:executable
   + *

Index: gobject/gobjectmodule.c
===================================================================
--- gobject/gobjectmodule.c	(revision 993)
+++ gobject/gobjectmodule.c	(working copy)
@@ -1053,6 +1053,73 @@
     }
 }
 
+
+/*  This implementation is bad, see bug 566571 for an example why.
+ *  Instead of scanning explicitly declared bases for interfaces, we
+ *  should automatically initialize all implemented interfaces to
+ *  prevent bugs like that one.  However, this will lead to
+ *  performance degradation as each virtual method in derived classes
+ *  will round-trip through do_*() stuff, *even* if it is not
+ *  overriden.  We need to teach codegen to retain parent method
+ *  instead of setting virtual to *_proxy_do_*() if corresponding
+ *  do_*() is not overriden.  Ok, that was a messy explanation.
+ */
+static void
+pyg_type_add_interfaces(PyTypeObject *class, GType instance_type,
+                        PyObject *bases, gboolean new_interfaces,
+                        GType *parent_interfaces, guint n_parent_interfaces)
+{
+    int i;
+
+    if (!bases) {
+        g_warning("type has no bases");
+        return;
+    }
+
+    for (i = 0; i < PyTuple_GET_SIZE(bases); ++i) {
+        guint k;
+        PyTypeObject *base = (PyTypeObject *) PyTuple_GET_ITEM(bases, i);
+        GType itype;
+        gboolean is_new = TRUE;
+        const GInterfaceInfo *iinfo;
+        GInterfaceInfo iinfo_copy;
+
+        if (!PyType_IsSubtype(base, &PyGInterface_Type))
+            continue;
+
+        itype = pyg_type_from_object((PyObject *) base);
+
+        /* Happens for _implementations_ of an interface. */
+        if (!G_TYPE_IS_INTERFACE(itype))
+            continue;
+
+        for (k = 0; k < n_parent_interfaces; ++k) {
+            if (parent_interfaces[k] == itype) {
+                is_new = FALSE;
+                break;
+            }
+        }
+
+        if ((new_interfaces && !is_new) || (!new_interfaces && is_new))
+            continue;
+
+        iinfo = pyg_lookup_interface_info(itype);
+        if (!iinfo) {
+            gchar *error;
+            error = g_strdup_printf("Interface type %s "
+                                    "has no Python implementation support",
+                                    base->tp_name);
+            PyErr_Warn(PyExc_RuntimeWarning, error);
+            g_free(error);
+            continue;
+        }
+
+        iinfo_copy = *iinfo;
+        iinfo_copy.interface_data = class;
+        g_type_add_interface_static(instance_type, itype, &iinfo_copy);
+    }
+}
+
 int
 pyg_type_register(PyTypeObject *class, const char *type_name)
 {
@@ -1060,7 +1127,6 @@
     GType parent_type, instance_type;
     GType *parent_interfaces;
     guint n_parent_interfaces;
-    gint i;
     GTypeQuery query;
     gpointer gclass;
     gpointer has_new_constructor_api;
@@ -1082,9 +1148,8 @@
 
     /* find the GType of the parent */
     parent_type = pyg_type_from_object((PyObject *)class);
-    if (!parent_type) {
+    if (!parent_type)
 	return -1;
-    }
 
     parent_interfaces = g_type_interfaces(parent_type, &n_parent_interfaces);
 
@@ -1139,54 +1204,18 @@
 			     pyg_object_descr_doc_get());
     }
 
-      /* Register interfaces that are already defined by the parent
-       * type and are going to be reimplemented  */
-    if (class->tp_bases) {
-        for (i = 0; i < PyTuple_GET_SIZE(class->tp_bases); ++i)
-        {
-            PyTypeObject *base =
-		(PyTypeObject *) PyTuple_GET_ITEM(class->tp_bases, i);
-            GType itype;
-            const GInterfaceInfo *iinfo;
-            GInterfaceInfo iinfo_copy;
-            guint parent_interface_iter;
+    /* Register interfaces that are already defined by the parent
+     * type and are going to be reimplemented.
+     *
+     * FIXME: Why do we do this in two passes at all?  See changelog
+     * for revision 592 in SVN (starts with "Fix type registration
+     * once more to account for all corner cases...").  Changelog
+     * entry describes what is done, but not what for.  No tests
+     * either.
+     */
+    pyg_type_add_interfaces(class, instance_type, class->tp_bases, FALSE,
+                            parent_interfaces, n_parent_interfaces);
 
-            if (((PyTypeObject *) base)->tp_base != &PyGInterface_Type)
-                continue;
-
-            itype = pyg_type_from_object((PyObject *) base);
-
-              /* ignore interface unless defined in parent type */
-            if (n_parent_interfaces == 0)
-                continue;
-            for (parent_interface_iter = 0;
-                 parent_interface_iter < n_parent_interfaces;
-                 ++parent_interface_iter)
-            {
-                if (parent_interfaces[parent_interface_iter] == itype)
-                    break;
-            }
-            if (parent_interface_iter == n_parent_interfaces)
-                continue;
-
-            iinfo = pyg_lookup_interface_info(itype);
-            if (!iinfo) {
-                char *msg;
-                msg = g_strdup_printf("Interface type %s "
-                                      "has no python implementation support",
-                                      base->tp_name);
-                PyErr_Warn(PyExc_RuntimeWarning, msg);
-                g_free(msg);
-                continue;
-            }
-
-            iinfo_copy = *iinfo;
-            iinfo_copy.interface_data = class;
-            g_type_add_interface_static(instance_type, itype, &iinfo_copy);
-        }
-    } else
-        g_warning("type has no tp_bases");
-
     /* we look this up in the instance dictionary, so we don't
      * accidentally get a parent type's __gsignals__ attribute. */
     gsignals = PyDict_GetItemString(class->tp_dict, "__gsignals__");
@@ -1231,55 +1260,12 @@
 	PyErr_Clear();
     }
 
-      /* Register new interfaces, that are _not_ already defined by
-       * the parent type  */
-    if (class->tp_bases) {
-        for (i = 0; i < PyTuple_GET_SIZE(class->tp_bases); ++i)
-        {
-            PyTypeObject *base =
-		(PyTypeObject *) PyTuple_GET_ITEM(class->tp_bases, i);
-            GType itype;
-            const GInterfaceInfo *iinfo;
-            GInterfaceInfo iinfo_copy;
-            guint parent_interface_iter;
+    /* Register new interfaces, that are _not_ already defined by
+     * the parent type.  FIXME: See above.
+     */
+    pyg_type_add_interfaces(class, instance_type, class->tp_bases, TRUE,
+                            parent_interfaces, n_parent_interfaces);
 
-            if (((PyTypeObject *) base)->tp_base != &PyGInterface_Type)
-                continue;
-
-            itype = pyg_type_from_object((PyObject *) base);
-
-              /* ignore interface if already defined in parent type */
-            if (n_parent_interfaces != 0) {
-                for (parent_interface_iter = 0;
-                     parent_interface_iter < n_parent_interfaces;
-                     ++parent_interface_iter)
-                {
-                    if (parent_interfaces[parent_interface_iter] == itype)
-                        break;
-                }
-
-                if (parent_interface_iter < n_parent_interfaces)
-                    continue;
-            }
-
-            iinfo = pyg_lookup_interface_info(itype);
-            if (!iinfo) {
-                char *msg;
-                msg = g_strdup_printf("Interface type %s "
-                                      "has no python implementation support",
-                                      base->tp_name);
-                PyErr_Warn(PyExc_RuntimeWarning, msg);
-                g_free(msg);
-                continue;
-            }
-
-            iinfo_copy = *iinfo;
-            iinfo_copy.interface_data = class;
-            g_type_add_interface_static(instance_type, itype, &iinfo_copy);
-        }
-    } else
-        g_warning("type has no tp_bases");
-
     gclass = g_type_class_ref(instance_type);
     if (pyg_run_class_init(instance_type, gclass, class)) {
         g_type_class_unref(gclass);
