[libpeas/proxys: 2/22] Add PeasExtensionC for extensions written in C.
- From: Steve Frécinaux <sfre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libpeas/proxys: 2/22] Add PeasExtensionC for extensions written in C.
- Date: Fri, 21 May 2010 19:12:37 +0000 (UTC)
commit b4982be3a7559f69be6ed88f6d003a04f8f23ddb
Author: Steve Frécinaux <code istique net>
Date: Fri May 14 13:34:21 2010 +0200
Add PeasExtensionC for extensions written in C.
configure.ac | 2 +
libpeas/Makefile.am | 2 +-
libpeas/peas-object-module.c | 8 +
libpeas/peas-object-module.h | 2 +
loaders/c/Makefile.am | 2 +
loaders/c/peas-extension-c.c | 268 ++++++++++++++++++++++++++++++++++++++
loaders/c/peas-extension-c.h | 58 ++++++++
loaders/c/peas-plugin-loader-c.c | 49 +++++++-
8 files changed, 389 insertions(+), 2 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 08e9d4a..4dfc34a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -53,6 +53,7 @@ LT_INIT([disable-static])
AC_CHECK_FUNCS(fsync)
AC_CHECK_FUNC(sigaction)
+AC_CHECK_SIZEOF(time_t, [], [#include <time.h>])
PKG_PROG_PKG_CONFIG
@@ -97,6 +98,7 @@ PKG_CHECK_MODULES(PEAS, [
glib-2.0 >= 2.18.0
gobject-2.0 >= 2.23.6
gmodule-2.0 >= 2.18.0
+ gobject-introspection-1.0 >= 0.6
])
PKG_CHECK_MODULES(PEASUI, [
diff --git a/libpeas/Makefile.am b/libpeas/Makefile.am
index f62adfc..03b8edf 100644
--- a/libpeas/Makefile.am
+++ b/libpeas/Makefile.am
@@ -54,7 +54,7 @@ if HAVE_INTROSPECTION
introspection_sources = $(libpeas_2_0_la_SOURCES)
Peas-2.0.gir: libpeas-2.0.la
- Peas_2_0_gir_INCLUDES = GObject-2.0 Gtk-2.0
+ Peas_2_0_gir_INCLUDES = GObject-2.0 Gtk-2.0 GModule-2.0
Peas_2_0_gir_CFLAGS = $(PEAS_CFLAGS)
Peas_2_0_gir_LIBS = libpeas-2.0.la
Peas_2_0_gir_FILES = $(addprefix $(srcdir)/,$(introspection_sources))
diff --git a/libpeas/peas-object-module.c b/libpeas/peas-object-module.c
index 70def92..5281e43 100644
--- a/libpeas/peas-object-module.c
+++ b/libpeas/peas-object-module.c
@@ -291,3 +291,11 @@ peas_object_module_get_type_registration (PeasObjectModule *module)
return module->priv->type_registration;
}
+
+GModule *
+peas_object_module_get_library (PeasObjectModule *module)
+{
+ g_return_val_if_fail (PEAS_IS_OBJECT_MODULE (module), NULL);
+
+ return module->priv->library;
+}
diff --git a/libpeas/peas-object-module.h b/libpeas/peas-object-module.h
index e26b175..12f8d65 100644
--- a/libpeas/peas-object-module.h
+++ b/libpeas/peas-object-module.h
@@ -66,6 +66,8 @@ const gchar *peas_object_module_get_path (PeasObjectModule
const gchar *peas_object_module_get_module_name (PeasObjectModule *module);
const gchar *peas_object_module_get_type_registration (PeasObjectModule *module);
+GModule *peas_object_module_get_library (PeasObjectModule *module);
+
G_END_DECLS
#endif /* __PEAS_OBJECT_MODULE_H__ */
diff --git a/loaders/c/Makefile.am b/loaders/c/Makefile.am
index 5aac4e2..c4cf91a 100644
--- a/loaders/c/Makefile.am
+++ b/loaders/c/Makefile.am
@@ -11,6 +11,8 @@ INCLUDES = \
loader_LTLIBRARIES = libcloader.la
libcloader_la_SOURCES = \
+ peas-extension-c.c \
+ peas-extension-c.h \
peas-plugin-loader-c.c \
peas-plugin-loader-c.h
diff --git a/loaders/c/peas-extension-c.c b/loaders/c/peas-extension-c.c
new file mode 100644
index 0000000..26b4661
--- /dev/null
+++ b/loaders/c/peas-extension-c.c
@@ -0,0 +1,268 @@
+/*
+ * peas-extension-c.c
+ * 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.
+ */
+
+#include "config.h"
+#include <girepository.h>
+#include "peas-extension-c.h"
+
+G_DEFINE_DYNAMIC_TYPE (PeasExtensionC, peas_extension_c, PEAS_TYPE_EXTENSION);
+
+void
+peas_extension_c_register (GTypeModule *module)
+{
+ peas_extension_c_register_type (module);
+}
+
+static void
+peas_extension_c_init (PeasExtensionC *cexten)
+{
+}
+
+static void
+read_next_argument (GArgument *cur_arg,
+ va_list args,
+ GITypeInfo *arg_type_info)
+{
+ /* Notes: According to GCC 4.4,
+ * - int8, uint8, int16, uint16, short and ushort are promoted to int when passed through '...'
+ * - float is promoted to double when passed through '...'
+ */
+ switch (g_type_info_get_tag (arg_type_info))
+ {
+ case GI_TYPE_TAG_VOID:
+ case GI_TYPE_TAG_BOOLEAN:
+ cur_arg->v_boolean = va_arg (args, gboolean);
+ break;
+ case GI_TYPE_TAG_INT8:
+ cur_arg->v_int8 = va_arg (args, gint);
+ break;
+ case GI_TYPE_TAG_UINT8:
+ cur_arg->v_uint8 = va_arg (args, gint);
+ break;
+ case GI_TYPE_TAG_INT16:
+ cur_arg->v_int16 = va_arg (args, gint);
+ break;
+ case GI_TYPE_TAG_UINT16:
+ cur_arg->v_uint16 = va_arg (args, gint);
+ break;
+ case GI_TYPE_TAG_INT32:
+ cur_arg->v_int32 = va_arg (args, gint32);
+ break;
+ case GI_TYPE_TAG_UINT32:
+ cur_arg->v_uint32 = va_arg (args, guint32);
+ break;
+ case GI_TYPE_TAG_INT64:
+ cur_arg->v_int64 = va_arg (args, gint64);
+ break;
+ case GI_TYPE_TAG_UINT64:
+ cur_arg->v_uint64 = va_arg (args, guint64);
+ break;
+ case GI_TYPE_TAG_SHORT:
+ cur_arg->v_short = va_arg (args, int);
+ break;
+ case GI_TYPE_TAG_USHORT:
+ cur_arg->v_ushort = va_arg (args, int);
+ break;
+ case GI_TYPE_TAG_INT:
+ cur_arg->v_int = va_arg (args, gint);
+ break;
+ case GI_TYPE_TAG_UINT:
+ cur_arg->v_uint = va_arg (args, guint);
+ break;
+ case GI_TYPE_TAG_LONG:
+ cur_arg->v_long = va_arg (args, glong);
+ break;
+ case GI_TYPE_TAG_ULONG:
+ cur_arg->v_ulong = va_arg (args, gulong);
+ break;
+ case GI_TYPE_TAG_SSIZE:
+ cur_arg->v_ssize = va_arg (args, gssize);
+ break;
+ case GI_TYPE_TAG_SIZE:
+ cur_arg->v_size = va_arg (args, gsize);
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ cur_arg->v_float = va_arg (args, gdouble);
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ cur_arg->v_double = va_arg (args, gdouble);
+ break;
+ case GI_TYPE_TAG_TIME_T:
+ /* borrowed from gfield.c in gobject-introspection */
+#if SIZEOF_TIME_T == 4
+ cur_arg->v_int32 = va_arg (args, time_t);
+#elif SIZEOF_TIME_T == 8
+ cur_Arg.v_int64 = va_args (args, time_t);
+#else
+# error "Unexpected size for time_t: not 4 or 8"
+#endif
+ break;
+ case GI_TYPE_TAG_GTYPE:
+ /* apparently, GType is meant to be a gsize, from gobject/gtype.h in glib */
+ cur_arg->v_size = va_arg (args, GType);
+ break;
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ cur_arg->v_string = va_arg (args, gchar *);
+ 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:
+ cur_arg->v_pointer = va_arg (args, gpointer);
+ break;
+ }
+}
+
+static gboolean
+peas_extension_c_call (PeasExtension *exten,
+ const gchar *method_name,
+ va_list args)
+{
+ PeasExtensionC *cexten = PEAS_EXTENSION_C (exten);
+ GIRepository *repo;
+ GIBaseInfo *type_info;
+ GIFunctionInfo *func_info;
+ guint n_args, n_in_args, n_out_args;
+ GArgument *in_args, *out_args;
+ GArgument retval;
+ guint i;
+ gboolean ret;
+ GError *error = NULL;
+
+ repo = g_irepository_get_default ();
+ type_info = g_irepository_find_by_gtype (repo, cexten->gtype);
+ if (type_info == NULL)
+ return FALSE;
+
+ switch (g_base_info_get_type (type_info))
+ {
+ case GI_INFO_TYPE_OBJECT:
+ func_info = g_object_info_find_method ((GIObjectInfo *) type_info,
+ method_name);
+ break;
+ case GI_INFO_TYPE_INTERFACE:
+ func_info = g_interface_info_find_method ((GIInterfaceInfo *) type_info,
+ method_name);
+ break;
+ default:
+ func_info = NULL;
+ }
+ if (func_info == NULL)
+ {
+ g_base_info_unref (type_info);
+ return FALSE;
+ }
+
+ n_args = g_callable_info_get_n_args ((GICallableInfo *) func_info);
+ n_in_args = 0;
+ n_out_args = 0;
+
+ in_args = g_new0 (GArgument, n_args + 1);
+ out_args = g_new0 (GArgument, n_args);
+
+ /* Set the object as the first argument for the method. */
+ in_args[n_in_args++].v_pointer = cexten->instance;
+
+ for (i = 0; i < n_args; i++)
+ {
+ GIArgInfo *arg_info;
+ GITypeInfo *arg_type_info;
+
+ arg_info = g_callable_info_get_arg ((GICallableInfo *) func_info, i);
+ arg_type_info = g_arg_info_get_type (arg_info);
+
+ switch (g_arg_info_get_direction (arg_info))
+ {
+ case GI_DIRECTION_IN:
+ read_next_argument (&in_args[n_in_args++], args, arg_type_info);
+ break;
+ /* In the other cases, we expect we will always have a pointer. */
+ case GI_DIRECTION_INOUT:
+ in_args[n_in_args++].v_pointer = out_args[n_out_args++].v_pointer = va_arg (args, gpointer);
+ break;
+ case GI_DIRECTION_OUT:
+ out_args[n_out_args++].v_pointer = va_arg (args, gpointer);
+ break;
+ }
+
+ g_base_info_unref ((GIBaseInfo *) arg_type_info);
+ g_base_info_unref ((GIBaseInfo *) arg_info);
+ }
+
+ ret = g_function_info_invoke (func_info, in_args, n_in_args, out_args, n_out_args, &retval, &error);
+ if (!ret)
+ {
+ g_debug ("Error while calling %s.%s: %s", g_type_name (cexten->gtype), method_name, error->message);
+ g_error_free (error);
+ }
+
+ /* FIXME: what are we supposed to do with out args now? */
+
+ g_free (in_args);
+ g_free (out_args);
+ g_base_info_unref ((GIBaseInfo *) func_info);
+ g_base_info_unref (type_info);
+
+ return ret;
+}
+
+static void
+peas_extension_c_finalize (GObject *object)
+{
+ PeasExtensionC *cexten = PEAS_EXTENSION_C (object);
+
+ if (cexten->instance)
+ g_object_unref (cexten->instance);
+
+ G_OBJECT_CLASS (peas_extension_c_parent_class)->finalize (object);
+}
+
+static void
+peas_extension_c_class_init (PeasExtensionCClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ PeasExtensionClass *extension_class = PEAS_EXTENSION_CLASS (klass);
+
+ object_class->finalize = peas_extension_c_finalize;
+
+ extension_class->call = peas_extension_c_call;
+}
+
+static void
+peas_extension_c_class_finalize (PeasExtensionCClass *klass)
+{
+}
+
+PeasExtension *
+peas_extension_c_new (GType gtype,
+ GObject *instance)
+{
+ PeasExtensionC *cexten;
+
+ cexten = PEAS_EXTENSION_C (g_object_new (PEAS_TYPE_EXTENSION_C, NULL));
+ cexten->gtype = gtype;
+ cexten->instance = instance;
+
+ return PEAS_EXTENSION (cexten);
+}
diff --git a/loaders/c/peas-extension-c.h b/loaders/c/peas-extension-c.h
new file mode 100644
index 0000000..f11081e
--- /dev/null
+++ b/loaders/c/peas-extension-c.h
@@ -0,0 +1,58 @@
+/*
+ * peas-extension-c.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_C_H__
+#define __PEAS_EXTENSION_C_H__
+
+#include <libpeas/peas-extension.h>
+
+G_BEGIN_DECLS
+
+#define PEAS_TYPE_EXTENSION_C (peas_extension_c_get_type ())
+#define PEAS_EXTENSION_C(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PEAS_TYPE_EXTENSION_C, PeasExtensionC))
+#define PEAS_EXTENSION_C_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PEAS_TYPE_EXTENSION_C, PeasExtensionCClass))
+#define PEAS_IS_EXTENSION_C(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PEAS_TYPE_EXTENSION_C))
+#define PEAS_IS_EXTENSION_C_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PEAS_TYPE_EXTENSION_C))
+#define PEAS_EXTENSION_C_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PEAS_TYPE_EXTENSION_C, PeasExtensionCClass))
+
+typedef struct _PeasExtensionC PeasExtensionC;
+typedef struct _PeasExtensionCClass PeasExtensionCClass;
+
+struct _PeasExtensionC {
+ PeasExtension parent;
+
+ GType gtype;
+ GObject *instance;
+};
+
+struct _PeasExtensionCClass {
+ PeasExtensionClass parent_class;
+};
+
+GType peas_extension_c_get_type (void) G_GNUC_CONST;
+void peas_extension_c_register (GTypeModule *module);
+
+PeasExtension *peas_extension_c_new (GType gtype,
+ GObject *instance);
+
+G_END_DECLS
+
+#endif /* __PEAS_PLUGIN_LOADER_C_H__ */
diff --git a/loaders/c/peas-plugin-loader-c.c b/loaders/c/peas-plugin-loader-c.c
index ab123d2..5272b08 100644
--- a/loaders/c/peas-plugin-loader-c.c
+++ b/loaders/c/peas-plugin-loader-c.c
@@ -20,15 +20,27 @@
*/
#include "peas-plugin-loader-c.h"
+#include "peas-extension-c.h"
#include <libpeas/peas-object-module.h>
+#include <gmodule.h>
+typedef gpointer (* CreateFunc) (void);
struct _PeasPluginLoaderCPrivate
{
GHashTable *loaded_plugins;
};
-PEAS_PLUGIN_LOADER_REGISTER_TYPE (PeasPluginLoaderC, peas_plugin_loader_c);
+/*PEAS_PLUGIN_LOADER_REGISTER_TYPE (PeasPluginLoaderC, peas_plugin_loader_c);*/
+G_DEFINE_DYNAMIC_TYPE (PeasPluginLoaderC, peas_plugin_loader_c, PEAS_TYPE_PLUGIN_LOADER);
+
+G_MODULE_EXPORT GObject *
+register_peas_plugin_loader (GTypeModule *type_module)
+{
+ peas_plugin_loader_c_register_type (type_module);
+ peas_extension_c_register (type_module);
+ return g_object_new (PEAS_TYPE_PLUGIN_LOADER_C, NULL);
+}
static void
peas_plugin_loader_c_add_module_directory (PeasPluginLoader *loader,
@@ -90,6 +102,40 @@ peas_plugin_loader_c_load (PeasPluginLoader * loader,
return result;
}
+static PeasExtension *
+peas_plugin_loader_c_get_extension (PeasPluginLoader *loader,
+ PeasPluginInfo *info,
+ GType exten_type)
+{
+ PeasPluginLoaderC *cloader;
+ PeasObjectModule *module;
+ gchar *symbol_name;
+ gpointer symbol;
+ gboolean ret;
+ gpointer instance;
+
+ cloader = PEAS_PLUGIN_LOADER_C (loader);
+
+ module = (PeasObjectModule *) g_hash_table_lookup (cloader->priv->loaded_plugins,
+ info);
+ g_return_val_if_fail (module != NULL, NULL);
+
+ symbol_name = g_strdup_printf ("create_%s", g_type_name (exten_type));
+ ret = g_module_symbol (peas_object_module_get_library (module), symbol_name, &symbol);
+ g_free (symbol_name);
+
+ if (!ret || !symbol)
+ return NULL;
+
+ instance = ((CreateFunc) symbol) ();
+
+ g_return_val_if_fail (instance != NULL, NULL);
+ g_return_val_if_fail (G_IS_OBJECT (instance), NULL);
+ g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (instance, exten_type), NULL);
+
+ return peas_extension_c_new (exten_type, G_OBJECT (instance));
+}
+
static void
peas_plugin_loader_c_unload (PeasPluginLoader *loader,
PeasPluginInfo *info)
@@ -152,6 +198,7 @@ peas_plugin_loader_c_class_init (PeasPluginLoaderCClass *klass)
loader_class->add_module_directory = peas_plugin_loader_c_add_module_directory;
loader_class->load = peas_plugin_loader_c_load;
loader_class->unload = peas_plugin_loader_c_unload;
+ loader_class->get_extension = peas_plugin_loader_c_get_extension;
g_type_class_add_private (object_class, sizeof (PeasPluginLoaderCPrivate));
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]