[libpeas] Make PeasExtension implement extension interfaces.
- From: Steve Frécinaux <sfre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libpeas] Make PeasExtension implement extension interfaces.
- Date: Tue, 31 Aug 2010 22:27:58 +0000 (UTC)
commit 4f24c6c687dd2e132e927d5cd84bdb2b0c111845
Author: Steve Frécinaux <code istique net>
Date: Tue Aug 31 21:07:16 2010 +0200
Make PeasExtension implement extension interfaces.
With this commit, we make it possible to use PeasExtension instances
directly with the extension interface methods.
This makes the overal use of libpeas nicer and more typesafe, make it
feel like we're using the real underlying extension instance, and make
it easier to port old code over without changing all the API calls.
https://bugzilla.gnome.org/show_bug.cgi?id=627338
libpeas/Makefile.am | 42 +++--
libpeas/peas-extension-subclasses.c | 296 ++++++++++++++++++++++++++++++++
libpeas/peas-extension-subclasses.h | 34 ++++
libpeas/peas-introspection.c | 64 +++++++
libpeas/peas-introspection.h | 3 +
loaders/c/peas-extension-c.c | 5 +-
loaders/python/peas-extension-python.c | 5 +-
loaders/seed/peas-extension-seed.c | 6 +-
peas-demo/peas-demo-window.c | 4 +-
9 files changed, 434 insertions(+), 25 deletions(-)
---
diff --git a/libpeas/Makefile.am b/libpeas/Makefile.am
index c0861ab..f7c96db 100644
--- a/libpeas/Makefile.am
+++ b/libpeas/Makefile.am
@@ -26,28 +26,30 @@ INST_H_FILES = \
peas-engine.h \
peas.h
-NOINST_H_FILES = \
- peas-debug.h \
- peas-dirs.h \
- peas-helpers.h \
- peas-i18n.h \
- peas-introspection.h \
- peas-plugin-info-priv.h \
+NOINST_H_FILES = \
+ peas-debug.h \
+ peas-dirs.h \
+ peas-extension-subclasses.h \
+ peas-helpers.h \
+ peas-i18n.h \
+ peas-introspection.h \
+ peas-plugin-info-priv.h \
peas-plugin-loader.h
-C_FILES = \
- peas-debug.c \
- peas-dirs.c \
- peas-helpers.c \
- peas-i18n.c \
- peas-object-module.c \
- peas-introspection.c \
- peas-plugin-info.c \
- peas-plugin-loader.c \
- peas-extension-base.c \
- peas-extension.c \
- peas-extension-set.c \
- peas-activatable.c \
+C_FILES = \
+ peas-debug.c \
+ peas-dirs.c \
+ peas-helpers.c \
+ peas-i18n.c \
+ peas-object-module.c \
+ peas-introspection.c \
+ peas-plugin-info.c \
+ peas-plugin-loader.c \
+ peas-extension-base.c \
+ peas-extension.c \
+ peas-extension-set.c \
+ peas-extension-subclasses.c \
+ peas-activatable.c \
peas-engine.c
BUILT_SOURCES = \
diff --git a/libpeas/peas-extension-subclasses.c b/libpeas/peas-extension-subclasses.c
new file mode 100644
index 0000000..a6cf6eb
--- /dev/null
+++ b/libpeas/peas-extension-subclasses.c
@@ -0,0 +1,296 @@
+/*
+ * peas-extension-subclasses.h
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2010 - Steve Frécinaux
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <girepository.h>
+#include <girffi.h>
+#include "peas-extension.h"
+#include "peas-extension-subclasses.h"
+#include "peas-introspection.h"
+
+typedef struct _MethodImpl {
+ GICallableInfo *info;
+ gchar *method_name;
+ ffi_cif cif;
+ ffi_closure *closure;
+ guint struct_offset;
+} MethodImpl;
+
+static GQuark
+method_impl_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (quark == 0)
+ quark = g_quark_from_static_string ("PeasExtensionInterfaceImplementation");
+
+ return quark;
+}
+
+static void
+handle_method_impl (ffi_cif *cif,
+ gpointer result,
+ gpointer *args,
+ gpointer data)
+{
+ MethodImpl *impl = (MethodImpl *) data;
+ GIArgInfo *arg_info;
+ GITypeInfo *type_info;
+ GITypeInfo *return_type_info;
+ guint n_args, i;
+ PeasExtension *instance;
+ GArgument *arguments;
+ GArgument return_value;
+
+ instance = *((PeasExtension **) args[0]);
+ g_assert (PEAS_IS_EXTENSION (instance));
+
+ n_args = g_callable_info_get_n_args (impl->info);
+ arguments = g_newa (GArgument, n_args);
+
+ for (i = 1; i < n_args; i++)
+ {
+ arg_info = g_callable_info_get_arg (impl->info, i);
+ type_info = g_arg_info_get_type (arg_info);
+
+ peas_gi_pointer_to_argument (type_info, args[i + 1], &arguments[i]);
+
+ g_base_info_unref (type_info);
+ g_base_info_unref (arg_info);
+ }
+
+ peas_extension_callv (instance, impl->method_name, arguments, &return_value);
+
+ for (i = 1; i < n_args; i++)
+ {
+ GIDirection direction;
+
+ arg_info = g_callable_info_get_arg (impl->info, i);
+ direction = g_arg_info_get_direction (arg_info);
+
+ if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT)
+ {
+ type_info = g_arg_info_get_type (arg_info);
+ peas_gi_argument_to_pointer (type_info, &arguments[i], args[i + 1]);
+ g_base_info_unref (type_info);
+ }
+
+ g_base_info_unref (arg_info);
+ }
+
+ return_type_info = g_callable_info_get_return_type (impl->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);
+
+ g_base_info_unref (return_type_info);
+}
+
+static void
+create_native_closure (GIInterfaceInfo *iface_info,
+ GIVFuncInfo *vfunc_info,
+ MethodImpl *impl)
+{
+ GIFunctionInfo *invoker_info;
+ GIStructInfo *struct_info;
+ GIFieldInfo *field_info;
+ GITypeInfo *type_info;
+ GICallbackInfo *callback_info;
+ guint n_fields, i;
+ gboolean found_field_info;
+
+ invoker_info = g_vfunc_info_get_invoker (vfunc_info);
+ if (invoker_info == NULL)
+ {
+ g_debug ("No invoker for VFunc '%s.%s'",
+ g_base_info_get_name (iface_info),
+ g_base_info_get_name (vfunc_info));
+ g_base_info_unref (vfunc_info);
+ return;
+ }
+
+ struct_info = g_interface_info_get_iface_struct (iface_info);
+ n_fields = g_struct_info_get_n_fields (struct_info);
+
+ found_field_info = FALSE;
+ for (i = 0; i < n_fields; i++)
+ {
+ field_info = g_struct_info_get_field (struct_info, i);
+
+ if (strcmp (g_base_info_get_name (field_info),
+ g_base_info_get_name (vfunc_info)) == 0)
+ {
+ found_field_info = TRUE;
+ break;
+ }
+
+ g_base_info_unref (field_info);
+ }
+
+ if (!found_field_info)
+ {
+ g_debug ("No struct field for VFunc '%s.%s'",
+ g_base_info_get_name (iface_info),
+ g_base_info_get_name (vfunc_info));
+ g_base_info_unref (struct_info);
+ g_base_info_unref (invoker_info);
+ return;
+ }
+
+ type_info = g_field_info_get_type (field_info);
+ g_assert (g_type_info_get_tag (type_info) == GI_TYPE_TAG_INTERFACE);
+
+ 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->closure = g_callable_info_prepare_closure (callback_info, &impl->cif,
+ handle_method_impl, impl);
+ impl->struct_offset = g_field_info_get_offset (field_info);
+
+ g_base_info_unref (callback_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
+implement_interface_methods (gpointer iface,
+ GType proxy_type)
+{
+ GType exten_type = G_TYPE_FROM_INTERFACE (iface);
+ GIInterfaceInfo *iface_info;
+ guint n_vfuncs, i;
+ MethodImpl *impls;
+
+ g_debug ("Implementing interface '%s' for proxy type '%s'",
+ g_type_name (exten_type), g_type_name (proxy_type));
+
+ iface_info = g_irepository_find_by_gtype (NULL, exten_type);
+ g_return_if_fail (g_base_info_get_type (iface_info) == GI_INFO_TYPE_INTERFACE);
+
+ n_vfuncs = g_interface_info_get_n_vfuncs (iface_info);
+
+ impls = g_type_get_qdata (exten_type, method_impl_quark ());
+
+ if (impls == NULL)
+ {
+ impls = g_new0 (MethodImpl, n_vfuncs);
+
+ 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]);
+ }
+
+ g_type_set_qdata (exten_type, method_impl_quark (), impls);
+ }
+
+ for (i = 0; i < n_vfuncs; i++)
+ {
+ gpointer *method_ptr;
+
+ if (impls[i].closure == NULL)
+ continue;
+
+ method_ptr = G_STRUCT_MEMBER_P (iface, impls[i].struct_offset);
+ *method_ptr = impls[i].closure;
+
+ g_debug ("Implemented '%s.%s' at %d (%p) with %p",
+ g_type_name (exten_type), impls[i].method_name,
+ impls[i].struct_offset, method_ptr, impls[i].closure);
+ }
+
+ g_base_info_unref (iface_info);
+
+ g_debug ("Implemented interface '%s' for '%s' proxy",
+ g_type_name (exten_type), g_type_name (proxy_type));
+}
+
+static void
+extension_subclass_init (GObjectClass *klass)
+{
+ g_debug ("Initializing class '%s'", G_OBJECT_CLASS_NAME (klass));
+}
+
+static void
+extension_subclass_instance_init (GObject *instance)
+{
+ g_debug ("Initializing new instance of '%s'", G_OBJECT_TYPE_NAME (instance));
+}
+
+GType
+peas_extension_register_subclass (GType parent_type,
+ GType extension_type)
+{
+ gchar *type_name;
+ GType the_type;
+
+ type_name = g_strdup_printf ("%s+%s",
+ g_type_name (parent_type),
+ g_type_name (extension_type));
+
+ the_type = g_type_from_name (type_name);
+
+ if (the_type == G_TYPE_INVALID)
+ {
+ GTypeQuery query;
+ GTypeInfo type_info = {
+ 0,
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) extension_subclass_init,
+ (GClassFinalizeFunc) NULL,
+ NULL,
+ 0,
+ 0,
+ (GInstanceInitFunc) extension_subclass_instance_init
+ };
+ GInterfaceInfo iface_info = {
+ (GInterfaceInitFunc) implement_interface_methods,
+ (GInterfaceFinalizeFunc) NULL,
+ NULL
+ };
+
+ g_debug ("Registering new type '%s'", type_name);
+
+ 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);
+
+ iface_info.interface_data = GSIZE_TO_POINTER (the_type);
+
+ g_type_add_interface_static (the_type, extension_type, &iface_info);
+ }
+
+ g_free (type_name);
+
+ return the_type;
+}
diff --git a/libpeas/peas-extension-subclasses.h b/libpeas/peas-extension-subclasses.h
new file mode 100644
index 0000000..e3fac1e
--- /dev/null
+++ b/libpeas/peas-extension-subclasses.h
@@ -0,0 +1,34 @@
+/*
+ * peas-extension-subclasses.h
+ * This file is part of libpeas
+ *
+ * Copyright (C) 2010 - Steve Frécinaux
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PEAS_EXTENSION_SUBCLASSES_H__
+#define __PEAS_EXTENSION_SUBCLASSES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+GType peas_extension_register_subclass (GType parent_type,
+ GType extension_type);
+
+G_END_DECLS
+
+#endif /* __PEAS_EXTENSION_SUBCLASSES_H__ */
diff --git a/libpeas/peas-introspection.c b/libpeas/peas-introspection.c
index 1ef4689..040d83c 100644
--- a/libpeas/peas-introspection.c
+++ b/libpeas/peas-introspection.c
@@ -233,6 +233,70 @@ peas_gi_argument_to_pointer (GITypeInfo *type_info,
}
}
+void
+peas_gi_pointer_to_argument (GITypeInfo *type_info,
+ gpointer ptr,
+ GArgument *arg)
+{
+ g_return_if_fail (ptr != NULL);
+
+ switch (g_type_info_get_tag (type_info))
+ {
+ case GI_TYPE_TAG_VOID:
+ case GI_TYPE_TAG_BOOLEAN:
+ arg->v_boolean = *((gboolean *) ptr);
+ break;
+ case GI_TYPE_TAG_INT8:
+ arg->v_int8 = *((gint8 *) ptr);
+ break;
+ case GI_TYPE_TAG_UINT8:
+ arg->v_uint8 = *((guint8 *) ptr);
+ break;
+ case GI_TYPE_TAG_INT16:
+ arg->v_int16 = *((gint16 *) ptr);
+ break;
+ case GI_TYPE_TAG_UINT16:
+ arg->v_uint16 = *((guint16 *) ptr);
+ break;
+ case GI_TYPE_TAG_INT32:
+ arg->v_int32 = *((gint32 *) ptr);
+ break;
+ case GI_TYPE_TAG_UINT32:
+ arg->v_uint32 = *((guint32 *) ptr);
+ break;
+ case GI_TYPE_TAG_INT64:
+ arg->v_int64 = *((gint64 *) ptr);
+ break;
+ case GI_TYPE_TAG_UINT64:
+ arg->v_uint64 = *((guint64 *) ptr);
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ arg->v_float = *((gfloat *) ptr);
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ arg->v_double = *((gdouble *) ptr);
+ break;
+ case GI_TYPE_TAG_GTYPE:
+ /* apparently, GType is meant to be a gsize, from gobject/gtype.h in glib */
+ arg->v_size = *((gsize *) ptr);
+ break;
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ arg->v_string = *((gchar **) ptr);
+ break;
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_INTERFACE:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_GHASH:
+ case GI_TYPE_TAG_ERROR:
+ arg->v_pointer = *((gpointer **) ptr);
+ break;
+ default:
+ g_return_if_reached ();
+ }
+}
+
GICallableInfo *
peas_gi_get_method_info (GType iface_type,
const gchar *method_name)
diff --git a/libpeas/peas-introspection.h b/libpeas/peas-introspection.h
index 679f9cf..dc15e45 100644
--- a/libpeas/peas-introspection.h
+++ b/libpeas/peas-introspection.h
@@ -37,6 +37,9 @@ void peas_gi_valist_to_arguments (GICallableInfo *callable_info
void peas_gi_argument_to_pointer (GITypeInfo *type_info,
GArgument *arg,
gpointer ptr);
+void peas_gi_pointer_to_argument (GITypeInfo *type_info,
+ gpointer ptr,
+ GArgument *arg);
gboolean peas_method_apply (GObject *instance,
GType iface_type,
const gchar *method_name,
diff --git a/loaders/c/peas-extension-c.c b/loaders/c/peas-extension-c.c
index 8a9fe5c..136c17f 100644
--- a/loaders/c/peas-extension-c.c
+++ b/loaders/c/peas-extension-c.c
@@ -25,6 +25,7 @@
#include <girepository.h>
#include <libpeas/peas-introspection.h>
+#include <libpeas/peas-extension-subclasses.h>
#include "peas-extension-c.h"
G_DEFINE_TYPE (PeasExtensionC, peas_extension_c, PEAS_TYPE_EXTENSION);
@@ -75,8 +76,10 @@ peas_extension_c_new (GType gtype,
GObject *instance)
{
PeasExtensionC *cexten;
+ GType real_type;
- cexten = PEAS_EXTENSION_C (g_object_new (PEAS_TYPE_EXTENSION_C,
+ real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_C, gtype);
+ cexten = PEAS_EXTENSION_C (g_object_new (real_type,
"extension-type", gtype,
NULL));
cexten->instance = instance;
diff --git a/loaders/python/peas-extension-python.c b/loaders/python/peas-extension-python.c
index d104112..ef147a7 100644
--- a/loaders/python/peas-extension-python.c
+++ b/loaders/python/peas-extension-python.c
@@ -30,6 +30,7 @@
#include <Python.h>
#include <pygobject.h>
#include <libpeas/peas-introspection.h>
+#include <libpeas/peas-extension-subclasses.h>
#include "peas-extension-python.h"
G_DEFINE_TYPE (PeasExtensionPython, peas_extension_python, PEAS_TYPE_EXTENSION);
@@ -84,8 +85,10 @@ peas_extension_python_new (GType gtype,
PyObject *instance)
{
PeasExtensionPython *pyexten;
+ GType real_type;
- pyexten = PEAS_EXTENSION_PYTHON (g_object_new (PEAS_TYPE_EXTENSION_PYTHON,
+ real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_PYTHON, gtype);
+ pyexten = PEAS_EXTENSION_PYTHON (g_object_new (real_type,
"extension-type", gtype,
NULL));
pyexten->instance = instance;
diff --git a/loaders/seed/peas-extension-seed.c b/loaders/seed/peas-extension-seed.c
index 50e3532..ad3d933 100644
--- a/loaders/seed/peas-extension-seed.c
+++ b/loaders/seed/peas-extension-seed.c
@@ -25,6 +25,7 @@
#include "peas-extension-seed.h"
#include <libpeas/peas-introspection.h>
+#include <libpeas/peas-extension-subclasses.h>
#include <girepository.h>
G_DEFINE_TYPE (PeasExtensionSeed, peas_extension_seed, PEAS_TYPE_EXTENSION);
@@ -399,10 +400,13 @@ peas_extension_seed_new (GType exten_type,
SeedContext js_context,
SeedObject js_object)
{
+ GType real_type;
+
g_return_val_if_fail (js_context != NULL, NULL);
g_return_val_if_fail (js_object != NULL, NULL);
- return PEAS_EXTENSION (g_object_new (PEAS_TYPE_EXTENSION_SEED,
+ real_type = peas_extension_register_subclass (PEAS_TYPE_EXTENSION_SEED, exten_type);
+ return PEAS_EXTENSION (g_object_new (real_type,
"extension-type", exten_type,
"js-context", js_context,
"js-object", js_object,
diff --git a/peas-demo/peas-demo-window.c b/peas-demo/peas-demo-window.c
index 9efd57c..35cc2cb 100644
--- a/peas-demo/peas-demo-window.c
+++ b/peas-demo/peas-demo-window.c
@@ -47,7 +47,7 @@ on_extension_added (PeasExtensionSet *set,
PeasExtension *exten,
DemoWindow *dw)
{
- peas_extension_call (exten, "activate", dw);
+ peas_activatable_activate (PEAS_ACTIVATABLE (exten));
}
static void
@@ -56,7 +56,7 @@ on_extension_removed (PeasExtensionSet *set,
PeasExtension *exten,
DemoWindow *dw)
{
- peas_extension_call (exten, "deactivate");
+ peas_activatable_deactivate (PEAS_ACTIVATABLE (exten));
}
static gboolean
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]