Mercurial > pidgin
changeset 11660:a3302d271199
[gaim-migrate @ 13945]
Thanks to the hard work of Eoin 'ecoffey' Coffey, here is the mono plugin loader.
It needs a lot of api wrapping a bit more autotools loving, but with the basic API that is wrapped, it works quite well.
committer: Tailor Script <tailor@pidgin.im>
author | Gary Kramlich <grim@reaperworld.com> |
---|---|
date | Fri, 14 Oct 2005 05:00:17 +0000 |
parents | d9a7befbc3f1 |
children | 8ebc2219fae3 |
files | COPYRIGHT configure.ac plugins/Makefile.am plugins/mono/.cvsignore plugins/mono/BooPlugin.boo plugins/mono/GetBuddyBack.cs plugins/mono/MPlugin.cs plugins/mono/Makefile.am plugins/mono/api/.cvsignore plugins/mono/api/Buddy.cs plugins/mono/api/BuddyList.cs plugins/mono/api/Debug.cs plugins/mono/api/Event.cs plugins/mono/api/GaimPlugin.cs plugins/mono/api/Makefile.am plugins/mono/api/Signal.cs plugins/mono/loader/.cvsignore plugins/mono/loader/Makefile.am plugins/mono/loader/blist-glue.c plugins/mono/loader/debug-glue.c plugins/mono/loader/mono-glue.h plugins/mono/loader/mono-helper.c plugins/mono/loader/mono-helper.h plugins/mono/loader/mono.c plugins/mono/loader/signal-glue.c |
diffstat | 25 files changed, 1004 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/COPYRIGHT Fri Oct 14 03:47:37 2005 +0000 +++ b/COPYRIGHT Fri Oct 14 05:00:17 2005 +0000 @@ -44,6 +44,7 @@ Vincas Ciziunas Jonathan Clark Joe Clarke +Eoin Coffey Jason Cohen Todd Cohen Nathan Conrad
--- a/configure.ac Fri Oct 14 03:47:37 2005 +0000 +++ b/configure.ac Fri Oct 14 05:00:17 2005 +0000 @@ -294,6 +294,7 @@ AM_CONDITIONAL(DYNAMIC_ZEPHYR, test "x$dynamic_zephyr" = "xyes") AC_ARG_ENABLE(audio, [ --disable-audio compile without libao/libaudiofile for sound playing],,enable_audio=yes) +AC_ARG_ENABLE(mono, [ --disable-mono compile without Mono runtime support],,enable_mono=yes) AC_ARG_ENABLE(plugins, [ --disable-plugins compile without plugin support],,enable_plugins=yes) AC_ARG_ENABLE(perl, [ --disable-perl compile without perl scripting],,enable_perl=yes) AC_ARG_ENABLE(tcl, [ --disable-tcl compile without Tcl scripting],,enable_tcl=yes) @@ -571,6 +572,45 @@ GC_TM_GMTOFF +dnl ####################################################################### +dnl # Check for Mono support +dnl ####################################################################### + +if test "$enable_mono" = yes ; then + AC_MSG_CHECKING(for Mono compile flags) + MONO_CFLAGS=`pkg-config --cflags mono 2> /dev/null` + if test $? != 0 ; then + AC_MSG_RESULT([not found, building without mono.]) + MONO_CFLAGS= + MONO_LIBS= + enable_mono = no + else + MONO_LIBS=`pkg-config --libs mono 2> /dev/null` + AC_MSG_RESULT(ok) + + oldLIBS="$LIBS" + LIBS="$LIBS $MONO_LIBS" + AC_MSG_CHECKING(for libmono) + AC_CHECK_FUNCS(mono_jit_init, [], enable_mono=no) + LIBS="$oldLIBS" + + oldCPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $MONO_CFLAGS" + AC_CHECK_HEADERS(mono/jit/jit.h, [], enable_mono=no) + AC_CHECK_HEADERS(mono/metadata/object.h, [], enable_mono=no) + CPPFLAGS="$oldCPPFLAGS" + + AC_DEFINE(ENABLE_MONO, 1, [Define if mono enabled.]) + fi +else + MONO_CFLAGS= + MONO_LIBS= + enable_mono = no +fi + +AC_SUBST(MONO_CFLAGS) +AC_SUBST(MONO_LIBS) +AM_CONDITIONAL(USE_MONO, test "x$enable_mono" = "xyes") dnl ####################################################################### dnl # Check for Perl support @@ -1379,6 +1419,9 @@ plugins/docklet/Makefile plugins/gevolution/Makefile plugins/gestures/Makefile + plugins/mono/Makefile + plugins/mono/api/Makefile + plugins/mono/loader/Makefile plugins/musicmessaging/Makefile plugins/perl/Makefile plugins/perl/common/Makefile.PL @@ -1421,6 +1464,7 @@ echo SSL Library/Libraries......... : $msg_ssl echo echo Build with Plugin support..... : $enable_plugins +echo Build with Mono support....... : $enable_mono echo Build with Perl support....... : $enable_perl echo Build with Tcl support........ : $enable_tcl echo Build with Tk support......... : $enable_tk
--- a/plugins/Makefile.am Fri Oct 14 03:47:37 2005 +0000 +++ b/plugins/Makefile.am Fri Oct 14 05:00:17 2005 +0000 @@ -19,6 +19,10 @@ MUSICMESSAGING_DIR = musicmessaging endif +if USE_MONO +MONO_DIR = mono +endif + SUBDIRS = \ docklet \ $(GEVOLUTION_DIR) \ @@ -27,7 +31,8 @@ ssl \ $(TCL_DIR) \ ticker \ - $(MUSICMESSAGING_DIR) + $(MUSICMESSAGING_DIR) \ + $(MONO_DIR) plugindir = $(libdir)/gaim
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/.cvsignore Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,3 @@ +Makefile +Makefile.in +*.dll
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/BooPlugin.boo Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,22 @@ +import Gaim + +class BooPlugin(GaimPlugin): + + def handle(*args as (object)): + b as Buddy + b = args[0] + Debug.debug(Debug.INFO, "booplugin", "Boo Plugin knows that " + b.Alias + " is away\n") + + override def Load(): + Debug.debug(Debug.INFO, "booplugin", "loading...\n") + BuddyList.OnBuddyAway.connect(self, handle) + + override def Unload(): + Debug.debug(Debug.INFO, "booplugin", "unloading...\n") + + override def Destroy(): + Debug.debug(Debug.INFO, "booplugin", "destroying...\n") + + override def Info(): + return GaimPluginInfo("Boo Plugin", "0.1", "Test Boo Plugin", "Longer Description", "Eoin Coffey", "urled") +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/GetBuddyBack.cs Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,32 @@ +using Gaim; + +public class GetBuddyBack : GaimPlugin +{ + public void HandleSig(object[] args) + { + Buddy buddy = (Buddy)args[0]; + + Debug.debug(Debug.INFO, "buddyback", "buddy " + buddy.Name + " is back!\n"); + } + + public override void Load() + { + Debug.debug(Debug.INFO, "buddyback", "loading...\n"); + + /*Signal.connect(BuddyList.GetHandle(), this, "buddy-back", new Signal.Handler(HandleSig));*/ + BuddyList.OnBuddyBack.connect(this, new Signal.Handler(HandleSig)); + } + + public override void Unload() + { + } + + public override void Destroy() + { + } + + public override GaimPluginInfo Info() + { + return new GaimPluginInfo("C# Get Buddy Back", "0.1", "Prints when a Buddy returns", "Longer Description", "Eoin Coffey", "urled"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/MPlugin.cs Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,34 @@ +using Gaim; + +public class MPlugin : GaimPlugin +{ + public void HandleSig(object[] args) + { + Buddy buddy = (Buddy)args[0]; + + Debug.debug(Debug.INFO, "mplug", "buddy " + buddy.Name + " went away\n"); + } + + public override void Load() + { + Debug.debug(Debug.INFO, "mplug", "loading...\n"); + + /*Signal.connect(BuddyList.GetHandle(), this, "buddy-away", new Signal.Handler(HandleSig));*/ + BuddyList.OnBuddyAway.connect(this, new Signal.Handler(HandleSig)); + } + + public override void Unload() + { + Debug.debug(Debug.INFO, "mplug", "unloading...\n"); + } + + public override void Destroy() + { + Debug.debug(Debug.INFO, "mplug", "destroying...\n"); + } + + public override GaimPluginInfo Info() + { + return new GaimPluginInfo("C# Plugin", "0.1", "Test C# Plugin", "Longer Description", "Eoin Coffey", "urled"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/Makefile.am Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,15 @@ +SUBDIRS = api loader + +TARGETS = MPlugin.dll GetBuddyBack.dll + +all: $(TARGETS) + +install-exec-am: + $(INSTALL) -m 644 $(TARGETS) $(libdir)/gaim + +clean-generic: + rm -rf $(TARGETS) + +SUFFIXES = .cs .dll +.cs.dll: + mcs -t:library -lib:./api -out:$*.dll -r:GaimAPI.dll $*.cs
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/api/.cvsignore Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,3 @@ +GaimAPI.dll +Makefile +Makefile.in
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/api/Buddy.cs Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,11 @@ +namespace Gaim +{ + public class Buddy + { + private string name; + private string alias; + + public string Name { get { return name; } set { name = value; } } + public string Alias { get { return alias; } set { alias = value; } } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/api/BuddyList.cs Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,21 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Gaim +{ + public class BuddyList + { + [MethodImplAttribute(MethodImplOptions.InternalCall)] + extern private static IntPtr _get_handle(); + + private static IntPtr handle = _get_handle(); + + public static Event OnBuddyAway = new Event(handle, "buddy-away"); + public static Event OnBuddyBack = new Event(handle, "buddy-back"); + + public static IntPtr GetHandle() + { + return _get_handle(); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/api/Debug.cs Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,28 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Gaim +{ + public class Debug + { + public static int ALL = 0; + public static int MISC = 1; + public static int INFO = 2; + public static int WARNING = 3; + public static int ERROR = 4; + public static int FATAL = 5; + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + extern private static void _debug(int type, string cat, string str); + + public static void debug(int type, string cat, string format) + { + _debug(type, cat, format); + } + + public static void debug(int type, string cat, string format, params object[] args) + { + _debug(type, cat, String.Format(format, args)); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/api/Event.cs Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,21 @@ +using System; + +namespace Gaim +{ + public class Event + { + private IntPtr handle; + private string signal; + + public Event(IntPtr h, string s) + { + handle = h; + signal = s; + } + + public void connect(object plugin, Signal.Handler handler) + { + Signal.connect(handle, plugin, signal, handler); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/api/GaimPlugin.cs Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,38 @@ +namespace Gaim +{ + public class GaimPluginInfo + { + private string name; + private string version; + private string summary; + private string description; + private string author; + private string homepage; + + public GaimPluginInfo(string name, string version, string summary, string description, string author, string homepage) + { + this.name = name; + this.version = version; + this.summary = summary; + this.description = description; + this.author = author; + this.homepage = homepage; + } + + public string Name { get { return name; } } + public string Version { get { return version; } } + public string Summary { get { return summary; } } + public string Description { get { return description; } } + public string Author { get { return author; } } + public string Homepage { get { return homepage; } } + } + + abstract public class GaimPlugin + { + public abstract void Load(); + public abstract void Unload(); + public abstract void Destroy(); + + public abstract GaimPluginInfo Info(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/api/Makefile.am Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,22 @@ +SOURCES=\ + GaimPlugin.cs \ + Debug.cs \ + BuddyList.cs \ + Buddy.cs \ + Signal.cs \ + Event.cs + +TARGET=GaimAPI.dll + +all: $(TARGET) + +$(TARGET): $(SOURCES) + mcs -t:library -out:$(TARGET) $(SOURCES) + +.PHONY: install clean + +install: + $(INSTALL) -m 644 $(TARGET) $(libdir)/gaim + +clean: + rm -rf $(TARGET)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/api/Signal.cs Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,18 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Gaim +{ + public class Signal + { + [MethodImplAttribute(MethodImplOptions.InternalCall)] + extern private static int _connect(IntPtr handle, object plugin, string signal, object evnt); + + public delegate void Handler(object[] args); + + public static int connect(IntPtr handle, object plugin, string signal, object evnt) + { + return _connect(handle, plugin, signal, evnt); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/.cvsignore Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,7 @@ +.deps +.libs +Makefile +Makefile.in +*.la +*.lo +*.loT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/Makefile.am Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,22 @@ +plugindir = $(libdir)/gaim + +plugin_LTLIBRARIES = mono.la + +mono_la_SOURCES = \ + mono.c \ + mono-helper.c \ + debug-glue.c \ + signal-glue.c \ + blist-glue.c + +mono_la_LDFLAGS = -module -avoid-version + +mono_la_LIBADD = $(MONO_LIBS) + +AM_CPPFLAGS = \ + -DVERSION=\"$(VERSION)\" \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src \ + $(DEBUG_CFLAGS) \ + $(PLUGIN_CFLAGS) \ + $(MONO_CFLAGS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/blist-glue.c Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,35 @@ +#include <string.h> +#include "blist.h" +#include "mono-helper.h" + +MonoObject* gaim_blist_get_handle_glue(void) +{ + void *handle = gaim_blist_get_handle(); + + return mono_value_box(mono_loader_get_domain(), mono_get_intptr_class(), &handle); +} + +MonoObject* gaim_blist_build_buddy_object(void* data) +{ + MonoObject *obj = NULL; + MonoClass *klass = NULL; + + GaimBuddy *buddy = (GaimBuddy*)data; + + klass = mono_class_from_name(mono_loader_get_api_image(), "Gaim", "Buddy"); + if (!klass) { + gaim_debug(GAIM_DEBUG_FATAL, "mono", "couldn't build the class!\n"); + } + + obj = mono_object_new(mono_loader_get_domain(), klass); + if (!obj) { + gaim_debug(GAIM_DEBUG_FATAL, "mono", "couldn't create the object!\n"); + } + + mono_runtime_object_init(obj); + + mono_loader_set_prop_string(obj, "Name", (char*)gaim_buddy_get_name(buddy)); + mono_loader_set_prop_string(obj, "Alias", (char*)gaim_buddy_get_alias(buddy)); + + return obj; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/debug-glue.c Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,16 @@ +#include "mono-glue.h" +#include "debug.h" + +void gaim_debug_glue(int type, MonoString *cat, MonoString *str) +{ + char *ccat; + char *cstr; + + ccat = mono_string_to_utf8(cat); + cstr = mono_string_to_utf8(str); + + gaim_debug(type, ccat, cstr); + + g_free(ccat); + g_free(cstr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/mono-glue.h Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,17 @@ +#ifndef _GAIM_MONO_LOADER_GLUE_H_ +#define _GAIM_MONO_LOADER_GLUE_H_ + +#include <mono/jit/jit.h> +#include <mono/metadata/object.h> +#include <mono/metadata/environment.h> +#include <mono/metadata/assembly.h> + +void gaim_debug_glue(int type, MonoString *cat, MonoString *str); + +int gaim_signal_connect_glue(MonoObject *h, MonoObject *plugin, MonoString *signal, MonoObject *func); + +MonoObject* gaim_blist_get_handle_glue(void); + +MonoObject* gaim_blist_build_buddy_object(void* buddy); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/mono-helper.c Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,166 @@ +/* + * Mono Plugin Loader + * + * -- Thanks to the perl plugin loader for all the great tips ;-) + * + * Eoin Coffey + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <string.h> +#include "mono-helper.h" +#include "mono-glue.h" +#include "value.h" + +MonoClass* mono_loader_find_plugin_class(MonoImage *image) +{ + MonoClass *klass, *pklass = NULL; + int i, total; + + total = mono_image_get_table_rows (image, MONO_TABLE_TYPEDEF); + for (i = 1; i <= total; ++i) { + klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i); + pklass = mono_class_get_parent(klass); + if (pklass) + if (strcmp("GaimPlugin", mono_class_get_name(pklass)) == 0) + return klass; + } + + return NULL; +} + +void mono_loader_set_prop_string(MonoObject *obj, char *field, char *data) +{ + MonoClass *klass; + MonoProperty *prop; + MonoString *str; + gpointer args[1]; + + klass = mono_object_get_class(obj); + + prop = mono_class_get_property_from_name(klass, field); + + str = mono_string_new(mono_loader_get_domain(), data); + + args[0] = str; + + mono_property_set_value(prop, obj, args, NULL); +} + +gchar* mono_loader_get_prop_string(MonoObject *obj, char *field) +{ + MonoClass *klass; + MonoProperty *prop; + MonoString *str; + + klass = mono_object_get_class(obj); + + prop = mono_class_get_property_from_name(klass, field); + + str = (MonoString*)mono_property_get_value(prop, obj, NULL, NULL); + + return mono_string_to_utf8(str); +} + +gboolean mono_loader_is_api_dll(MonoImage *image) +{ + MonoClass *klass; + int i, total; + + total = mono_image_get_table_rows (image, MONO_TABLE_TYPEDEF); + for (i = 1; i <= total; ++i) { + klass = mono_class_get (image, MONO_TOKEN_TYPE_DEF | i); + if (strcmp(mono_class_get_name(klass), "Debug") == 0) + if (strcmp(mono_class_get_namespace(klass), "Gaim") == 0) { + mono_loader_set_api_image(image); + return TRUE; + } + } + + return FALSE; +} + +MonoObject* mono_loader_object_from_gaim_type(GaimType type, gpointer data) +{ + return NULL; +} + +MonoObject* mono_loader_object_from_gaim_subtype(GaimSubType type, gpointer data) +{ + MonoObject *obj; + + switch (type) { + case GAIM_SUBTYPE_BLIST_BUDDY: + obj = gaim_blist_build_buddy_object(data); + break; + default: + break; + } + + return obj; +} + +static MonoDomain *_domain; + +MonoDomain* mono_loader_get_domain(void) +{ + return _domain; +} + +void mono_loader_set_domain(MonoDomain *d) +{ + _domain = d; +} + +static MonoImage *_api_image = NULL; + +void mono_loader_set_api_image(MonoImage *image) +{ + _api_image = image; +} + +MonoImage* mono_loader_get_api_image() +{ + return _api_image; +} + +void mono_loader_init_internal_calls(void) +{ + mono_add_internal_call("Gaim.Debug::_debug", gaim_debug_glue); + mono_add_internal_call("Gaim.Signal::_connect", gaim_signal_connect_glue); + mono_add_internal_call("Gaim.BuddyList::_get_handle", gaim_blist_get_handle_glue); +} + +static GHashTable *plugins_hash = NULL; + +void mono_loader_add_plugin(GaimMonoPlugin *plugin) +{ + if (!plugins_hash) + plugins_hash = g_hash_table_new(NULL, NULL); + + g_hash_table_insert(plugins_hash, plugin->klass, plugin); +} + +gboolean mono_loader_remove_plugin(GaimMonoPlugin *plugin) +{ + return g_hash_table_remove(plugins_hash, plugin->klass); +} + +gpointer mono_loader_find_plugin(GaimMonoPlugin *plugin) +{ + return g_hash_table_lookup(plugins_hash, plugin->klass); +} + +gpointer mono_loader_find_plugin_by_class(MonoClass *klass) +{ + return g_hash_table_lookup(plugins_hash, klass); +} + +GHashTable* mono_loader_get_plugin_hash() +{ + return plugins_hash; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/mono-helper.h Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,59 @@ +#ifndef _GAIM_MONO_LOADER_MONO_HELPER_H_ +#define _GAIM_MONO_LOADER_MONO_HELPER_H_ + +#include <mono/jit/jit.h> +#include <mono/metadata/object.h> +#include <mono/metadata/environment.h> +#include <mono/metadata/assembly.h> +#include <mono/metadata/debug-helpers.h> +#include <mono/metadata/tokentype.h> +#include "plugin.h" +#include "value.h" +#include "debug.h" + +typedef struct { + GaimPlugin *plugin; + MonoAssembly *assm; + MonoClass *klass; + MonoObject *obj; + MonoMethod *init; + MonoMethod *load; + MonoMethod *unload; + MonoMethod *destroy; +} GaimMonoPlugin; + +MonoClass* mono_loader_find_plugin_class(MonoImage *image); + +gchar* mono_loader_get_prop_string(MonoObject *obj, char *field); + +void mono_loader_set_prop_string(MonoObject *obj, char *field, char *data); + +gboolean mono_loader_is_api_dll(MonoImage *image); + +MonoDomain* mono_loader_get_domain(void); + +void mono_loader_set_domain(MonoDomain *d); + +void mono_loader_init_internal_calls(void); + +MonoObject* mono_loader_object_from_gaim_type(GaimType type, gpointer data); + +MonoObject* mono_loader_object_from_gaim_subtype(GaimSubType type, gpointer data); + +void mono_loader_set_api_image(MonoImage *image); + +MonoImage* mono_loader_get_api_image(); + +/* hash table stuff; probably don't need it anymore */ + +void mono_loader_add_plugin(GaimMonoPlugin *plugin); + +gboolean mono_loader_remove_plugin(GaimMonoPlugin *plugin); + +gpointer mono_loader_find_plugin(GaimMonoPlugin *plugin); + +gpointer mono_loader_find_plugin_by_class(MonoClass *klass); + +GHashTable* mono_loader_get_plugin_hash(); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/mono.c Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,241 @@ +/* + * Mono Plugin Loader + * + * -- Thanks to the perl plugin loader for all the great tips ;-) + * + * Eoin Coffey + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "internal.h" +#include "debug.h" +#include "plugin.h" +#include "version.h" +#include "mono-helper.h" + +#define MONO_PLUGIN_ID "core-mono" + +/* This is where our code executes */ +static MonoDomain *domain; + +/* probes the given plugin to determine if its a plugin */ +static gboolean probe_mono_plugin(GaimPlugin *plugin) +{ + MonoAssembly *assm; + MonoMethod *m = NULL; + MonoMethod *info_method = NULL; + MonoObject *plugin_info; + gboolean found_load = FALSE, found_unload = FALSE, found_destroy = FALSE, found_info = FALSE; + gpointer iter = NULL; + + GaimPluginInfo *info; + GaimMonoPlugin *mplug; + + char *file = plugin->path; + + assm = mono_domain_assembly_open(domain, file); + + if (!assm) { + return FALSE; + } + + gaim_debug(GAIM_DEBUG_INFO, "mono", "Probing plugin\n"); + + if (mono_loader_is_api_dll(mono_assembly_get_image(assm))) { + gaim_debug(GAIM_DEBUG_INFO, "mono", "Found our GaimAPI.dll\n"); + return FALSE; + } + + info = g_new0(GaimPluginInfo, 1); + mplug = g_new0(GaimMonoPlugin, 1); + + mplug->assm = assm; + + mplug->klass = mono_loader_find_plugin_class(mono_assembly_get_image(mplug->assm)); + if (!mplug->klass) { + gaim_debug(GAIM_DEBUG_ERROR, "mono", "no plugin class in \'%s\'\n", file); + return FALSE; + } + + mplug->obj = mono_object_new(domain, mplug->klass); + if (!mplug->obj) { + gaim_debug(GAIM_DEBUG_ERROR, "mono", "obj not valid\n"); + return FALSE; + } + + mono_runtime_object_init(mplug->obj); + + while ((m = mono_class_get_methods(mplug->klass, &iter))) { + if (strcmp(mono_method_get_name(m), "Load") == 0) { + mplug->load = m; + found_load = TRUE; + } else if (strcmp(mono_method_get_name(m), "Unload") == 0) { + mplug->unload = m; + found_unload = TRUE; + } else if (strcmp(mono_method_get_name(m), "Destroy") == 0) { + mplug->destroy = m; + found_destroy = TRUE; + } else if (strcmp(mono_method_get_name(m), "Info") == 0) { + info_method = m; + found_info = TRUE; + } + } + + if (!(found_load && found_unload && found_destroy && found_info)) { + gaim_debug(GAIM_DEBUG_ERROR, "mono", "did not find the required methods\n"); + return FALSE; + } + + plugin_info = mono_runtime_invoke(info_method, mplug->obj, NULL, NULL); + + /* now that the methods are filled out we can populate + the info struct with all the needed info */ + + info->name = mono_loader_get_prop_string(plugin_info, "Name"); + info->version = mono_loader_get_prop_string(plugin_info, "Version"); + info->summary = mono_loader_get_prop_string(plugin_info, "Summary"); + info->description = mono_loader_get_prop_string(plugin_info, "Description"); + info->author = mono_loader_get_prop_string(plugin_info, "Author"); + info->homepage = mono_loader_get_prop_string(plugin_info, "Homepage"); + + info->magic = GAIM_PLUGIN_MAGIC; + info->major_version = GAIM_MAJOR_VERSION; + info->minor_version = GAIM_MINOR_VERSION; + info->type = GAIM_PLUGIN_STANDARD; + + /* this plugin depends on us; duh */ + info->dependencies = g_list_append(info->dependencies, MONO_PLUGIN_ID); + mplug->plugin = plugin; + + plugin->info = info; + info->extra_info = mplug; + + mono_loader_add_plugin(mplug); + + return gaim_plugin_register(plugin); +} + +/* Loads a Mono Plugin by calling 'load' in the class */ +static gboolean load_mono_plugin(GaimPlugin *plugin) +{ + GaimMonoPlugin *mplug; + + gaim_debug(GAIM_DEBUG_INFO, "mono", "Loading plugin\n"); + + mplug = (GaimMonoPlugin*)plugin->info->extra_info; + + mono_runtime_invoke(mplug->load, mplug->obj, NULL, NULL); + + return TRUE; +} + +/* Unloads a Mono Plugin by calling 'unload' in the class */ +static gboolean unload_mono_plugin(GaimPlugin *plugin) +{ + GaimMonoPlugin *mplug; + + gaim_debug(GAIM_DEBUG_INFO, "mono", "Unloading plugin\n"); + + mplug = (GaimMonoPlugin*)plugin->info->extra_info; + + gaim_signals_disconnect_by_handle((gpointer)mplug->klass); + + mono_runtime_invoke(mplug->unload, mplug->obj, NULL, NULL); + + return TRUE; +} + +/* Destroys a Mono Plugin by calling 'destroy' in the class, + and cleaning up all the malloced memory */ +static gboolean destroy_mono_plugin(GaimPlugin *plugin) +{ + GaimMonoPlugin *mplug; + + gaim_debug(GAIM_DEBUG_INFO, "mono", "Destroying plugin\n"); + + mplug = (GaimMonoPlugin*)plugin->info->extra_info; + + mono_runtime_invoke(mplug->destroy, mplug->obj, NULL, NULL); + + if (plugin->info) { + if (plugin->info->name) g_free(plugin->info->name); + if (plugin->info->version) g_free(plugin->info->version); + if (plugin->info->summary) g_free(plugin->info->summary); + if (plugin->info->description) g_free(plugin->info->description); + if (plugin->info->author) g_free(plugin->info->author); + if (plugin->info->homepage) g_free(plugin->info->homepage); + } + + if (mplug) { + if (mplug->assm) { + mono_assembly_close(mplug->assm); + } + + g_free(mplug); + mplug = NULL; + } + + return TRUE; +} + +gboolean plugin_destroy(GaimPlugin *plugin) +{ + mono_jit_cleanup(domain); + + return TRUE; +} + +static GaimPluginLoaderInfo loader_info = +{ + NULL, + probe_mono_plugin, + load_mono_plugin, + unload_mono_plugin, + destroy_mono_plugin +}; + +static GaimPluginInfo info = +{ + GAIM_PLUGIN_MAGIC, + GAIM_MAJOR_VERSION, + GAIM_MINOR_VERSION, + GAIM_PLUGIN_LOADER, + NULL, + 0, + NULL, + GAIM_PRIORITY_DEFAULT, + MONO_PLUGIN_ID, + N_("Mono Plugin Loader"), + VERSION, + N_("Loads .NET plugins with Mono."), + N_("Loads .NET plugins with Mono."), + "Eoin Coffey <ecoffey@simla.colostate.edu>", + GAIM_WEBSITE, + NULL, + NULL, + plugin_destroy, + NULL, + &loader_info, + NULL, + NULL +}; + +/* Creates the domain to execute in, and setups our CS Gaim API (note: + in the future the 'mono_add_internal_call' will be spread through out + the source to whatever module is exposing the API; this function will + simply call helper functions to do so) */ +static void init_plugin(GaimPlugin *plugin) +{ + domain = mono_jit_init("gaim"); + + mono_loader_set_domain(domain); + + mono_loader_init_internal_calls(); + + loader_info.exts = g_list_append(loader_info.exts, "dll"); +} + +GAIM_INIT_PLUGIN(mono, init_plugin, info)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/mono/loader/signal-glue.c Fri Oct 14 05:00:17 2005 +0000 @@ -0,0 +1,122 @@ +#include "mono-glue.h" +#include "mono-helper.h" +#include "debug.h" +#include "blist.h" +#include "signals.h" +#include "value.h" + +typedef struct { + MonoObject *func; + char *signal; + GaimValue **values; + GaimValue *ret_value; + int num_vals; +} SignalData; + +static GaimCallback get_callback(SignalData *sig_data); + +static gpointer dispatch_callback(SignalData *sig_data, int num_vals, ...) +{ + MonoArray *array; + MonoObject *obj; + int i; + gpointer meth_args[1]; + gpointer gaim_obj; + + va_list args; + + va_start(args, num_vals); + + array = mono_array_new(mono_loader_get_domain(), mono_get_object_class(), num_vals); + + for (i = 0; i < num_vals; i++) { + if (gaim_value_get_type(sig_data->values[i]) == GAIM_TYPE_SUBTYPE) { + gaim_obj = va_arg(args, gpointer); + obj = mono_loader_object_from_gaim_subtype(gaim_value_get_subtype(sig_data->values[i]), gaim_obj); + mono_array_set(array, MonoObject*, i, obj); + } else { + gaim_obj = va_arg(args, gpointer); + obj = mono_loader_object_from_gaim_type(gaim_value_get_type(sig_data->values[i]), gaim_obj); + mono_array_set(array, MonoObject*, i, obj); + } + } + + va_end(args); + + meth_args[0] = array; + + return mono_runtime_delegate_invoke(sig_data->func, meth_args, NULL); +} + +static void cb_void__pointer(void *arg1, void *data) +{ + dispatch_callback((SignalData*)data, ((SignalData*)data)->num_vals, arg1); + +} + +int gaim_signal_connect_glue(MonoObject* h, MonoObject *plugin, MonoString *signal, MonoObject *func) +{ + char *sig; + void **instance = NULL; + SignalData *sig_data; + + sig = mono_string_to_utf8(signal); + gaim_debug(GAIM_DEBUG_INFO, "mono", "connecting signal: %s\n", sig); + + instance = (void*)mono_object_unbox(h); + + sig_data = g_new0(SignalData, 1); + + sig_data->func = func; + sig_data->signal = sig; + + gaim_signal_get_values(*instance, sig, &sig_data->ret_value, &sig_data->num_vals, &sig_data->values); + + return gaim_signal_connect(*instance, sig, (gpointer)mono_object_get_class(plugin), get_callback(sig_data), (gpointer)sig_data); +} + +static int determine_index(GaimType type) +{ + switch (type) { + case GAIM_TYPE_SUBTYPE: + case GAIM_TYPE_STRING: + case GAIM_TYPE_OBJECT: + case GAIM_TYPE_POINTER: + case GAIM_TYPE_BOXED: + return 1; + break; + default: + return type; + break; + } +} + +static gpointer callbacks[]= { + NULL, + cb_void__pointer, + }; + +static int callbacks_array_size = sizeof(callbacks) / sizeof(GaimCallback); + + +static GaimCallback get_callback(SignalData *sig_data) +{ + int i, index = 0; + + if (sig_data->ret_value == NULL) + index = 0; + else + index = gaim_value_get_type(sig_data->ret_value); + + for (i = 0; i < sig_data->num_vals; i++) { + index += determine_index(gaim_value_get_type(sig_data->values[i])); + } + + if (index >= callbacks_array_size || callbacks[index] == NULL) { + gaim_debug(GAIM_DEBUG_ERROR, "mono", "couldn't find a callback function for signal: %s\n", sig_data->signal); + return NULL; + } + + gaim_debug(GAIM_DEBUG_MISC, "mono", "using callback at index: %d\n", index); + return GAIM_CALLBACK(callbacks[index]); +}