]> git.draconx.ca Git - gob-dx.git/blobdiff - src/main.c
Implement chaining of interface methods.
[gob-dx.git] / src / main.c
index 6a0c7911cadee6726195ce40eb05754cb288b28b..c7171c50fc441390d82d9d9cdf7b43926a650384 100644 (file)
@@ -954,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)
 {
@@ -1003,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
@@ -1037,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;
 
@@ -1047,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);
@@ -3053,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)
 {
@@ -3068,6 +3132,7 @@ put_method(Method *m)
                        g_free(doc);
                }
        }
+
        switch(m->method) {
        case REGULAR_METHOD:
                if(m->line_no > 0)
@@ -3078,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: