aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--e-util/ChangeLog14
-rw-r--r--e-util/Makefile.am11
-rw-r--r--e-util/e-plugin-mono.c200
-rw-r--r--e-util/e-plugin-mono.h27
-rw-r--r--e-util/e-plugin.c280
-rw-r--r--e-util/e-plugin.h23
6 files changed, 238 insertions, 317 deletions
diff --git a/e-util/ChangeLog b/e-util/ChangeLog
index 610624fb3f..d5fc3efb4a 100644
--- a/e-util/ChangeLog
+++ b/e-util/ChangeLog
@@ -1,3 +1,17 @@
+2005-05-25 Not Zed <NotZed@Ximian.com>
+
+ * e-plugin-mono.[ch]: Removed, these are now implemented as a
+ plugin.
+
+ * e-plugin.c (ep_load_plugin): separate out plugin xml loading
+ code from the loading loop. If a plugin type doesn't exist, then
+ save it in a list for later checking.
+ (ep_load): call above to do the work.
+ (e_plugin_register_type): check the pending doc list, if any
+ plugins now have a type, load them.
+ (e_plugin_type_hook_get_type): a plugin hook for registering new
+ plugin types ('loaders') at runtime.
+
2005-05-19 Not Zed <NotZed@Ximian.com>
* e-import.[ch]: Initial, and un-finished work on importer plugin
diff --git a/e-util/Makefile.am b/e-util/Makefile.am
index 25db475676..e6182ce2b7 100644
--- a/e-util/Makefile.am
+++ b/e-util/Makefile.am
@@ -1,11 +1,6 @@
eutilincludedir = $(privincludedir)/e-util
econdincludedir = $(privincludedir)/e-conduit
-if ENABLE_MONO
-MONOHEADERS = e-plugin-mono.h
-MONOSOURCES = e-plugin-mono.c
-endif
-
INCLUDES = \
-I$(top_srcdir) \
-DEVOLUTION_IMAGES=\""$(imagesdir)"\" \
@@ -54,8 +49,7 @@ eutilinclude_HEADERS = \
e-signature-list.h \
e-time-utils.h \
e-uid.h \
- md5-utils.h \
- $(MONOHEADERS)
+ md5-utils.h
libeutil_la_SOURCES = \
$(MARSHAL_GENERATED) \
@@ -96,8 +90,7 @@ libeutil_la_SOURCES = \
e-uid.c \
eggtrayicon.c \
eggtrayicon.h \
- md5-utils.c \
- $(MONOSOURCES)
+ md5-utils.c
MARSHAL_GENERATED = e-util-marshal.c e-util-marshal.h
@EVO_MARSHAL_RULE@
diff --git a/e-util/e-plugin-mono.c b/e-util/e-plugin-mono.c
deleted file mode 100644
index 2692620133..0000000000
--- a/e-util/e-plugin-mono.c
+++ /dev/null
@@ -1,200 +0,0 @@
-
-#include <sys/types.h>
-#include <dirent.h>
-#include <string.h>
-
-#include "e-plugin-mono.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);
-}
-
-GType
-e_plugin_mono_get_type(void)
-{
- 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 type;
-}
diff --git a/e-util/e-plugin-mono.h b/e-util/e-plugin-mono.h
deleted file mode 100644
index 4c49edf71c..0000000000
--- a/e-util/e-plugin-mono.h
+++ /dev/null
@@ -1,27 +0,0 @@
-
-#ifndef _E_PLUGIN_MONO_H
-#define _E_PLUGIN_MONO_H
-
-#include "e-plugin.h"
-
-/* ********************************************************************** */
-
-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;
-};
-
-GType e_plugin_mono_get_type(void);
-
-#endif /* ! _E_PLUGIN_MONO_H */
diff --git a/e-util/e-plugin.c b/e-util/e-plugin.c
index d7320ab2cf..a60aa7bafd 100644
--- a/e-util/e-plugin.c
+++ b/e-util/e-plugin.c
@@ -54,7 +54,7 @@ static GSList *ep_path;
/* global table of plugins by plugin.id */
static GHashTable *ep_plugins;
/* a table of GSLists of plugins by hook class for hooks not loadable yet */
-static GHashTable *ep_plugins_pending;
+static GHashTable *ep_plugins_pending_hooks;
/* list of all cached xml docs:struct _plugin_doc's */
static EDList ep_plugin_docs = E_DLIST_INITIALISER(ep_plugin_docs);
/* gconf client */
@@ -71,8 +71,11 @@ struct _plugin_doc {
struct _plugin_doc *next;
struct _plugin_doc *prev;
+ char *filename;
xmlDocPtr doc;
- GSList *plugins;
+
+ GSList *plugin_hooks; /* EPlugin objects with pending hooks */
+ GSList *plugins; /* xmlNodePtr's of plugins with unknown type (mono,etc) */
};
static gboolean
@@ -159,14 +162,14 @@ ep_construct(EPlugin *ep, xmlNodePtr root)
GSList *l;
char *oldclass;
- if (ep_plugins_pending == NULL)
- ep_plugins_pending = g_hash_table_new(g_str_hash, g_str_equal);
- if (!g_hash_table_lookup_extended(ep_plugins_pending, class, (void **)&oldclass, (void **)&l)) {
+ if (ep_plugins_pending_hooks == NULL)
+ ep_plugins_pending_hooks = g_hash_table_new(g_str_hash, g_str_equal);
+ if (!g_hash_table_lookup_extended(ep_plugins_pending_hooks, class, (void **)&oldclass, (void **)&l)) {
oldclass = class;
l = NULL;
}
l = g_slist_prepend(l, ep);
- g_hash_table_insert(ep_plugins_pending, oldclass, l);
+ g_hash_table_insert(ep_plugins_pending_hooks, oldclass, l);
ep->hooks_pending = g_slist_prepend(ep->hooks_pending, node);
}
} else if (strcmp(node->name, "description") == 0) {
@@ -281,6 +284,54 @@ e_plugin_get_type(void)
return type;
}
+static EPlugin *
+ep_load_plugin(xmlNodePtr root, struct _plugin_doc *pdoc)
+{
+ char *prop, *id;
+ EPluginClass *klass;
+ EPlugin *ep;
+
+ id = e_plugin_xml_prop(root, "id");
+ if (id == NULL) {
+ g_warning("Invalid e-plugin entry in '%s': no id", pdoc->filename);
+ return NULL;
+ }
+
+ if (g_hash_table_lookup(ep_plugins, id)) {
+ g_warning("Plugin '%s' already defined", id);
+ g_free(id);
+ return NULL;
+ }
+
+ prop = xmlGetProp(root, "type");
+ if (prop == NULL) {
+ g_free(id);
+ g_warning("Invalid e-plugin entry in '%s': no type", pdoc->filename);
+ return NULL;
+ }
+
+ /* If we can't find a plugin, add it to a pending list which is checked when a new type is registered */
+ klass = g_hash_table_lookup(ep_types, prop);
+ if (klass == NULL) {
+ pd(printf("Delaying loading of plugin '%s' unknown type '%s'\n", id, prop));
+ g_free(id);
+ xmlFree(prop);
+ pdoc->plugins = g_slist_prepend(pdoc->plugins, root);
+ return NULL;
+ }
+ xmlFree(prop);
+
+ ep = g_object_new(G_TYPE_FROM_CLASS(klass), NULL);
+ ep->id = id;
+ ep->path = g_strdup(pdoc->filename);
+ ep->enabled = ep_check_enabled(id);
+ if (e_plugin_construct(ep, root) == -1)
+ e_plugin_enable(ep, FALSE);
+ g_hash_table_insert(ep_plugins, ep->id, ep);
+
+ return ep;
+}
+
static int
ep_load(const char *filename)
{
@@ -305,60 +356,28 @@ ep_load(const char *filename)
pdoc = g_malloc0(sizeof(*pdoc));
pdoc->doc = doc;
- pdoc->plugins = NULL;
+ pdoc->filename = g_strdup(filename);
for (root = root->children; root ; root = root->next) {
if (strcmp(root->name, "e-plugin") == 0) {
- char *prop, *id;
- EPluginClass *klass;
-
- id = e_plugin_xml_prop(root, "id");
- if (id == NULL) {
- g_warning("Invalid e-plugin entry in '%s': no id", filename);
- goto fail;
+ ep = ep_load_plugin(root, pdoc);
+ if (ep) {
+ pdoc->plugin_hooks = g_slist_prepend(pdoc->plugin_hooks, ep);
+ cache |= (ep->hooks_pending != NULL);
}
-
- if (g_hash_table_lookup(ep_plugins, id)) {
- g_warning("Plugin '%s' already defined", id);
- g_free(id);
- continue;
- }
-
- prop = xmlGetProp(root, "type");
- if (prop == NULL) {
- g_free(id);
- g_warning("Invalid e-plugin entry in '%s': no type", filename);
- goto fail;
- }
-
- klass = g_hash_table_lookup(ep_types, prop);
- if (klass == NULL) {
- g_warning("Can't find plugin type '%s' for plugin '%s'\n", prop, id);
- g_free(id);
- xmlFree(prop);
- continue;
- }
- xmlFree(prop);
-
- ep = g_object_new(G_TYPE_FROM_CLASS(klass), NULL);
- ep->id = id;
- ep->path = g_strdup(filename);
- ep->enabled = ep_check_enabled(id);
- if (e_plugin_construct(ep, root) == -1)
- e_plugin_enable(ep, FALSE);
- g_hash_table_insert(ep_plugins, ep->id, ep);
- pdoc->plugins = g_slist_prepend(pdoc->plugins, ep);
- cache |= (ep->hooks_pending != NULL);
+ cache |= pdoc->plugins != NULL;
}
}
res = 0;
-fail:
+
if (cache) {
pd(printf("Caching plugin description '%s' for unknown future hooks\n", filename));
e_dlist_addtail(&ep_plugin_docs, (EDListNode *)pdoc);
} else {
+ pd(printf("freeing plugin description '%s', nothing uses it\n", filename));
xmlFreeDoc(pdoc->doc);
+ g_free(pdoc->filename);
g_free(pdoc);
}
@@ -453,7 +472,6 @@ e_plugin_load_plugins(void)
return 0;
}
-
for (l = ep_path;l;l = g_slist_next(l)) {
DIR *dir;
struct dirent *d;
@@ -495,6 +513,7 @@ void
e_plugin_register_type(GType type)
{
EPluginClass *klass;
+ struct _plugin_doc *pdoc, *ndoc;
if (ep_types == NULL) {
ep_types = g_hash_table_new(g_str_hash, g_str_equal);
@@ -509,6 +528,41 @@ e_plugin_register_type(GType type)
pd(printf("register plugin type '%s'\n", klass->type));
g_hash_table_insert(ep_types, (void *)klass->type, klass);
+
+ /* check for pending plugins */
+ pdoc = (struct _plugin_doc *)ep_plugin_docs.head;
+ ndoc = pdoc->next;
+ while (ndoc) {
+ if (pdoc->plugins) {
+ GSList *l, *add = NULL;
+
+ for (l=pdoc->plugins;l;l=g_slist_next(l)) {
+ xmlNodePtr root = l->data;
+ char *type;
+
+ type = xmlGetProp(root, "type");
+ if (!strcmp(type, klass->type))
+ add = g_slist_append(add, l->data);
+ xmlFree(type);
+ }
+
+ for (l=add;l;l=g_slist_next(l)) {
+ xmlNodePtr root = l->data;
+ EPlugin *ep;
+
+ pdoc->plugins = g_slist_remove(pdoc->plugins, root);
+ ep = ep_load_plugin(root, pdoc);
+ if (ep)
+ pdoc->plugin_hooks = g_slist_prepend(pdoc->plugin_hooks, ep);
+ /* TODO: garbage collect plugin doc? */
+ }
+
+ g_slist_free(add);
+ }
+
+ pdoc = ndoc;
+ ndoc = ndoc->next;
+ }
}
static void
@@ -798,8 +852,10 @@ epl_construct(EPlugin *ep, xmlNodePtr root)
epl->location = e_plugin_xml_prop(root, "location");
- if (epl->location == NULL)
+ if (epl->location == NULL) {
+ g_warning("Library plugin '%s' has no location", ep->id);
return -1;
+ }
/* If we're enabled, check for the load-on-startup property */
if (ep->enabled) {
@@ -999,11 +1055,11 @@ e_plugin_hook_register_type(GType type)
/* if we've already loaded a plugin that needed this hook but it didn't exist, re-load it now */
- if (ep_plugins_pending
- && g_hash_table_lookup_extended(ep_plugins_pending, klass->id, (void **)&class, (void **)&plugins)) {
+ if (ep_plugins_pending_hooks
+ && g_hash_table_lookup_extended(ep_plugins_pending_hooks, klass->id, (void **)&class, (void **)&plugins)) {
struct _plugin_doc *pdoc, *ndoc;
- g_hash_table_remove(ep_plugins_pending, class);
+ g_hash_table_remove(ep_plugins_pending_hooks, class);
g_free(class);
for (l = plugins; l; l = g_slist_next(l)) {
EPlugin *ep = l->data;
@@ -1020,15 +1076,16 @@ e_plugin_hook_register_type(GType type)
ndoc = pdoc->next;
while (ndoc) {
if (pdoc->doc) {
- int cache = FALSE;
+ int cache = pdoc->plugins != NULL;
- for (l=pdoc->plugins;l;l=g_slist_next(l))
+ for (l=pdoc->plugin_hooks;!cache && l;l=g_slist_next(l))
cache |= (((EPlugin *)l->data)->hooks_pending != NULL);
if (!cache) {
- pd(printf("Gargabe collecting plugin description\n"));
+ pd(printf("Gargabe collecting plugin description '%s'\n", pdoc->filename));
e_dlist_remove((EDListNode *)pdoc);
xmlFreeDoc(pdoc->doc);
+ g_free(pdoc->filename);
g_free(pdoc);
}
}
@@ -1127,39 +1184,100 @@ e_plugin_hook_id(xmlNodePtr root, const struct _EPluginHookTargetKey *map, const
return ~0;
}
-#if 0
-/*
- e-mail-format-handler
- mime_type
- target
-*/
-struct _EMFormatPlugin {
- EPlugin plugin;
+/* ********************************************************************** */
+/* Plugin plugin */
- char *target;
- char *mime_type;
- struct _EMFormatHandler *(*get_handler)(void);
-};
+static void *epth_parent_class;
+#define epth ((EPluginTypeHook *)eph)
-struct _EMFormatPluginClass {
- EPluginClass plugin_class;
-};
+static int
+epth_load_plugin(void *d)
+{
+ EPluginHook *eph = d;
+ GType type;
-#endif
+ epth->idle = 0;
-#if 0
-void em_setup_plugins(void);
+ type = GPOINTER_TO_UINT(e_plugin_invoke(eph->plugin, epth->get_type, eph->plugin));
+ if (type != 0)
+ e_plugin_register_type(type);
-void
-em_setup_plugins(void)
+ return FALSE;
+}
+
+static int
+epth_construct(EPluginHook *eph, EPlugin *ep, xmlNodePtr root)
{
- GType *e_plugin_mono_get_type(void);
+ xmlNodePtr node;
- e_plugin_register_type(e_plugin_lib_get_type());
- e_plugin_register_type(e_plugin_mono_get_type());
+ phd(printf("loading plugin hook\n"));
- e_plugin_hook_register_type(em_popup_hook_get_type());
+ if (((EPluginHookClass *)epth_parent_class)->construct(eph, ep, root) == -1)
+ return -1;
- e_plugin_load_plugins(".");
+ node = root->children;
+ while (node) {
+ if (strcmp(node->name, "plugin-type") == 0) {
+ epth->get_type = e_plugin_xml_prop(node, "get-type");
+ /* We need to run this in an idle handler,
+ * since at this point the parent EPlugin wont
+ * be fully initialised ... darn */
+ if (epth->get_type)
+ epth->idle = g_idle_add(epth_load_plugin, epth);
+ else
+ g_warning("Plugin type plugin missing get-type callback");
+ }
+ node = node->next;
+ }
+
+ eph->plugin = ep;
+
+ return 0;
+}
+
+static void
+epth_finalise(GObject *o)
+{
+ EPluginHook *eph = (EPluginHook *)o;
+
+ if (epth->idle != 0)
+ g_source_remove(epth->idle);
+
+ g_free(epth->get_type);
+
+ ((GObjectClass *)eph_parent_class)->finalize((GObject *)o);
+}
+
+static void
+epth_class_init(EPluginHookClass *klass)
+{
+ ((GObjectClass *)klass)->finalize = epth_finalise;
+ klass->construct = epth_construct;
+
+ klass->id = "org.gnome.evolution.plugin.type:1.0";
+}
+
+/**
+ * e_plugin_type_hook_get_type:
+ *
+ * Get the type for the plugin plugin hook.
+ *
+ * Return value: The type of the plugin type hook.
+ **/
+GType
+e_plugin_type_hook_get_type(void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof(EPluginTypeHookClass), NULL, NULL, (GClassInitFunc) epth_class_init, NULL, NULL,
+ sizeof(EPluginTypeHook), 0, (GInstanceInitFunc) NULL,
+ };
+
+ epth_parent_class = g_type_class_ref(e_plugin_hook_get_type());
+ type = g_type_register_static(e_plugin_hook_get_type(), "EPluginTypeHook", &info, 0);
+ }
+
+ return type;
}
-#endif
diff --git a/e-util/e-plugin.h b/e-util/e-plugin.h
index efc53d5108..7e4bfbc24b 100644
--- a/e-util/e-plugin.h
+++ b/e-util/e-plugin.h
@@ -247,4 +247,27 @@ void e_plugin_hook_enable(EPluginHook *eph, int state);
guint32 e_plugin_hook_mask(xmlNodePtr root, const struct _EPluginHookTargetKey *map, const char *prop);
guint32 e_plugin_hook_id(xmlNodePtr root, const struct _EPluginHookTargetKey *map, const char *prop);
+/* ********************************************************************** */
+
+/* EPluginTypeHook lets a plugin register a new plugin type.
+ <hook class="org.gnome.evolution.plugin.type:1.0">
+ <plugin-type get-type="e_plugin_mono_get_type/>
+ </hook>
+*/
+typedef struct _EPluginTypeHook EPluginTypeHook;
+typedef struct _EPluginTypeHookClass EPluginTypeHookClass;
+
+struct _EPluginTypeHook {
+ EPluginHook hook;
+
+ char *get_type;
+ guint idle;
+};
+
+struct _EPluginTypeHookClass {
+ EPluginHookClass hook_class;
+};
+
+GType e_plugin_type_hook_get_type(void);
+
#endif /* ! _E_PLUGIN_H */