[libpeas/proxys: 2/22] Add PeasExtensionC for extensions written in C.



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]