[libpeas] Allow multiple interfaces for all extensions
- From: Garrett Regier <gregier src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libpeas] Allow multiple interfaces for all extensions
- Date: Sat, 19 Nov 2011 18:46:00 +0000 (UTC)
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]