diff options
-rw-r--r-- | e-util/ChangeLog | 14 | ||||
-rw-r--r-- | e-util/Makefile.am | 11 | ||||
-rw-r--r-- | e-util/e-plugin-mono.c | 200 | ||||
-rw-r--r-- | e-util/e-plugin-mono.h | 27 | ||||
-rw-r--r-- | e-util/e-plugin.c | 280 | ||||
-rw-r--r-- | e-util/e-plugin.h | 23 |
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 */ |