]> git.draconx.ca Git - gob-dx.git/commitdiff
Fix dynamic interface implementation.
authorNick Bowler <nbowler@draconx.ca>
Thu, 6 Feb 2020 05:07:44 +0000 (00:07 -0500)
committerNick Bowler <nbowler@draconx.ca>
Fri, 7 Feb 2020 02:17:06 +0000 (21:17 -0500)
When a dynamic type implements an interface and derives from a type
which implements the same interface, the g_type_module_add_interface
function does not actually work: no interface will be added to the
dynamic type in this case.

The bug is in the GTypeModule class implementation in gobject,
the actual type system has no such limitation.  It is reasonably
straightforward to hack around the problem in GOB.

src/main.c
tests/interface.at

index 424f12c0fcfd48584e88a4e571d1fe0fb9329ee6..6a0c7911cadee6726195ce40eb05754cb288b28b 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) 1999,2000 the Free Software Foundation.
  * Copyright (C) 2000 Eazel, Inc.
  * Copyright (C) 2001-2011 George (Jiri) Lebl
+ * Copyright © 2019-2020 Nick Bowler
  *
  * Author: George (Jiri) Lebl
  *
@@ -1129,20 +1130,46 @@ add_interfaces (void)
 static void
 add_dynamic_interfaces(void)
 {
-       GList *li;
-       for (li = ((Class *)class)->interfaces;
-            li != NULL;
-            li = li ->next) {
-               char *name = replace_sep (li->data, '_');
-               char *type = make_pre_macro (li->data, "TYPE");
+       GList *li = ((Class *)class)->interfaces;
 
-               out_printf(out,
-                          "\t\tg_type_module_add_interface(\n"
-                          "\t\t\ttype_module,\n"
-                          "\t\t\t%s_type_id,\n"
-                          "\t\t\t%s,\n"
-                          "\t\t\t&%s_info);\n",
-                          funcbase, type, name);
+       if (li) {
+               /*
+                * Hack to work around bug in g_type_module_add_interface,
+                * which will fail to add an interface to types that derive
+                * from something that also implements the same interface.
+                *
+                * The actual GType system does not have any such problem,
+                * and the GTypeModule implementation details relied upon
+                * here have not changed once since the feature was first
+                * implemented almost 20 years ago.
+                */
+               out_printf(out, "\t\tstruct _ModuleInterfaceInfo {\n"
+                               "\t\t\tgboolean loaded;\n"
+                               "\t\t\tGType instance_type;\n"
+                               "\t\t\tGType interface_type;\n"
+                               "\t\t\tGInterfaceInfo info;\n"
+                               "\t\t} *modinfo;\n");
+       }
+
+       for (; li; li = li->next) {
+               char *name = replace_sep(li->data, '_');
+               char *type = make_pre_macro(li->data, "TYPE");
+
+               out_printf(out, "\n"
+                               "\t\tmodinfo = g_malloc(sizeof *modinfo);\n"
+                               "\t\tmodinfo->loaded = TRUE;\n"
+                               "\t\tmodinfo->instance_type = %s_type_id;\n"
+                               "\t\tmodinfo->interface_type = %s;\n"
+                               "\t\tmodinfo->info = %s_info;\n"
+                               "\t\tg_type_add_interface_dynamic\n"
+                               "\t\t\t( modinfo->instance_type\n"
+                               "\t\t\t, modinfo->interface_type\n"
+                               "\t\t\t, G_TYPE_PLUGIN(type_module)\n"
+                               "\t\t\t);\n"
+                               "\t\ttype_module->interface_infos = g_slist_prepend\n"
+                               "\t\t\t( type_module->interface_infos\n"
+                               "\t\t\t, modinfo\n"
+                               "\t\t\t);\n", funcbase, type, name);
 
                g_free(type);
                g_free(name);
index 82771e17035b878a3bf3bc50eab70d23deb7c9c3..c8e2a9c88d7f70668bf28f4e2bd18a64bedb37ce 100644 (file)
@@ -232,8 +232,6 @@ TEST_COMPILE_GOBJECT([main.c], [0], [], [ignore])
 AT_CHECK([$CC $CFLAGS $LDFLAGS $LIBGOBJECT_LIBS -o main \
   test-a.o test-b.o test-b-mod.o test-fooable.o main.o])
 
-# Currently borked
-AT_XFAIL_IF([:])
 AT_CHECK([./main], [0], [Test:A foo called
 42
 Test:B foo called
@@ -286,8 +284,6 @@ TEST_COMPILE_GOBJECT([main.c], [0], [], [ignore])
 AT_CHECK([$CC $CFLAGS $LDFLAGS $LIBGOBJECT_LIBS -o main \
   test-a.o test-a-mod.o test-b.o test-b-mod.o test-fooable.o main.o])
 
-# Currently borked
-AT_XFAIL_IF([:])
 AT_CHECK([./main], [0], [Test:A foo called
 42
 Test:B foo called