aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/mono/ChangeLog4
-rw-r--r--plugins/mono/Makefile.am16
-rw-r--r--plugins/mono/mono-plugin.c200
-rw-r--r--plugins/mono/mono-plugin.h28
-rw-r--r--plugins/mono/org-gnome-evolution-mono.eplug.xml16
5 files changed, 264 insertions, 0 deletions
diff --git a/plugins/mono/ChangeLog b/plugins/mono/ChangeLog
index 4a630d355d..11f7ce36ff 100644
--- a/plugins/mono/ChangeLog
+++ b/plugins/mono/ChangeLog
@@ -1,3 +1,7 @@
+2005-05-25 Not Zed <NotZed@Ximian.com>
+
+ * mono-plugin.c: implement the mono loader as a plugin itself.
+
2005-05-17 Not Zed <NotZed@Ximian.com>
* Evolution.cs: added initial e_error wrapper.
diff --git a/plugins/mono/Makefile.am b/plugins/mono/Makefile.am
new file mode 100644
index 0000000000..6cb849c126
--- /dev/null
+++ b/plugins/mono/Makefile.am
@@ -0,0 +1,16 @@
+INCLUDES = \
+ -I$(top_srcdir) \
+ $(E_UTIL_CFLAGS)
+
+@EVO_PLUGIN_RULE@
+
+plugin_DATA = org-gnome-evolution-mono.eplug
+plugin_LTLIBRARIES = liborg-gnome-evolution-mono.la
+
+liborg_gnome_evolution_mono_la_SOURCES = mono-plugin.c
+liborg_gnome_evolution_mono_la_LDFLAGS = -module -avoid-version
+
+EXTRA_DIST = org-gnome-evolution-mono.eplug.xml
+
+BUILT_SOURCES = $(plugin_DATA)
+CLEANFILES = $(BUILT_SOURCES)
diff --git a/plugins/mono/mono-plugin.c b/plugins/mono/mono-plugin.c
new file mode 100644
index 0000000000..d09b8326b0
--- /dev/null
+++ b/plugins/mono/mono-plugin.c
@@ -0,0 +1,200 @@
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+
+#include "mono-plugin.h"
+
+#include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/object.h>
+#include <mono/metadata/appdomain.h>
+#include <mono/metadata/assembly.h>
+#include <mono/jit/jit.h>
+
+#define d(x)
+
+static MonoDomain *domain;
+
+/* ********************************************************************** */
+static void *epm_parent_class;
+
+typedef struct _EPluginMonoPrivate {
+ MonoAssembly *assembly;
+ MonoClass *klass;
+ MonoObject *plugin;
+ GHashTable *methods;
+} EPluginMonoPrivate;
+
+#define epm ((EPluginMono *)ep)
+
+static char *
+get_xml_prop(xmlNodePtr node, const char *id)
+{
+ char *p = xmlGetProp(node, id);
+ char *out = NULL;
+
+ if (p) {
+ out = g_strdup(p);
+ xmlFree(p);
+ }
+
+ return out;
+}
+
+/*
+ Two approaches:
+ You can have a Evolution.Plugin implementation which has every callback as methods on it.
+ Or you can just use static methods for everything.
+
+ All methods take a single (structured) argument.
+*/
+
+static void *
+epm_invoke(EPlugin *ep, const char *name, void *data)
+{
+ EPluginMonoPrivate *p = epm->priv;
+ MonoMethodDesc *d;
+ MonoMethod *m;
+ MonoObject *x = NULL, *res;
+ void **params;
+
+ /* we need to do this every time since we may be called from any thread for some uses */
+ mono_thread_attach(domain);
+
+ if (p->assembly == NULL) {
+ p->assembly = mono_domain_assembly_open(domain, epm->location);
+ if (p->assembly == NULL) {
+ g_warning("can't load assembly '%s'", epm->location);
+ return NULL;
+ }
+
+ if (epm->handler == NULL
+ || (p->klass = mono_class_from_name(mono_assembly_get_image(p->assembly), "", epm->handler)) == NULL) {
+ d(printf("Using static callbacks only"));
+ } else {
+ p->plugin = mono_object_new(domain, p->klass);
+ /* could conceivably init with some context too */
+ mono_runtime_object_init(p->plugin);
+ }
+ }
+
+ m = g_hash_table_lookup(p->methods, name);
+ if (m == NULL) {
+ if (p->klass) {
+ d(printf("looking up method '%s' in class\n", name));
+ /* class method */
+ d = mono_method_desc_new(name, FALSE);
+ if (d == NULL) {
+ g_warning("Can't create method descriptor for '%s'", name);
+ return NULL;
+ }
+
+ m = mono_method_desc_search_in_class(d, p->klass);
+ if (m == NULL) {
+ g_warning("Can't find method callback '%s'", name);
+ return NULL;
+ }
+ } else {
+ d(printf("looking up static method '%s'\n", name));
+ /* static method */
+ d = mono_method_desc_new(name, FALSE);
+ if (d == NULL) {
+ g_warning("Can't create method descriptor for '%s'", name);
+ return NULL;
+ }
+
+ m = mono_method_desc_search_in_image(d, mono_assembly_get_image(p->assembly));
+ if (m == NULL) {
+ g_warning("Can't find method callback '%s'", name);
+ return NULL;
+ }
+ }
+
+ g_hash_table_insert(p->methods, g_strdup(name), m);
+ }
+
+ params = g_malloc0(sizeof(*params)*1);
+ params[0] = &data;
+ res = mono_runtime_invoke(m, p->plugin, params, &x);
+ /* do i need to free params?? */
+
+ if (x)
+ mono_print_unhandled_exception(x);
+
+ if (res) {
+ void **p = mono_object_unbox(res);
+ d(printf("mono method returned '%p' %ld\n", *p, (long int)*p));
+ return *p;
+ } else
+ return NULL;
+}
+
+static int
+epm_construct(EPlugin *ep, xmlNodePtr root)
+{
+ if (((EPluginClass *)epm_parent_class)->construct(ep, root) == -1)
+ return -1;
+
+ epm->location = get_xml_prop(root, "location");
+ epm->handler = get_xml_prop(root, "handler");
+
+ if (epm->location == NULL)
+ return -1;
+
+ return 0;
+}
+
+static void
+epm_finalise(GObject *o)
+{
+ EPlugin *ep = (EPlugin *)o;
+ EPluginMonoPrivate *p = epm->priv;
+
+ g_free(epm->location);
+ g_free(epm->handler);
+
+ g_hash_table_foreach(p->methods, (GHFunc)g_free, NULL);
+ g_hash_table_destroy(p->methods);
+
+ g_free(epm->priv);
+
+ ((GObjectClass *)epm_parent_class)->finalize(o);
+}
+
+static void
+epm_class_init(EPluginClass *klass)
+{
+ ((GObjectClass *)klass)->finalize = epm_finalise;
+ klass->construct = epm_construct;
+ klass->invoke = epm_invoke;
+ klass->type = "mono";
+}
+
+static void
+epm_init(GObject *o)
+{
+ EPlugin *ep = (EPlugin *)o;
+
+ epm->priv = g_malloc0(sizeof(*epm->priv));
+ epm->priv->methods = g_hash_table_new(g_str_hash, g_str_equal);
+}
+
+void *
+org_gnome_evolution_mono_get_type(void *a, void *b)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof(EPluginMonoClass), NULL, NULL, (GClassInitFunc) epm_class_init, NULL, NULL,
+ sizeof(EPluginMono), 0, (GInstanceInitFunc) epm_init,
+ };
+
+ epm_parent_class = g_type_class_ref(e_plugin_get_type());
+ type = g_type_register_static(e_plugin_get_type(), "EPluginMono", &info, 0);
+ domain = mono_jit_init("Evolution");
+ mono_thread_attach(domain);
+ }
+
+ return GUINT_TO_POINTER(type);
+}
diff --git a/plugins/mono/mono-plugin.h b/plugins/mono/mono-plugin.h
new file mode 100644
index 0000000000..76e459f743
--- /dev/null
+++ b/plugins/mono/mono-plugin.h
@@ -0,0 +1,28 @@
+
+#ifndef _ORG_GNOME_EVOLUTION_MONO_H
+#define _ORG_GNOME_EVOLUTION_MONO_H
+
+#include "e-util/e-plugin.h"
+
+/* ********************************************************************** */
+/* This is ALL private */
+
+typedef struct _EPluginMono EPluginMono;
+typedef struct _EPluginMonoClass EPluginMonoClass;
+
+struct _EPluginMono {
+ EPlugin plugin;
+
+ struct _EPluginMonoPrivate *priv;
+
+ char *location; /* location */
+ char *handler; /* handler class */
+};
+
+struct _EPluginMonoClass {
+ EPluginClass plugin_class;
+};
+
+void *org_gnome_evolution_mono_get_type(void *a, void *b);
+
+#endif /* ! _ORG_GNOME_EVOLUTION_MONO_H */
diff --git a/plugins/mono/org-gnome-evolution-mono.eplug.xml b/plugins/mono/org-gnome-evolution-mono.eplug.xml
new file mode 100644
index 0000000000..cdd12fc307
--- /dev/null
+++ b/plugins/mono/org-gnome-evolution-mono.eplug.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<e-plugin-list>
+ <e-plugin
+ type="shlib"
+ id="org.gnome.evolution.plugin.mono"
+ location="@PLUGINDIR@/liborg-gnome-evolution-mono.so"
+ _name="Mono Loader">
+ <_description>A plugin which implements mono plugins.</_description>
+ <author name="Michael Zucchi" email="notzed@ximian.com"/>
+
+ <hook class="org.gnome.evolution.plugin.type:1.0">
+ <plugin-type get-type="org_gnome_evolution_mono_get_type"/>
+ </hook>
+
+ </e-plugin>
+</e-plugin-list>