[libpeas] Allow multiple interfaces for all extensions



commit 38f859208eb1d7a2eab9afc218bf41d67b389725
Author: Garrett Regier <garrettregier gmail com>
Date:   Thu Oct 27 16:38:54 2011 -0700

    Allow multiple interfaces for all extensions
    
    Instead of only implementing the required interface implement
    every interface that type implements.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=626644

 libpeas/peas-extension-subclasses.c                |  113 ++++++++++-------
 libpeas/peas-extension-subclasses.h                |    4 +-
 libpeas/peas-extension-wrapper.c                   |   23 ++++-
 libpeas/peas-extension-wrapper.h                   |    5 +
 libpeas/peas-extension.c                           |   74 +++++++++--
 libpeas/peas-introspection.c                       |  132 +++++++++++++++++---
 libpeas/peas-introspection.h                       |   17 ++-
 loaders/c/peas-plugin-loader-c.c                   |    2 +-
 loaders/gjs/peas-extension-gjs.c                   |   35 ++---
 loaders/gjs/peas-extension-gjs.h                   |    1 +
 loaders/gjs/peas-plugin-loader-gjs.c               |   72 +++++++++++-
 loaders/python/peas-extension-python.c             |   19 ++--
 loaders/python/peas-extension-python.h             |    3 +-
 loaders/python/peas-plugin-loader-python.c         |    4 +-
 loaders/seed/peas-extension-seed.c                 |   26 ++---
 loaders/seed/peas-extension-seed.h                 |    7 +-
 loaders/seed/peas-plugin-loader-seed.c             |   67 ++++++++++-
 tests/libpeas/extension-set.c                      |   10 +-
 tests/libpeas/introspection/Makefile.am            |   12 +-
 .../introspection/introspection-has-prerequisite.c |   37 ++++++
 .../introspection/introspection-has-prerequisite.h |   52 ++++++++
 .../libpeas/plugins/extension-c/callable-plugin.c  |   89 +++++++++++++-
 .../libpeas/plugins/extension-c/callable-plugin.h  |    3 +
 .../plugins/extension-c/extension-c-plugin.c       |    7 +
 tests/libpeas/plugins/extension-js/extension-js.js |   19 ++-
 .../plugins/extension-python/extension-python.py   |   27 +++--
 tests/libpeas/testing/testing-extension.c          |   33 +++++-
 tests/libpeas/testing/testing-extension.h          |    2 +
 28 files changed, 722 insertions(+), 173 deletions(-)
---
diff --git a/libpeas/peas-extension-subclasses.c b/libpeas/peas-extension-subclasses.c
index 909c2aa..54870a5 100644
--- a/libpeas/peas-extension-subclasses.c
+++ b/libpeas/peas-extension-subclasses.c
@@ -31,8 +31,9 @@
 #include "peas-introspection.h"
 
 typedef struct _MethodImpl {
-  GICallableInfo *info;
-  gchar *method_name;
+  GType interface_type;
+  GIFunctionInfo *invoker_info;
+  const gchar *method_name;
   ffi_cif cif;
   ffi_closure *closure;
   guint struct_offset;
@@ -67,30 +68,33 @@ handle_method_impl (ffi_cif  *cif,
   instance = *((PeasExtensionWrapper **) args[0]);
   g_assert (PEAS_IS_EXTENSION_WRAPPER (instance));
 
-  n_args = g_callable_info_get_n_args (impl->info);
-  g_return_if_fail (n_args >= 1);
-  arguments = g_newa (GIArgument, n_args-1);
+  n_args = g_callable_info_get_n_args (impl->invoker_info);
+  g_return_if_fail (n_args >= 0);
+  arguments = g_newa (GIArgument, n_args);
 
-  for (i = 1; i < n_args; i++)
+  for (i = 0; i < n_args; i++)
     {
-      g_callable_info_load_arg (impl->info, i, &arg_info);
+      g_callable_info_load_arg (impl->invoker_info, i, &arg_info);
       g_arg_info_load_type (&arg_info, &type_info);
 
       if (g_arg_info_get_direction (&arg_info) == GI_DIRECTION_IN)
-        peas_gi_pointer_to_argument (&type_info, args[i], &arguments[i-1]);
+        peas_gi_pointer_to_argument (&type_info, args[i + 1], &arguments[i]);
       else
-        arguments[i-1].v_pointer = *((gpointer **) args[i]);
+        arguments[i].v_pointer = *((gpointer **) args[i + 1]);
     }
 
-  peas_extension_wrapper_callv (instance, impl->method_name, arguments, &return_value);
+  peas_extension_wrapper_callv (instance, impl->interface_type,
+                                impl->invoker_info, impl->method_name,
+                                arguments, &return_value);
 
-  g_callable_info_load_return_type (impl->info, &return_type_info);
+  g_callable_info_load_return_type (impl->invoker_info, &return_type_info);
   if (g_type_info_get_tag (&return_type_info) != GI_TYPE_TAG_VOID)
     peas_gi_argument_to_pointer (&return_type_info, &return_value, result);
 }
 
 static void
-create_native_closure (GIInterfaceInfo *iface_info,
+create_native_closure (GType            interface_type,
+                       GIInterfaceInfo *iface_info,
                        GIVFuncInfo     *vfunc_info,
                        MethodImpl      *impl)
 {
@@ -145,8 +149,9 @@ create_native_closure (GIInterfaceInfo *iface_info,
   callback_info = g_type_info_get_interface (type_info);
   g_assert (g_base_info_get_type (callback_info) == GI_INFO_TYPE_CALLBACK);
 
-  impl->info = g_base_info_ref (callback_info);
-  impl->method_name = g_strdup (g_base_info_get_name (invoker_info));
+  impl->interface_type = interface_type;
+  impl->invoker_info = invoker_info;
+  impl->method_name = g_base_info_get_name (invoker_info);
   impl->closure = g_callable_info_prepare_closure (callback_info, &impl->cif,
                                                    handle_method_impl, impl);
   impl->struct_offset = g_field_info_get_offset (field_info);
@@ -155,7 +160,6 @@ create_native_closure (GIInterfaceInfo *iface_info,
   g_base_info_unref (type_info);
   g_base_info_unref (field_info);
   g_base_info_unref (struct_info);
-  g_base_info_unref (invoker_info);
 }
 
 static void
@@ -185,8 +189,11 @@ implement_interface_methods (gpointer iface,
       for (i = 0; i < n_vfuncs; i++)
         {
           GIVFuncInfo *vfunc_info;
+
           vfunc_info = g_interface_info_get_vfunc (iface_info, i);
-          create_native_closure (iface_info, vfunc_info, &impls[i]);
+          create_native_closure (exten_type, iface_info,
+                                 vfunc_info, &impls[i]);
+
           g_base_info_unref ((GIBaseInfo *) vfunc_info);
         }
 
@@ -260,35 +267,42 @@ extension_subclass_get_property (GObject    *object,
 
 static void
 extension_subclass_init (GObjectClass *klass,
-                         GType         exten_type)
+                         GType        *exten_types)
 {
-  guint n_props, i;
-  gpointer iface_vtable;
-  GParamSpec **properties;
+  guint i;
 
   g_debug ("Initializing class '%s'", G_OBJECT_CLASS_NAME (klass));
 
-  iface_vtable = g_type_default_interface_peek (exten_type);
-  properties = g_object_interface_list_properties (iface_vtable, &n_props);
+  klass->set_property = extension_subclass_set_property;
+  klass->get_property = extension_subclass_get_property;
 
-  if (n_props > 0)
+  for (i = 0; exten_types[i] != 0; ++i)
     {
-      klass->set_property = extension_subclass_set_property;
-      klass->get_property = extension_subclass_get_property;
+      guint n_props, j;
+      gpointer iface_vtable;
+      GParamSpec **properties;
 
-      for (i = 0; i < n_props; ++i)
+      iface_vtable = g_type_default_interface_peek (exten_types[i]);
+      properties = g_object_interface_list_properties (iface_vtable, &n_props);
+
+      if (n_props > 0)
         {
-          const gchar *property_name = g_param_spec_get_name (properties[i]);
+          for (j = 0; j < n_props; ++j)
+            {
+              const gchar *property_name;
+
+              property_name = g_param_spec_get_name (properties[j]);
 
-          g_object_class_override_property (klass, i + 1, property_name);
+              g_object_class_override_property (klass, j + 1, property_name);
 
-          g_debug ("Overrided '%s:%s' for '%s' proxy",
-                   g_type_name (exten_type), property_name,
-                   G_OBJECT_CLASS_NAME (klass));
+              g_debug ("Overrided '%s:%s' for '%s' proxy",
+                       g_type_name (exten_types[i]), property_name,
+                       G_OBJECT_CLASS_NAME (klass));
+            }
         }
-    }
 
-  g_free (properties);
+      g_free (properties);
+    }
 
   g_debug ("Initialized class '%s'", G_OBJECT_CLASS_NAME (klass));
 }
@@ -300,17 +314,24 @@ extension_subclass_instance_init (GObject *instance)
 }
 
 GType
-peas_extension_register_subclass (GType parent_type,
-                                  GType extension_type)
+peas_extension_register_subclass (GType  parent_type,
+                                  GType *extension_types)
 {
-  gchar *type_name;
+  guint i;
+  GString *type_name;
   GType the_type;
 
-  type_name = g_strdup_printf ("%s+%s",
-                               g_type_name (parent_type),
-                               g_type_name (extension_type));
+  type_name = g_string_new (g_type_name (parent_type));
+
+  for (i = 0; extension_types[i] != 0; ++i)
+    {
+      /* Use something that is not allowed in symbol names */
+      g_string_append_c (type_name, '+');
+
+      g_string_append (type_name, g_type_name (extension_types[i]));
+    }
 
-  the_type = g_type_from_name (type_name);
+  the_type = g_type_from_name (type_name->str);
 
   if (the_type == G_TYPE_INVALID)
     {
@@ -321,7 +342,7 @@ peas_extension_register_subclass (GType parent_type,
         (GBaseFinalizeFunc) NULL,
         (GClassInitFunc) extension_subclass_init,
         (GClassFinalizeFunc) NULL,
-        GSIZE_TO_POINTER (extension_type),
+        g_memdup (extension_types, sizeof (GType) * (i + 1)),
         0,
         0,
         (GInstanceInitFunc) extension_subclass_instance_init,
@@ -333,20 +354,22 @@ peas_extension_register_subclass (GType parent_type,
         NULL
       };
 
-      g_debug ("Registering new type '%s'", type_name);
+      g_debug ("Registering new type '%s'", type_name->str);
 
       g_type_query (parent_type, &query);
       type_info.class_size = query.class_size;
       type_info.instance_size = query.instance_size;
 
-      the_type = g_type_register_static (parent_type, type_name, &type_info, 0);
+      the_type = g_type_register_static (parent_type, type_name->str,
+                                         &type_info, 0);
 
       iface_info.interface_data = GSIZE_TO_POINTER (the_type);
 
-      g_type_add_interface_static (the_type, extension_type, &iface_info);
+      for (i = 0; extension_types[i] != 0; ++i)
+        g_type_add_interface_static (the_type, extension_types[i], &iface_info);
     }
 
-  g_free (type_name);
+  g_string_free (type_name, TRUE);
 
   return the_type;
 }
diff --git a/libpeas/peas-extension-subclasses.h b/libpeas/peas-extension-subclasses.h
index 1509170..05efa92 100644
--- a/libpeas/peas-extension-subclasses.h
+++ b/libpeas/peas-extension-subclasses.h
@@ -26,8 +26,8 @@
 
 G_BEGIN_DECLS
 
-GType         peas_extension_register_subclass      (GType parent_type,
-                                                     GType extension_type);
+GType         peas_extension_register_subclass      (GType  parent_type,
+                                                     GType *extension_types);
 
 G_END_DECLS
 
diff --git a/libpeas/peas-extension-wrapper.c b/libpeas/peas-extension-wrapper.c
index 1232ea2..6021a85 100644
--- a/libpeas/peas-extension-wrapper.c
+++ b/libpeas/peas-extension-wrapper.c
@@ -45,11 +45,27 @@ peas_extension_wrapper_constructed (GObject *object)
 }
 
 static void
+peas_extension_wrapper_dispose (GObject *object)
+{
+  PeasExtensionWrapper *exten = PEAS_EXTENSION_WRAPPER (object);
+
+  if (exten->interfaces != NULL)
+    {
+      g_free (exten->interfaces);
+      exten->interfaces = NULL;
+    }
+
+  if (G_OBJECT_CLASS (peas_extension_wrapper_parent_class)->dispose != NULL)
+    G_OBJECT_CLASS (peas_extension_wrapper_parent_class)->dispose (object);
+}
+
+static void
 peas_extension_wrapper_class_init (PeasExtensionWrapperClass *klass)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
   object_class->constructed = peas_extension_wrapper_constructed;
+  object_class->dispose = peas_extension_wrapper_dispose;
 
   /* Don't add properties as they could shadow the instance's
    * and C plugins would not have the property.
@@ -66,6 +82,8 @@ peas_extension_wrapper_get_extension_type (PeasExtensionWrapper *exten)
 
 gboolean
 peas_extension_wrapper_callv (PeasExtensionWrapper *exten,
+                              GType                 interface_type,
+                              GICallableInfo       *method_info,
                               const gchar          *method_name,
                               GIArgument           *args,
                               GIArgument           *return_value)
@@ -73,8 +91,11 @@ peas_extension_wrapper_callv (PeasExtensionWrapper *exten,
   PeasExtensionWrapperClass *klass;
 
   g_return_val_if_fail (PEAS_IS_EXTENSION_WRAPPER (exten), FALSE);
+  g_return_val_if_fail (interface_type != G_TYPE_INVALID, FALSE);
+  g_return_val_if_fail (method_info != NULL, FALSE);
   g_return_val_if_fail (method_name != NULL, FALSE);
 
   klass = PEAS_EXTENSION_WRAPPER_GET_CLASS (exten);
-  return klass->call (exten, method_name, args, return_value);
+  return klass->call (exten, interface_type, method_info,
+                      method_name, args, return_value);
 }
diff --git a/libpeas/peas-extension-wrapper.h b/libpeas/peas-extension-wrapper.h
index 33eb0ac..a0a8a95 100644
--- a/libpeas/peas-extension-wrapper.h
+++ b/libpeas/peas-extension-wrapper.h
@@ -45,6 +45,7 @@ struct _PeasExtensionWrapper {
 
   /*< private >*/
   GType exten_type;
+  GType *interfaces;
   gboolean constructed;
 };
 
@@ -53,6 +54,8 @@ struct _PeasExtensionWrapperClass {
 
   /*< private >*/
   gboolean   (*call)                      (PeasExtensionWrapper *exten,
+                                           GType                 interface_type,
+                                           GICallableInfo       *method_info,
                                            const gchar          *method,
                                            GIArgument           *args,
                                            GIArgument           *return_value);
@@ -67,6 +70,8 @@ GType        peas_extension_wrapper_get_extension_type
                                                 (PeasExtensionWrapper *exten);
 
 gboolean     peas_extension_wrapper_callv       (PeasExtensionWrapper *exten,
+                                                 GType                 interface_type,
+                                                 GICallableInfo       *method_info,
                                                  const gchar          *method_name,
                                                  GIArgument           *args,
                                                  GIArgument           *return_value);
diff --git a/libpeas/peas-extension.c b/libpeas/peas-extension.c
index ee2bfb5..63a3407 100644
--- a/libpeas/peas-extension.c
+++ b/libpeas/peas-extension.c
@@ -67,6 +67,48 @@ peas_extension_get_type (void)
   return G_TYPE_OBJECT;
 }
 
+static GICallableInfo *
+get_method_info (PeasExtension *exten,
+                 const gchar   *method_name,
+                 GType         *interface)
+{
+  guint i;
+  GType *interfaces;
+  GICallableInfo *method_info;
+  gboolean must_free_interfaces = FALSE;
+
+  if (PEAS_IS_EXTENSION_WRAPPER (exten))
+    {
+      interfaces = PEAS_EXTENSION_WRAPPER (exten)->interfaces;
+    }
+  else
+    {
+      must_free_interfaces = TRUE;
+      interfaces = g_type_interfaces (G_TYPE_FROM_INSTANCE (exten), NULL);
+    }
+
+  for (i = 0; interfaces[i] != G_TYPE_INVALID; ++i)
+    {
+      method_info = peas_gi_get_method_info (interfaces[i], method_name);
+
+      if (method_info != NULL)
+        {
+          if (interface != NULL)
+            *interface = interfaces[i];
+
+          break;
+        }
+    }
+
+  if (must_free_interfaces)
+    g_free (interfaces);
+
+  if (method_info == NULL)
+    g_warning ("Could not find the interface for method '%s'", method_name);
+
+  return method_info;
+}
+
 /**
  * peas_extension_get_extension_type:
  * @exten: A #PeasExtension.
@@ -164,8 +206,7 @@ peas_extension_call_valist (PeasExtension *exten,
   g_return_val_if_fail (PEAS_IS_EXTENSION (exten), FALSE);
   g_return_val_if_fail (method_name != NULL, FALSE);
 
-  callable_info = peas_gi_get_method_info (peas_extension_get_extension_type (exten),
-                                           method_name);
+  callable_info = get_method_info (exten, method_name, NULL);
 
   /* Already warned */
   if (callable_info == NULL)
@@ -210,21 +251,28 @@ peas_extension_callv (PeasExtension *exten,
                       GIArgument    *args,
                       GIArgument    *return_value)
 {
+  GICallableInfo *method_info;
+  GType interface;
+  gboolean success;
+
+  method_info = get_method_info (exten, method_name, &interface);
+
+  /* Already warned */
+  if (method_info == NULL)
+    return FALSE;
+
   if (PEAS_IS_EXTENSION_WRAPPER (exten))
     {
-      return peas_extension_wrapper_callv (PEAS_EXTENSION_WRAPPER (exten),
-                                           method_name,
-                                           args,
-                                           return_value);
+      success = peas_extension_wrapper_callv (PEAS_EXTENSION_WRAPPER (exten),
+                                              interface, method_info,
+                                              method_name, args, return_value);
     }
   else
     {
-      GType gtype = peas_extension_get_extension_type (exten);
-
-      return peas_method_apply (G_OBJECT (exten),
-                                gtype,
-                                method_name,
-                                args,
-                                return_value);
+      success = peas_gi_method_call (G_OBJECT (exten), method_info, interface,
+                                     method_name, args, return_value);
     }
+
+  g_base_info_unref (method_info);
+  return success;
 }
diff --git a/libpeas/peas-introspection.c b/libpeas/peas-introspection.c
index e47b139..5aa8c6b 100644
--- a/libpeas/peas-introspection.c
+++ b/libpeas/peas-introspection.c
@@ -23,6 +23,8 @@
 #include <config.h>
 #endif
 
+#include <string.h>
+
 #include "peas-introspection.h"
 
 void
@@ -334,34 +336,130 @@ peas_gi_get_method_info (GType        iface_type,
       func_info = NULL;
     }
 
-  if (func_info == NULL)
+  g_base_info_unref (iface_info);
+  return (GICallableInfo *) func_info;
+}
+
+/* Only for interfaces! */
+GType
+peas_gi_get_type_from_name (const gchar *type_name)
+{
+  guint i;
+  gchar **ns;
+  GType the_type = G_TYPE_INVALID;
+
+  /* Hope for the best */
+  the_type = g_type_from_name (type_name);
+
+  if (the_type != G_TYPE_INVALID)
+    return the_type;
+
+
+  ns = g_irepository_get_loaded_namespaces (NULL);
+
+  /* Attempt to find it via naming conventions */
+  for (i = 0; ns[i] != NULL; ++i)
     {
-      g_warning ("Method '%s.%s' not found",
-                 g_type_name (iface_type),
-                 method_name);
+      gsize len;
+
+      /* Allow GObject and Gio Interfaces to use the fast path */
+      if (g_strcmp0 (ns[i], "GObject") == 0 || g_strcmp0 (ns[i], "Gio") == 0)
+        len = 1;
+      else
+        len = strlen (ns[i]);
+
+      /* Only compare the prefix of the type name */
+      if (strncmp (type_name, ns[i], len) == 0)
+        {
+          GIBaseInfo *info;
+
+          info = g_irepository_find_by_name (NULL, ns[i], type_name + len);
+
+          if (info != NULL)
+            {
+              if (!GI_IS_INTERFACE_INFO (info))
+                {
+                  g_base_info_unref (info);
+                }
+              else
+                {
+                  g_registered_type_info_get_g_type (info);
+                  g_base_info_unref (info);
+
+                  /* It might not be the correct interface */
+                  the_type = g_type_from_name (type_name);
+
+                  if (the_type != G_TYPE_INVALID)
+                    break;
+                }
+            }
+
+          /* Cannot break here otherwise PeasGtk symbols would not be found */
+        }
     }
 
-  g_base_info_unref (iface_info);
-  return (GICallableInfo *) func_info;
+  /* The all or nothing approach, on the upside this
+   * will cause g_type_name() on many other types to work.
+   */
+  if (the_type == G_TYPE_INVALID)
+    {
+      for (i = 0; ns[i] != NULL; ++i)
+        {
+          gint j;
+          gint n_infos;
+
+          n_infos = g_irepository_get_n_infos (NULL, ns[i]);
+
+          for (j = 0; j < n_infos; ++j)
+            {
+              GIBaseInfo *info;
+
+              info = g_irepository_get_info (NULL, ns[i], j);
+
+              if (!GI_IS_INTERFACE_INFO (info))
+                {
+                  g_base_info_unref (info);
+                }
+              else
+                {
+                  g_registered_type_info_get_g_type (info);
+                  g_base_info_unref (info);
+
+                  the_type = g_type_from_name (type_name);
+
+                  if (the_type != G_TYPE_INVALID)
+                    break;
+                }
+            }
+        }
+    }
+
+  /* Seems they did not import it */
+
+  g_free (ns);
+  return the_type;
 }
 
 gboolean
-peas_method_apply (GObject     *instance,
-                   GType        iface_type,
-                   const gchar *method_name,
-                   GIArgument  *args,
-                   GIArgument  *return_value)
+peas_gi_method_call (GObject        *instance,
+                     GICallableInfo *func_info,
+                     GType           iface_type,
+                     const gchar    *method_name,
+                     GIArgument     *args,
+                     GIArgument     *return_value)
 {
-  GICallableInfo *func_info;
   gint n_args;
   guint n_in_args, n_out_args;
   GIArgument *in_args, *out_args;
   gboolean ret = TRUE;
   GError *error = NULL;
 
-  func_info = peas_gi_get_method_info (iface_type, method_name);
-  if (func_info == NULL)
-    return FALSE;
+  g_return_val_if_fail (G_IS_OBJECT (instance), FALSE);
+  g_return_val_if_fail (func_info != NULL, FALSE);
+  g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_type), FALSE);
+  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (instance, iface_type),
+                        FALSE);
+  g_return_val_if_fail (method_name != NULL, FALSE);
 
   n_args = g_callable_info_get_n_args (func_info);
   g_return_val_if_fail (n_args >= 0, FALSE);
@@ -389,11 +487,7 @@ peas_method_apply (GObject     *instance,
       g_warning ("Error while calling '%s.%s': %s",
                  g_type_name (iface_type), method_name, error->message);
       g_error_free (error);
-      goto out;
     }
 
-out:
-  g_base_info_unref ((GIBaseInfo *) func_info);
-
   return ret;
 }
diff --git a/libpeas/peas-introspection.h b/libpeas/peas-introspection.h
index 08542d8..802f645 100644
--- a/libpeas/peas-introspection.h
+++ b/libpeas/peas-introspection.h
@@ -27,8 +27,10 @@
 
 G_BEGIN_DECLS
 
-GICallableInfo  *peas_gi_get_method_info          (GType        iface_type,
-                                                   const gchar *method_name);
+GICallableInfo  *peas_gi_get_method_info          (GType           iface_type,
+                                                   const gchar    *method_name);
+
+GType            peas_gi_get_type_from_name       (const gchar    *type_name);
 
 void             peas_gi_valist_to_arguments      (GICallableInfo *callable_info,
                                                    va_list         va_args,
@@ -40,11 +42,12 @@ void             peas_gi_argument_to_pointer      (GITypeInfo     *type_info,
 void             peas_gi_pointer_to_argument      (GITypeInfo     *type_info,
                                                    gpointer        ptr,
                                                    GIArgument     *arg);
-gboolean         peas_method_apply                (GObject     *instance,
-                                                   GType        iface_type,
-                                                   const gchar *method_name,
-                                                   GIArgument  *args,
-                                                   GIArgument  *return_value);
+gboolean         peas_gi_method_call              (GObject        *instance,
+                                                   GICallableInfo *method_info,
+                                                   GType           iface_type,
+                                                   const gchar    *method_name,
+                                                   GIArgument     *args,
+                                                   GIArgument     *return_value);
 
 G_END_DECLS
 
diff --git a/loaders/c/peas-plugin-loader-c.c b/loaders/c/peas-plugin-loader-c.c
index 5ce2421..e361578 100644
--- a/loaders/c/peas-plugin-loader-c.c
+++ b/loaders/c/peas-plugin-loader-c.c
@@ -146,7 +146,7 @@ peas_plugin_loader_c_create_extension (PeasPluginLoader *loader,
 
   /* As we do not instantiate a PeasExtensionWrapper, we have to remember
    * somehow which interface we are instantiating, to make it possible to use
-   * the deprecated peas_extension_call() method.
+   * the deprecated peas_extension_get_extension_type() method.
    */
   g_object_set_data (instance, "peas-extension-type", GUINT_TO_POINTER (exten_type));
 
diff --git a/loaders/gjs/peas-extension-gjs.c b/loaders/gjs/peas-extension-gjs.c
index 65ecaf4..694fdd7 100644
--- a/loaders/gjs/peas-extension-gjs.c
+++ b/loaders/gjs/peas-extension-gjs.c
@@ -129,6 +129,8 @@ peas_extension_gjs_dispose (GObject *object)
       gexten->js_context = NULL;
       gexten->js_object = NULL;
     }
+
+  G_OBJECT_CLASS (peas_extension_gjs_parent_class)->dispose (object);
 }
 
 static gboolean
@@ -181,15 +183,15 @@ set_out_arg (JSContext      *js_context,
 
 static gboolean
 peas_extension_gjs_call (PeasExtensionWrapper *exten,
+                         GType                 exten_type,
+                         GICallableInfo       *func_info,
                          const gchar          *method_name,
                          GIArgument           *args,
                          GIArgument           *retval)
 {
   PeasExtensionGjs *gexten = PEAS_EXTENSION_GJS (exten);
-  GType exten_type;
   gboolean success = FALSE;
   jsval js_method, js_retval;
-  GICallableInfo *func_info;
   jsval *js_args;
   CachedArg *arg_cache;
   gint i, n_args, nth_out_arg;
@@ -197,8 +199,6 @@ peas_extension_gjs_call (PeasExtensionWrapper *exten,
   gint n_out_args = 0;
   gint cached_args = 0;
 
-  exten_type = peas_extension_wrapper_get_extension_type (exten);
-
   /* Fetch the JS method we want to call */
   if (!JS_GetProperty (gexten->js_context, gexten->js_object,
                        method_name, &js_method) ||
@@ -217,16 +217,11 @@ peas_extension_gjs_call (PeasExtensionWrapper *exten,
       return FALSE;
     }
 
-  /* Prepare the arguments */
-  func_info = peas_gi_get_method_info (exten_type, method_name);
-  if (func_info == NULL)
-    return FALSE;
-
   n_args = g_callable_info_get_n_args (func_info);
   if (n_args < 0)
     {
       g_warn_if_fail (n_args >= 0);
-      goto out;
+      return FALSE;
     }
 
   js_args = g_newa (jsval, n_args);
@@ -257,7 +252,7 @@ peas_extension_gjs_call (PeasExtensionWrapper *exten,
         {
           g_warning ("Error failed to convert argument '%s'",
                      g_base_info_get_name (&arg_cache[cached_args].arg_info));
-          goto out;
+          return FALSE;
         }
 
       if (direction == GI_DIRECTION_INOUT)
@@ -272,7 +267,7 @@ peas_extension_gjs_call (PeasExtensionWrapper *exten,
             {
               g_warning ("Error failed to convert argument '%s'",
                          g_base_info_get_name (&arg_cache[cached_args].arg_info));
-              goto out;
+              return FALSE;
             }
         }
 
@@ -290,7 +285,7 @@ peas_extension_gjs_call (PeasExtensionWrapper *exten,
     {
       g_warning ("Error while calling '%s.%s'",
                  g_type_name (exten_type), method_name);
-      goto out;
+      return FALSE;
     }
 
   /* First we need to release in argument */
@@ -327,8 +322,7 @@ peas_extension_gjs_call (PeasExtensionWrapper *exten,
           !JS_IsArrayObject (gexten->js_context, JSVAL_TO_OBJECT (js_retval)))
         {
           g_warning ("Error return value is not an array");
-          success = FALSE;
-          goto out;
+          return FALSE;
         }
     }
 
@@ -366,7 +360,7 @@ peas_extension_gjs_call (PeasExtensionWrapper *exten,
               js_value == JSVAL_VOID)
             {
               g_warning ("Error failed to get out argument %i", nth_out_arg);
-              success = FALSE;
+              return FALSE;
             }
           else
             {
@@ -378,10 +372,6 @@ peas_extension_gjs_call (PeasExtensionWrapper *exten,
         }
     }
 
-out:
-
-  g_base_info_unref (func_info);
-
   return success;
 }
 
@@ -400,6 +390,7 @@ peas_extension_gjs_class_init (PeasExtensionGjsClass *klass)
 
 GObject *
 peas_extension_gjs_new (GType      exten_type,
+                        GType     *interfaces,
                         JSContext *js_context,
                         JSObject  *js_object)
 {
@@ -409,12 +400,14 @@ peas_extension_gjs_new (GType      exten_type,
   g_return_val_if_fail (js_context != NULL, NULL);
   g_return_val_if_fail (js_object != NULL, NULL);
 
-  real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_GJS, exten_type);
+  real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_GJS,
+                                                interfaces);
   gexten = PEAS_EXTENSION_GJS (g_object_new (real_type, NULL));
 
   gexten->js_context = js_context;
   gexten->js_object = js_object;
   PEAS_EXTENSION_WRAPPER (gexten)->exten_type = exten_type;
+  PEAS_EXTENSION_WRAPPER (gexten)->interfaces = interfaces;
   JS_AddObjectRoot (gexten->js_context, &gexten->js_object);
 
   return G_OBJECT (gexten);
diff --git a/loaders/gjs/peas-extension-gjs.h b/loaders/gjs/peas-extension-gjs.h
index 3012fc8..88fcf17 100644
--- a/loaders/gjs/peas-extension-gjs.h
+++ b/loaders/gjs/peas-extension-gjs.h
@@ -51,6 +51,7 @@ struct _PeasExtensionGjsClass {
 GType            peas_extension_gjs_get_type (void) G_GNUC_CONST;
 
 GObject         *peas_extension_gjs_new      (GType      exten_type,
+                                              GType     *interfaces,
                                               JSContext *js_context,
                                               JSObject  *js_object);
 
diff --git a/loaders/gjs/peas-plugin-loader-gjs.c b/loaders/gjs/peas-plugin-loader-gjs.c
index 77ef99b..34a28be 100644
--- a/loaders/gjs/peas-plugin-loader-gjs.c
+++ b/loaders/gjs/peas-plugin-loader-gjs.c
@@ -28,6 +28,8 @@
 #include <gi/repo.h>
 #include <gi/value.h>
 
+#include <libpeas/peas-introspection.h>
+
 #include "peas-plugin-loader-gjs.h"
 #include "peas-extension-gjs.h"
 
@@ -142,6 +144,19 @@ peas_plugin_loader_gjs_provides_extension  (PeasPluginLoader *loader,
          JSVAL_IS_OBJECT (extension) && !JSVAL_IS_NULL (extension);
 }
 
+static gint
+prerequisites_sort (GType *a,
+                    GType *b)
+{
+  if (g_type_is_a (*a, *b))
+    return 1;
+
+  if (g_type_is_a (*b, *a))
+    return -1;
+
+  return 0;
+}
+
 static PeasExtension *
 peas_plugin_loader_gjs_create_extension (PeasPluginLoader *loader,
                                          PeasPluginInfo   *info,
@@ -157,6 +172,9 @@ peas_plugin_loader_gjs_create_extension (PeasPluginLoader *loader,
   guint i;
   jsval js_value;
   GValue gvalue = { 0 };
+  GArray *interfaces;
+  JSObject *prop_iter;
+  jsid prop_name_id;
 
   ginfo = g_hash_table_lookup (gloader->loaded_plugins, info);
 
@@ -229,7 +247,59 @@ peas_plugin_loader_gjs_create_extension (PeasPluginLoader *loader,
 
   g_value_unset (&gvalue);
 
-  return peas_extension_gjs_new (exten_type, js_context, extension);
+
+  /* Do not add exten_type as it will be added below */
+  interfaces = g_array_new (TRUE, FALSE, sizeof (GType));
+
+  prop_iter = JS_NewPropertyIterator (js_context, ginfo->extensions);
+
+  /* If this returns FALSE then an error has occurred */
+  while (JS_NextProperty (js_context, prop_iter, &prop_name_id))
+    {
+      jsval prop_extension_ctor;
+      jsval prop_name_val;
+      gchar *prop_name;
+      GType the_type;
+
+      /* No more properties to iterate over */
+      if (prop_name_id == JSID_VOID)
+        break;
+
+      if (!JS_GetPropertyById (js_context, ginfo->extensions,
+                               prop_name_id, &prop_extension_ctor) ||
+          prop_extension_ctor != extension_ctor)
+        continue;
+
+      if (!JS_IdToValue (js_context, prop_name_id, &prop_name_val) ||
+          !JSVAL_IS_STRING (prop_name_val) ||
+          !gjs_string_to_utf8 (js_context, prop_name_val, &prop_name))
+        {
+          g_warning ("Extension '%s' in plugin '%s' in not a valid "
+                     "constructor object", prop_name,
+                     peas_plugin_info_get_module_name (info));
+          continue;
+        }
+
+      the_type = peas_gi_get_type_from_name (prop_name);
+
+      if (the_type == G_TYPE_INVALID)
+        {
+          g_warning ("Could not find GType for '%s', "
+                     "did you forget to import it?", prop_name);
+        }
+      else
+        {
+          g_array_append_val (interfaces, the_type);
+        }
+
+      g_free (prop_name);
+    }
+
+  g_array_sort (interfaces, (GCompareFunc) prerequisites_sort);
+
+  return peas_extension_gjs_new (exten_type,
+                                 (GType *) g_array_free (interfaces, FALSE),
+                                 js_context, extension);
 }
 
 static void
diff --git a/loaders/python/peas-extension-python.c b/loaders/python/peas-extension-python.c
index 1bca42d..b722561 100644
--- a/loaders/python/peas-extension-python.c
+++ b/loaders/python/peas-extension-python.c
@@ -42,22 +42,22 @@ peas_extension_python_init (PeasExtensionPython *pyexten)
 
 static gboolean
 peas_extension_python_call (PeasExtensionWrapper *exten,
+                            GType                 interface_type,
+                            GICallableInfo       *method_info,
                             const gchar          *method_name,
                             GIArgument           *args,
                             GIArgument           *retval)
 {
   PeasExtensionPython *pyexten = PEAS_EXTENSION_PYTHON (exten);
-  GType gtype;
   PyGILState_STATE state;
   GObject *instance;
   gboolean success;
 
-  gtype = peas_extension_wrapper_get_extension_type (exten);
-
   state = pyg_gil_state_ensure ();
 
   instance = pygobject_get (pyexten->instance);
-  success = peas_method_apply (instance, gtype, method_name, args, retval);
+  success = peas_gi_method_call (instance, method_info, interface_type,
+                                 method_name, args, retval);
 
   pyg_gil_state_release (state);
   return success;
@@ -135,17 +135,20 @@ peas_extension_python_class_init (PeasExtensionPythonClass *klass)
 }
 
 GObject *
-peas_extension_python_new (GType     gtype,
+peas_extension_python_new (GType     exten_type,
+                           GType    *interfaces,
                            PyObject *instance)
 {
   PeasExtensionPython *pyexten;
   GType real_type;
-
-  real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_PYTHON, gtype);
+  
+  real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_PYTHON,
+                                                interfaces);
   pyexten = PEAS_EXTENSION_PYTHON (g_object_new (real_type, NULL));
 
   pyexten->instance = instance;
-  PEAS_EXTENSION_WRAPPER (pyexten)->exten_type = gtype;
+  PEAS_EXTENSION_WRAPPER (pyexten)->exten_type = exten_type;
+  PEAS_EXTENSION_WRAPPER (pyexten)->interfaces = interfaces;
   Py_INCREF (instance);
 
   return G_OBJECT (pyexten);
diff --git a/loaders/python/peas-extension-python.h b/loaders/python/peas-extension-python.h
index 943be28..3d33489 100644
--- a/loaders/python/peas-extension-python.h
+++ b/loaders/python/peas-extension-python.h
@@ -53,7 +53,8 @@ struct _PeasExtensionPythonClass {
 
 GType            peas_extension_python_get_type (void) G_GNUC_CONST;
 
-GObject         *peas_extension_python_new      (GType        gtype,
+GObject         *peas_extension_python_new      (GType        exten_type,
+                                                 GType       *interfaces,
                                                  PyObject    *instance);
 
 G_END_DECLS
diff --git a/loaders/python/peas-plugin-loader-python.c b/loaders/python/peas-plugin-loader-python.c
index 5f8f1f3..23da7b4 100644
--- a/loaders/python/peas-plugin-loader-python.c
+++ b/loaders/python/peas-plugin-loader-python.c
@@ -177,7 +177,9 @@ peas_plugin_loader_python_create_extension (PeasPluginLoader *loader,
   PyObject_SetAttrString (pyobject, "plugin_info", pyplinfo);
   Py_DECREF (pyplinfo);
 
-  exten = peas_extension_python_new (exten_type, pyobject);
+  exten = peas_extension_python_new (exten_type,
+                                     g_type_interfaces (the_type, NULL),
+                                     pyobject);
   Py_DECREF (pyobject);
 
 out:
diff --git a/loaders/seed/peas-extension-seed.c b/loaders/seed/peas-extension-seed.c
index 0f16cc8..bf0e428 100644
--- a/loaders/seed/peas-extension-seed.c
+++ b/loaders/seed/peas-extension-seed.c
@@ -141,18 +141,20 @@ peas_extension_seed_dispose (GObject *object)
       sexten->js_object = NULL;
       sexten->js_context = NULL;
     }
+
+  G_OBJECT_CLASS (peas_extension_seed_parent_class)->dispose (object);
 }
 
 static gboolean
 peas_extension_seed_call (PeasExtensionWrapper *exten,
+                          GType                 exten_type,
+                          GICallableInfo       *func_info,
                           const gchar          *method_name,
                           GIArgument           *args,
                           GIArgument           *retval)
 {
   PeasExtensionSeed *sexten = PEAS_EXTENSION_SEED (exten);
-  GType exten_type;
   SeedValue js_method;
-  GICallableInfo *func_info;
   gint n_args, i;
   SeedValue *js_in_args;
   OutArg *out_args;
@@ -166,8 +168,6 @@ peas_extension_seed_call (PeasExtensionWrapper *exten,
   g_return_val_if_fail (sexten->js_context != NULL, FALSE);
   g_return_val_if_fail (sexten->js_object != NULL, FALSE);
 
-  exten_type = peas_extension_wrapper_get_extension_type (exten);
-
   /* Fetch the JS method we want to call */
   js_method = seed_object_get_property (sexten->js_context,
                                         sexten->js_object,
@@ -187,11 +187,6 @@ peas_extension_seed_call (PeasExtensionWrapper *exten,
       return FALSE;
     }
 
-  /* Prepare the arguments */
-  func_info = peas_gi_get_method_info (exten_type, method_name);
-  if (func_info == NULL)
-    return FALSE;
-
   n_args = g_callable_info_get_n_args (func_info);
   g_return_val_if_fail (n_args >= 0, FALSE);
 
@@ -278,8 +273,6 @@ peas_extension_seed_call (PeasExtensionWrapper *exten,
 
 cleanup:
 
-  g_base_info_unref ((GIBaseInfo *) func_info);
-
   if (exc == NULL)
     return TRUE;
 
@@ -303,9 +296,10 @@ peas_extension_seed_class_init (PeasExtensionSeedClass *klass)
 }
 
 GObject *
-peas_extension_seed_new (GType       exten_type,
-                         SeedContext js_context,
-                         SeedObject  js_object)
+peas_extension_seed_new (GType        exten_type,
+                         GType       *interfaces,
+                         SeedContext  js_context,
+                         SeedObject   js_object)
 {
   PeasExtensionSeed *sexten;
   GType real_type;
@@ -313,12 +307,14 @@ peas_extension_seed_new (GType       exten_type,
   g_return_val_if_fail (js_context != NULL, NULL);
   g_return_val_if_fail (js_object != NULL, NULL);
 
-  real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_SEED, exten_type);
+  real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_SEED,
+                                                interfaces);
   sexten = PEAS_EXTENSION_SEED (g_object_new (real_type, NULL));
 
   sexten->js_context = js_context;
   sexten->js_object = js_object;
   PEAS_EXTENSION_WRAPPER (sexten)->exten_type = exten_type;
+  PEAS_EXTENSION_WRAPPER (sexten)->interfaces = interfaces;
 
   seed_context_ref (sexten->js_context);
   seed_value_protect (sexten->js_context, sexten->js_object);
diff --git a/loaders/seed/peas-extension-seed.h b/loaders/seed/peas-extension-seed.h
index 6938d6a..c653d9d 100644
--- a/loaders/seed/peas-extension-seed.h
+++ b/loaders/seed/peas-extension-seed.h
@@ -50,9 +50,10 @@ struct _PeasExtensionSeedClass {
 
 GType            peas_extension_seed_get_type (void) G_GNUC_CONST;
 
-GObject         *peas_extension_seed_new      (GType           exten_type,
-                                               SeedContext     js_context,
-                                               SeedObject      js_object);
+GObject         *peas_extension_seed_new      (GType        exten_type,
+                                               GType       *interfaces,
+                                               SeedContext  js_context,
+                                               SeedObject   js_object);
 
 G_END_DECLS
 
diff --git a/loaders/seed/peas-plugin-loader-seed.c b/loaders/seed/peas-plugin-loader-seed.c
index 9349571..c900569 100644
--- a/loaders/seed/peas-plugin-loader-seed.c
+++ b/loaders/seed/peas-plugin-loader-seed.c
@@ -26,6 +26,8 @@
 #include <seed.h>
 #include <JavaScriptCore/JavaScript.h>
 
+#include <libpeas/peas-introspection.h>
+
 #include "peas-plugin-loader-seed.h"
 #include "peas-extension-seed.h"
 
@@ -136,6 +138,19 @@ peas_plugin_loader_seed_provides_extension  (PeasPluginLoader *loader,
   return extension && seed_value_is_object (sinfo->context, extension);
 }
 
+static gint
+prerequisites_sort (GType *a,
+                    GType *b)
+{
+  if (g_type_is_a (*a, *b))
+    return 1;
+
+  if (g_type_is_a (*b, *a))
+    return -1;
+
+  return 0;
+}
+
 static PeasExtension *
 peas_plugin_loader_seed_create_extension (PeasPluginLoader *loader,
                                           PeasPluginInfo   *info,
@@ -149,6 +164,8 @@ peas_plugin_loader_seed_create_extension (PeasPluginLoader *loader,
   guint i, j;
   SeedValue value;
   GValue gvalue = { 0 };
+  GArray *interfaces;
+  gchar **property_names;
 
   sinfo = (SeedInfo *) g_hash_table_lookup (sloader->loaded_plugins, info);
 
@@ -240,7 +257,55 @@ peas_plugin_loader_seed_create_extension (PeasPluginLoader *loader,
 
   g_value_unset (&gvalue);
 
-  return peas_extension_seed_new (exten_type, sinfo->context, extension);
+
+  /* Do not add exten_type as it will be added below */
+  interfaces = g_array_new (TRUE, FALSE, sizeof (GType));
+
+  property_names = seed_object_copy_property_names (sinfo->context,
+                                                    sinfo->extensions);
+
+  for (i = 0; property_names[i] != NULL; ++i)
+    {
+      gchar *property_name = property_names[i];
+      SeedValue *prop_extension_ctor;
+      GType the_type;
+
+      prop_extension_ctor = seed_object_get_property (sinfo->context,
+                                                      sinfo->extensions,
+                                                      property_name);
+
+      if (prop_extension_ctor != extension_ctor)
+        continue;
+
+      if (!seed_value_is_object (sinfo->context, extension_ctor))
+        {
+          g_warning ("Extension '%s' in plugin '%s' is not a Seed object",
+                     property_name, peas_plugin_info_get_module_name (info));
+          continue;
+        }
+
+      the_type = peas_gi_get_type_from_name (property_name);
+
+      if (the_type == G_TYPE_INVALID)
+        {
+          g_warning ("Could not find GType for '%s', "
+                     "did you forget to import it?", property_name);
+        }
+      else
+        {
+          g_array_append_val (interfaces, the_type);
+        }
+
+      g_free (property_name);
+    }
+
+  g_array_sort (interfaces, (GCompareFunc) prerequisites_sort);
+
+  g_free (property_names);
+
+  return peas_extension_seed_new (exten_type,
+                                  (GType *) g_array_free (interfaces, FALSE),
+                                  sinfo->context, extension);
 }
 
 static void
diff --git a/tests/libpeas/extension-set.c b/tests/libpeas/extension-set.c
index cb2b57a..7d889c5 100644
--- a/tests/libpeas/extension-set.c
+++ b/tests/libpeas/extension-set.c
@@ -158,9 +158,9 @@ test_extension_set_activate (PeasEngine *engine)
       g_assert (peas_engine_load_plugin (engine, info));
     }
 
-  /* Load a plugin that does not provide a PeasActivatable */
+  /* Load a plugin that does not provide a PeasActivatable
   info = peas_engine_get_plugin_info (engine, "extension-c");
-  g_assert (peas_engine_load_plugin (engine, info));
+  g_assert (peas_engine_load_plugin (engine, info)); */
 
   g_assert_cmpint (active, ==, G_N_ELEMENTS (loadable_plugins));
 
@@ -185,9 +185,9 @@ test_extension_set_deactivate (PeasEngine *engine)
 
   test_extension_set_activate (engine);
 
-  /* Unload the plugin that does not provide a PeasActivatable */
+  /* Unload the plugin that does not provide a PeasActivatable
   info = peas_engine_get_plugin_info (engine, "extension-c");
-  g_assert (peas_engine_unload_plugin (engine, info));
+  g_assert (peas_engine_unload_plugin (engine, info)); */
 
   /* To keep deps in order */
   for (i = G_N_ELEMENTS (loadable_plugins); i > 0; --i)
@@ -252,7 +252,7 @@ test_extension_set_call_invalid (PeasEngine *engine)
 
   test_extension_set_activate (engine);
 
-  testing_util_push_log_hook ("*Method 'PeasActivatable.invalid' not found*");
+  //testing_util_push_log_hook ("*Method 'PeasActivatable.invalid' not found*");
 
   extension_set = peas_extension_set_new (engine,
                                           PEAS_TYPE_ACTIVATABLE,
diff --git a/tests/libpeas/introspection/Makefile.am b/tests/libpeas/introspection/Makefile.am
index c81ee93..ff9393c 100644
--- a/tests/libpeas/introspection/Makefile.am
+++ b/tests/libpeas/introspection/Makefile.am
@@ -15,11 +15,13 @@ libintrospection_1_0_la_LDFLAGS = \
 libintrospection_1_0_la_LIBADD = $(PEAS_LIBS)
 
 libintrospection_1_0_la_SOURCES = \
-	introspection-callable.c	\
-	introspection-callable.h	\
-	introspection-properties.c	\
-	introspection-properties.h	\
-	introspection-unimplemented.c	\
+	introspection-callable.c		\
+	introspection-callable.h		\
+	introspection-has-prerequisite.c	\
+	introspection-has-prerequisite.h	\
+	introspection-properties.c		\
+	introspection-properties.h		\
+	introspection-unimplemented.c		\
 	introspection-unimplemented.h
 
 INCLUDES += $(INTROSPECTION_INCLUDES)
diff --git a/tests/libpeas/introspection/introspection-has-prerequisite.c b/tests/libpeas/introspection/introspection-has-prerequisite.c
new file mode 100644
index 0000000..625be31
--- /dev/null
+++ b/tests/libpeas/introspection/introspection-has-prerequisite.c
@@ -0,0 +1,37 @@
+/*
+ * introspection-has-prerequisite.h
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2011 Garrett Regier
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Library General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "introspection-has-prerequisite.h"
+
+#include "introspection-callable.h"
+
+G_DEFINE_INTERFACE(IntrospectionHasPrerequisite,
+                   introspection_has_prerequisite,
+                   INTROSPECTION_TYPE_CALLABLE)
+
+void
+introspection_has_prerequisite_default_init (IntrospectionHasPrerequisiteInterface *iface)
+{
+}
diff --git a/tests/libpeas/introspection/introspection-has-prerequisite.h b/tests/libpeas/introspection/introspection-has-prerequisite.h
new file mode 100644
index 0000000..4557f51
--- /dev/null
+++ b/tests/libpeas/introspection/introspection-has-prerequisite.h
@@ -0,0 +1,52 @@
+/*
+ * introspection-has-prerequisite.h
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2011 - Garrett Regier
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Library General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Library General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Library General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __INTROSPECTION_HAS_PREREQUISITE_H__
+#define __INTROSPECTION_HAS_PREREQUISITE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+/*
+ * Type checking and casting macros
+ */
+#define INTROSPECTION_TYPE_HAS_PREREQUISITE             (introspection_has_prerequisite_get_type ())
+#define INTROSPECTION_HAS_PREREQUISITE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), INTROSPECTION_TYPE_HAS_PREREQUISITE, IntrospectionHasPrerequisite))
+#define INTROSPECTION_HAS_PREREQUISITE_IFACE(obj)       (G_TYPE_CHECK_CLASS_CAST ((obj), INTROSPECTION_TYPE_HAS_PREREQUISITE, IntrospectionHasPrerequisiteInterface))
+#define INTROSPECTION_IS_HAS_PREREQUISITE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INTROSPECTION_TYPE_HAS_PREREQUISITE))
+#define INTROSPECTION_HAS_PREREQUISITE_GET_IFACE(obj)   (G_TYPE_INSTANCE_GET_INTERFACE ((obj), INTROSPECTION_TYPE_HAS_PREREQUISITE, IntrospectionHasPrerequisiteInterface))
+
+typedef struct _IntrospectionHasPrerequisite           IntrospectionHasPrerequisite; /* dummy typedef */
+typedef struct _IntrospectionHasPrerequisiteInterface  IntrospectionHasPrerequisiteInterface;
+
+struct _IntrospectionHasPrerequisiteInterface {
+  GTypeInterface g_iface;
+};
+
+/*
+ * Public methods
+ */
+GType        introspection_has_prerequisite_get_type         (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __INTROSPECTION_HAS_PREREQUISITE_H__ */
diff --git a/tests/libpeas/plugins/extension-c/callable-plugin.c b/tests/libpeas/plugins/extension-c/callable-plugin.c
index 0730115..b52ab37 100644
--- a/tests/libpeas/plugins/extension-c/callable-plugin.c
+++ b/tests/libpeas/plugins/extension-c/callable-plugin.c
@@ -30,21 +30,88 @@
 #include <libpeas/peas.h>
 
 #include "introspection-callable.h"
+#include "introspection-has-prerequisite.h"
 
 #include "callable-plugin.h"
 
+struct _TestingCallablePluginPrivate {
+  GObject *object;
+};
+
+static void introspection_activatable_iface_init (PeasActivatableInterface *iface);
 static void introspection_callable_iface_init (IntrospectionCallableInterface *iface);
+static void introspection_has_prerequisite_iface_init (IntrospectionHasPrerequisiteInterface *iface);
 
 G_DEFINE_DYNAMIC_TYPE_EXTENDED (TestingCallablePlugin,
                                 testing_callable_plugin,
                                 G_TYPE_OBJECT,
                                 0,
+                                G_IMPLEMENT_INTERFACE_DYNAMIC (PEAS_TYPE_ACTIVATABLE,
+                                                               introspection_activatable_iface_init)
                                 G_IMPLEMENT_INTERFACE_DYNAMIC (INTROSPECTION_TYPE_CALLABLE,
-                                                               introspection_callable_iface_init))
+                                                               introspection_callable_iface_init)
+                                G_IMPLEMENT_INTERFACE_DYNAMIC (INTROSPECTION_TYPE_HAS_PREREQUISITE,
+                                                               introspection_has_prerequisite_iface_init))
+
+enum {
+  PROP_0,
+  PROP_OBJECT
+};
+
+static void
+testing_callable_plugin_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  TestingCallablePlugin *plugin = TESTING_CALLABLE_PLUGIN (object);
+
+  switch (prop_id)
+    {
+    case PROP_OBJECT:
+      plugin->priv->object = g_value_get_object (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+testing_callable_plugin_get_property (GObject    *object,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+  TestingCallablePlugin *plugin = TESTING_CALLABLE_PLUGIN (object);
+
+  switch (prop_id)
+    {
+    case PROP_OBJECT:
+      g_value_set_object (value, plugin->priv->object);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
 
 static void
 testing_callable_plugin_init (TestingCallablePlugin *plugin)
 {
+  plugin->priv = G_TYPE_INSTANCE_GET_PRIVATE (plugin,
+                                              TESTING_TYPE_CALLABLE_PLUGIN,
+                                              TestingCallablePluginPrivate);
+}
+
+static void
+testing_callable_plugin_activate (PeasActivatable *activatable)
+{
+}
+
+static void
+testing_callable_plugin_deactivate (PeasActivatable *activatable)
+{
 }
 
 static const gchar *
@@ -73,6 +140,21 @@ testing_callable_plugin_call_multi_args (IntrospectionCallable *callable,
 static void
 testing_callable_plugin_class_init (TestingCallablePluginClass *klass)
 {
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = testing_callable_plugin_set_property;
+  object_class->get_property = testing_callable_plugin_get_property;
+
+  g_object_class_override_property (object_class, PROP_OBJECT, "object");
+
+  g_type_class_add_private (klass, sizeof (TestingCallablePluginPrivate));
+}
+
+static void
+introspection_activatable_iface_init (PeasActivatableInterface *iface)
+{
+  iface->activate = testing_callable_plugin_activate;
+  iface->deactivate = testing_callable_plugin_deactivate;
 }
 
 static void
@@ -84,6 +166,11 @@ introspection_callable_iface_init (IntrospectionCallableInterface *iface)
 }
 
 static void
+introspection_has_prerequisite_iface_init (IntrospectionHasPrerequisiteInterface *iface)
+{
+}
+
+static void
 testing_callable_plugin_class_finalize (TestingCallablePluginClass *klass)
 {
 }
diff --git a/tests/libpeas/plugins/extension-c/callable-plugin.h b/tests/libpeas/plugins/extension-c/callable-plugin.h
index 587d394..e48b250 100644
--- a/tests/libpeas/plugins/extension-c/callable-plugin.h
+++ b/tests/libpeas/plugins/extension-c/callable-plugin.h
@@ -35,12 +35,15 @@ G_BEGIN_DECLS
 
 typedef struct _TestingCallablePlugin         TestingCallablePlugin;
 typedef struct _TestingCallablePluginClass    TestingCallablePluginClass;
+typedef struct _TestingCallablePluginPrivate  TestingCallablePluginPrivate;
 
 struct _TestingCallablePlugin {
   /* Inherit from GObject and not PeasExtensionBase
    * to check that it is possible
    */
   GObject parent_instance;
+
+  TestingCallablePluginPrivate *priv;
 };
 
 struct _TestingCallablePluginClass {
diff --git a/tests/libpeas/plugins/extension-c/extension-c-plugin.c b/tests/libpeas/plugins/extension-c/extension-c-plugin.c
index 0f933c8..84f85de 100644
--- a/tests/libpeas/plugins/extension-c/extension-c-plugin.c
+++ b/tests/libpeas/plugins/extension-c/extension-c-plugin.c
@@ -26,6 +26,7 @@
 #include "extension-c-plugin.h"
 
 #include "introspection-callable.h"
+#include "introspection-has-prerequisite.h"
 
 #include "callable-plugin.h"
 
@@ -35,6 +36,12 @@ peas_register_types (PeasObjectModule *module)
   testing_callable_plugin_register (G_TYPE_MODULE (module));
 
   peas_object_module_register_extension_type (module,
+                                              PEAS_TYPE_ACTIVATABLE,
+                                              TESTING_TYPE_CALLABLE_PLUGIN);
+  peas_object_module_register_extension_type (module,
                                               INTROSPECTION_TYPE_CALLABLE,
                                               TESTING_TYPE_CALLABLE_PLUGIN);
+  peas_object_module_register_extension_type (module,
+                                              INTROSPECTION_TYPE_HAS_PREREQUISITE,
+                                              TESTING_TYPE_CALLABLE_PLUGIN);
 }
diff --git a/tests/libpeas/plugins/extension-js/extension-js.js b/tests/libpeas/plugins/extension-js/extension-js.js
index c7dbc7b..e632f67 100644
--- a/tests/libpeas/plugins/extension-js/extension-js.js
+++ b/tests/libpeas/plugins/extension-js/extension-js.js
@@ -2,6 +2,10 @@ function callable_extension() {
 }
 
 callable_extension.prototype = {
+  activate: function() {
+  },
+  deactivate: function() {
+  },
   call_with_return: function() {
     return "Hello, World!"
   },
@@ -13,15 +17,16 @@ callable_extension.prototype = {
   call_multi_args: function(in_, inout) {
     return [ inout, in_ ]
   }
-};
+}
 
 function properties_extension() {
-  this.read_only = "read-only"
-  this.readwrite = "readwrite"
-};
+  this.read_only = "read-only";
+  this.readwrite = "readwrite";
+}
 
 var extensions = {
+  "PeasActivatable": callable_extension,
   "IntrospectionCallable": callable_extension,
-  "IntrospectionProperties" : properties_extension
-};
-
+  "IntrospectionProperties": properties_extension,
+  "IntrospectionHasPrerequisite": callable_extension
+}
diff --git a/tests/libpeas/plugins/extension-python/extension-python.py b/tests/libpeas/plugins/extension-python/extension-python.py
index 1539481..24efddb 100644
--- a/tests/libpeas/plugins/extension-python/extension-python.py
+++ b/tests/libpeas/plugins/extension-python/extension-python.py
@@ -3,7 +3,19 @@
 
 from gi.repository import GObject, Introspection, Peas
 
-class CallablePythonPlugin(GObject.Object, Introspection.Callable):
+class ActivatablePythonPlugin(GObject.Object, Peas.Activatable):
+    object = GObject.property(type=GObject.Object)
+
+    def do_activate(self):
+        pass
+
+    def do_deactivate(self):
+        pass
+
+    def update_state(self):
+        pass
+
+class CallablePythonPlugin(ActivatablePythonPlugin, Introspection.Callable):
     def do_call_with_return(self):
         return "Hello, World!";
 
@@ -25,14 +37,5 @@ class PropertiesPythonPlugin(GObject.Object, Introspection.Properties):
 
     readwrite = GObject.property(type=str, default="readwrite")
 
-class ActivatablePythonExtension(GObject.Object, Peas.Activatable):
-    object = GObject.property(type=GObject.Object)
-
-    def do_activate(self):
-        pass
-
-    def do_deactivate(self):
-        pass
-
-    def update_state(self):
-        pass
+class HasPrerequisitePythonPlugin(CallablePythonPlugin, Introspection.HasPrerequisite):
+    pass
diff --git a/tests/libpeas/testing/testing-extension.c b/tests/libpeas/testing/testing-extension.c
index 8e440ad..65296e4 100644
--- a/tests/libpeas/testing/testing-extension.c
+++ b/tests/libpeas/testing/testing-extension.c
@@ -34,6 +34,7 @@
 #include "testing-extension.h"
 
 #include "introspection-callable.h"
+#include "introspection-has-prerequisite.h"
 #include "introspection-properties.h"
 #include "introspection-unimplemented.h"
 
@@ -188,6 +189,26 @@ testing_extension_create_invalid_ (PeasEngine *engine)
 }
 
 void
+testing_extension_create_with_prerequisite_ (PeasEngine *engine)
+{
+  PeasPluginInfo *info;
+  PeasExtension *extension;
+
+  info = peas_engine_get_plugin_info (engine, extension_plugin);
+
+  g_assert (peas_engine_load_plugin (engine, info));
+
+  extension = peas_engine_create_extension (engine, info,
+                                            INTROSPECTION_TYPE_HAS_PREREQUISITE,
+                                            NULL);
+
+  g_assert (INTROSPECTION_IS_HAS_PREREQUISITE (extension));
+  g_assert (INTROSPECTION_IS_CALLABLE (extension));
+
+  g_object_unref (extension);
+}
+
+void
 testing_extension_reload_ (PeasEngine *engine)
 {
   gint i;
@@ -214,7 +235,8 @@ testing_extension_call_no_args_ (PeasEngine *engine)
   g_assert (peas_engine_load_plugin (engine, info));
 
   extension = peas_engine_create_extension (engine, info,
-                                            INTROSPECTION_TYPE_CALLABLE,
+                                            PEAS_TYPE_ACTIVATABLE,
+                                            "object", NULL,
                                             NULL);
 
   callable = INTROSPECTION_CALLABLE (extension);
@@ -238,7 +260,8 @@ testing_extension_call_with_return_ (PeasEngine *engine)
   g_assert (peas_engine_load_plugin (engine, info));
 
   extension = peas_engine_create_extension (engine, info,
-                                            INTROSPECTION_TYPE_CALLABLE,
+                                            PEAS_TYPE_ACTIVATABLE,
+                                            "object", NULL,
                                             NULL);
 
   callable = INTROSPECTION_CALLABLE (extension);
@@ -267,7 +290,8 @@ testing_extension_call_single_arg_ (PeasEngine *engine)
   g_assert (peas_engine_load_plugin (engine, info));
 
   extension = peas_engine_create_extension (engine, info,
-                                            INTROSPECTION_TYPE_CALLABLE,
+                                            PEAS_TYPE_ACTIVATABLE,
+                                            "object", NULL,
                                             NULL);
 
   callable = INTROSPECTION_CALLABLE (extension);
@@ -297,7 +321,8 @@ testing_extension_call_multi_args_ (PeasEngine *engine)
   g_assert (peas_engine_load_plugin (engine, info));
 
   extension = peas_engine_create_extension (engine, info,
-                                            INTROSPECTION_TYPE_CALLABLE,
+                                            PEAS_TYPE_ACTIVATABLE,
+                                            "object", NULL,
                                             NULL);
 
   callable = INTROSPECTION_CALLABLE (extension);
diff --git a/tests/libpeas/testing/testing-extension.h b/tests/libpeas/testing/testing-extension.h
index dafb73c..11a7980 100644
--- a/tests/libpeas/testing/testing-extension.h
+++ b/tests/libpeas/testing/testing-extension.h
@@ -48,6 +48,7 @@ void testing_extension_provides_valid_            (PeasEngine *engine);
 void testing_extension_provides_invalid_          (PeasEngine *engine);
 void testing_extension_create_valid_              (PeasEngine *engine);
 void testing_extension_create_invalid_            (PeasEngine *engine);
+void testing_extension_create_with_prerequisite_  (PeasEngine *engine);
 void testing_extension_reload_                    (PeasEngine *engine);
 void testing_extension_call_no_args_              (PeasEngine *engine);
 void testing_extension_call_with_return_          (PeasEngine *engine);
@@ -80,6 +81,7 @@ void testing_extension_properties_readwrite_      (PeasEngine *engine);
 \
   _EXTENSION_TEST (loader, "create-valid", create_valid); \
   _EXTENSION_TEST (loader, "create-invalid", create_invalid); \
+  _EXTENSION_TEST (loader, "create-with-prerequisite", create_with_prerequisite); \
 \
   _EXTENSION_TEST (loader, "reload", reload)
 



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