X-Git-Url: http://git.draconx.ca/gitweb/gob-dx.git/blobdiff_plain/4f931a71edce4d7456c233487703a894410fd599..154af5b3783df5a53759b700db95b88a1e9365ab:/src/main.c diff --git a/src/main.c b/src/main.c index 424f12c..5767215 100644 --- a/src/main.c +++ b/src/main.c @@ -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 * @@ -21,7 +22,7 @@ * USA. */ -#include "config.h" +#include #include #include #include @@ -953,6 +954,59 @@ add_signal_prots(Method *m) out_printf (out, "}\n\n"); } +static char * +interface_type(const char *if_name) +{ + char *rawtype = remove_sep(if_name); + char *end = "", *typename; + + if (!gtk3_ok) { + /* + * EEEK! evil, we should have some sort of option + * to force this for arbitrary interfaces, since + * some are Class and some are Iface. Glib is shite + * in consistency. + */ + + if (strcmp (rawtype, "GtkEditable") == 0 + || strcmp (rawtype, "GTypePlugin") == 0) + { + end = "Class"; + } else { + /* We'll assume Iface is the standard ending */ + end = "Iface"; + } + } else { + /* GTK3 doesn't need Iface end */ + end = "Interface"; + } + + typename = g_strconcat(rawtype, end, (char *)NULL); + g_free(rawtype); + + return typename; +} + +static void +define_parent_interface_refs(Class *c) +{ + GList *li; + + if (!c->interfaces) + return; + + out_printf(out, "\n/* parent class interface implementations */\n"); + for (li = c->interfaces; li != NULL; li = li->next) { + char *name = replace_sep(li->data, '_'); + char *type = interface_type(li->data); + + out_printf (out, "static %s *%s_parent_iface;\n", type, name); + + g_free(name); + g_free(type); + } +} + static void add_enums(Class *c) { @@ -1002,7 +1056,9 @@ add_enums(Class *c) "static guint object_signals[LAST_SIGNAL] = {0};\n\n"); out_printf(out, "/* pointer to the class of our parent */\n"); - out_printf(out, "static %sClass *parent_class = NULL;\n\n", ptypebase); + out_printf(out, "static %sClass *parent_class = NULL;\n", ptypebase); + define_parent_interface_refs(c); + out_printf(out, "\n"); } static void @@ -1036,7 +1092,7 @@ add_interface_methods (Class *c, const char *interface) } static void -add_interface_inits (Class *c) +add_interface_inits(Class *c) { GList *li; @@ -1046,39 +1102,19 @@ add_interface_inits (Class *c) out_printf(out, "\n"); for (li = c->interfaces; li != NULL; li = li->next) { - const char *interface = li->data; - const char *end; - char *name = replace_sep (interface, '_'); - char *type = remove_sep (interface); + char *name = replace_sep(li->data, '_'); + char *type = interface_type(li->data); - if(!gtk3_ok) - { - /* EEEK! evil, we should have some sort of option - * to force this for arbitrary interfaces, since - * some are Class and some are Iface. Glib is shite - * in consistency. */ - - if (strcmp (type, "GtkEditable") == 0 || - strcmp (type, "GTypePlugin") == 0) - end = "Class"; - else - // We'll assume Iface is the standard ending - end = "Iface"; - } - else - { - /*GTK3 doesn't need Iface end*/ - end="Interface"; - } - - out_printf (out, "\nstatic void\n" - "___%s_init (%s%s *iface)\n" - "{\n", - name, type, end); + out_printf(out, "static void\n" + "___%s_init (%s *iface)\n" + "{\n", name, type); - add_interface_methods (c, interface); + add_interface_methods(c, li->data); - out_printf (out, "}\n\n"); + out_printf(out, "\t%s_parent_iface\n", name); + out_printf(out, for_cpp ? "\t\t= (%s *)" : "\t\t= ", type); + out_printf(out, "g_type_interface_peek_parent(iface);\n" + "}\n\n"); g_free (name); g_free (type); @@ -1129,20 +1165,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); @@ -3026,6 +3088,35 @@ get_arg_names_for_macro (Method *m) return g_string_free (gs, FALSE); } +static gboolean method_is_void(Method *m) +{ + return !strcmp(m->mtype->name, "void") && !m->mtype->pointer; +} + +static const char *method_err_retval(Method *m) +{ + if (method_is_void(m)) + return "(void)0"; + if (m->onerror) + return m->onerror; + return "0"; +} + +static void +put_interface_parent_handler(Method *m) +{ + const char *errval = method_err_retval(m); + char *name = replace_sep(m->interface, '_'); + char *args = get_arg_names_for_macro(m); + + out_printf(out, "#define PARENT_HANDLER(%s) (%s_parent_iface \\\n" + "\t? %s_parent_iface->%s(%s) \\\n" + "\t: %s)\n", args, name, name, m->id, args, errval); + + g_free(name); + g_free(args); +} + static void put_method(Method *m) { @@ -3041,6 +3132,7 @@ put_method(Method *m) g_free(doc); } } + switch(m->method) { case REGULAR_METHOD: if(m->line_no > 0) @@ -3051,7 +3143,18 @@ put_method(Method *m) else /* PUBLIC, PROTECTED */ print_method(out, "", "\n", "", " ", "", "\n", m, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE); + + if (m->interface) { + out_addline_outfile(out); + put_interface_parent_handler(m); + } + print_method_body(m, TRUE, TRUE); + + if (m->interface) { + out_printf(out, "#undef PARENT_HANDLER\n"); + } + /* the outfile line was added above */ break; case SIGNAL_FIRST_METHOD: