aboutsummaryrefslogtreecommitdiffstats
path: root/modules/plugin-python
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2009-08-29 08:21:54 +0800
committerMatthew Barnes <mbarnes@redhat.com>2009-08-30 05:23:20 +0800
commit32f545cdf031ebe3718791f18e8fb6b6141fd081 (patch)
tree980723161c32da855ca91b135318d7fa67dc18c7 /modules/plugin-python
parente8382099228d46ebef684c5384bab6ec710283ce (diff)
downloadgsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.tar
gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.tar.gz
gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.tar.bz2
gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.tar.lz
gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.tar.xz
gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.tar.zst
gsoc2013-evolution-32f545cdf031ebe3718791f18e8fb6b6141fd081.zip
Simplify EPlugin loading at startup.
- Require all EPlugin and EPluginHook subtypes be registered before loading plugins. This drastically simplifies the EPlugin/EPluginHook negotiation. - Turn most EPluginHook subtypes into GTypeModules and register their types from an e_module_load() function (does not include shell hooks). - Convert EPluginLib and the Mono and Python bindings to GTypeModules and register their types from an e_module_load() function, and kill EPluginTypeHook.
Diffstat (limited to 'modules/plugin-python')
-rw-r--r--modules/plugin-python/Makefile.am31
-rw-r--r--modules/plugin-python/e-plugin-python.c230
-rw-r--r--modules/plugin-python/e-plugin-python.h70
-rw-r--r--modules/plugin-python/evolution-module-plugin-python.c41
-rw-r--r--modules/plugin-python/example/Makefile.am29
-rw-r--r--modules/plugin-python/example/hello_python.py5
-rw-r--r--modules/plugin-python/example/org-gnome-hello-python-ui.xml16
-rw-r--r--modules/plugin-python/example/org-gnome-hello-python.eplug.xml20
8 files changed, 442 insertions, 0 deletions
diff --git a/modules/plugin-python/Makefile.am b/modules/plugin-python/Makefile.am
new file mode 100644
index 0000000000..e6a32c3c83
--- /dev/null
+++ b/modules/plugin-python/Makefile.am
@@ -0,0 +1,31 @@
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"evolution-plugin-python\" \
+ -I$(top_srcdir) \
+ $(E_UTIL_CFLAGS) \
+ $(PY_INCLUDES)
+
+module_LTLIBRARIES = libevolution-module-plugin-python.la
+
+libevolution_module_plugin_python_la_SOURCES = \
+ evolution-module-plugin-python.c \
+ e-plugin-python.c \
+ e-plugin-python.h
+
+libevolution_module_plugin_python_la_LIBADD = \
+ -lpthread -ldl -lutil -lm \
+ $(top_builddir)/e-util/libeutil.la \
+ $(E_UTIL_LIBS) \
+ $(PY_LIBS)
+
+libevolution_module_plugin_python_la_LDFLAGS = \
+ -module -avoid-version $(NO_UNDEFINED)
+
+example_sources = \
+ example/hello_python.py \
+ example/org-gnome-hello-python-ui.xml \
+ example/org-gnome-hello-python.eplug.xml \
+ example/Makefile.am
+
+EXTRA_DIST = $(example_sources)
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/plugin-python/e-plugin-python.c b/modules/plugin-python/e-plugin-python.c
new file mode 100644
index 0000000000..747ba57bac
--- /dev/null
+++ b/modules/plugin-python/e-plugin-python.c
@@ -0,0 +1,230 @@
+/*
+ * e-plugin-python.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+/* Include <Python.h> first to avoid:
+ * warning: "_POSIX_C_SOURCE" redefined */
+#include <Python.h>
+
+#include "e-plugin-python.h"
+
+#include <sys/types.h>
+#include <string.h>
+
+#define E_PLUGIN_PYTHON_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE \
+ ((obj), E_TYPE_PLUGIN_PYTHON, EPluginPythonPrivate))
+
+struct _EPluginPythonPrivate {
+ PyObject *pModule;
+ PyObject *pClass;
+ PyObject *pFunc;
+ PyObject *pDict;
+ GHashTable *methods;
+};
+
+static gpointer parent_class;
+static GType plugin_python_type;
+
+static gchar *
+get_xml_prop (xmlNodePtr node, const gchar *id)
+{
+ xmlChar *prop;
+ gchar *out = NULL;
+
+ prop = xmlGetProp (node, (xmlChar *) id);
+
+ if (prop != NULL) {
+ out = g_strdup ((gchar *) prop);
+ xmlFree (prop);
+ }
+
+ return out;
+}
+
+static void
+plugin_python_finalize (GObject *object)
+{
+ EPluginPython *plugin_python;
+
+ plugin_python = E_PLUGIN_PYTHON (object);
+
+ g_free (plugin_python->location);
+ g_free (plugin_python->module_name);
+ g_free (plugin_python->pClass);
+
+ g_hash_table_destroy (plugin_python->priv->methods);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gint
+plugin_python_construct (EPlugin *plugin, xmlNodePtr root)
+{
+ EPluginPython *plugin_python;
+
+ /* Chain up to parent's construct() method. */
+ if (E_PLUGIN_CLASS (parent_class)->construct (plugin, root) == -1)
+ return -1;
+
+ plugin_python = E_PLUGIN_PYTHON (plugin);
+ plugin_python->location = get_xml_prop (root, "location");
+ plugin_python->module_name = get_xml_prop (root, "module_name");
+ plugin_python->pClass = get_xml_prop (root, "pClass");
+
+ return (plugin_python->location != NULL) ? 0 : -1;
+}
+
+static gpointer
+plugin_python_invoke (EPlugin *plugin,
+ const gchar *name,
+ gpointer data)
+{
+ EPluginPython *plugin_python;
+ EPluginPythonPrivate *priv;
+ PyObject *pModuleName, *pFunc;
+ PyObject *pInstance, *pValue = NULL;
+
+ plugin_python = E_PLUGIN_PYTHON (plugin);
+ priv = plugin_python->priv;
+
+ /* We need to do this every time since we may be called
+ * from any thread for some uses. */
+ Py_Initialize ();
+
+ if (priv->pModule == NULL) {
+ gchar *string;
+
+ pModuleName = PyString_FromString (plugin_python->module_name);
+
+ string = g_strdup_printf (
+ "import sys; "
+ "sys.path.insert(0, '%s')",
+ plugin_python->location);
+ PyRun_SimpleString (string);
+ g_free (string);
+
+ priv->pModule = PyImport_Import (pModuleName);
+
+ Py_DECREF (pModuleName); //Free
+
+ if (priv->pModule == NULL) {
+ PyErr_Print ();
+ g_warning (
+ "Can't load python module '%s'",
+ plugin_python->location);
+ return NULL;
+ }
+
+ priv->pDict = PyModule_GetDict (priv->pModule);
+
+ if (plugin_python->pClass != NULL) {
+ priv->pClass = PyDict_GetItemString (
+ priv->pDict, plugin_python->pClass);
+ }
+ }
+
+ if (priv->pClass) {
+
+ if (PyCallable_Check (priv->pClass))
+ pInstance = PyObject_CallObject (priv->pClass, NULL);
+
+ pValue = PyObject_CallMethod (pInstance, (gchar *) name, NULL);
+
+ } else {
+
+ pFunc = PyDict_GetItemString (priv->pDict, name);
+
+ if (pFunc && PyCallable_Check (pFunc))
+ pValue = PyObject_CallObject (pFunc, NULL);
+ else
+ PyErr_Print ();
+ }
+
+ if (pValue) {
+ Py_DECREF(pValue);
+ /* Fixme */
+ return NULL;
+ } else
+ return NULL;
+}
+
+static void
+plugin_python_class_init (EPluginPythonClass *class)
+{
+ GObjectClass *object_class;
+ EPluginClass *plugin_class;
+
+ parent_class = g_type_class_peek_parent (class);
+ g_type_class_add_private (class, sizeof (EPluginPythonPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = plugin_python_finalize;
+
+ plugin_class = E_PLUGIN_CLASS (class);
+ plugin_class->construct = plugin_python_construct;
+ plugin_class->invoke = plugin_python_invoke;
+ plugin_class->type = "python";
+}
+
+static void
+plugin_python_init (EPluginPython *plugin_python)
+{
+ GHashTable *methods;
+
+ methods = g_hash_table_new_full (
+ g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify) NULL);
+
+ plugin_python->priv = E_PLUGIN_PYTHON_GET_PRIVATE (plugin_python);
+ plugin_python->priv->methods = methods;
+}
+
+GType
+e_plugin_python_get_type (void)
+{
+ return plugin_python_type;
+}
+
+void
+e_plugin_python_register_type (GTypeModule *type_module)
+{
+ static const GTypeInfo type_info = {
+ sizeof (EPluginPythonClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) plugin_python_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (EPluginPython),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) plugin_python_init,
+ NULL /* value_table */
+ };
+
+ plugin_python_type = g_type_module_register_type (
+ type_module, E_TYPE_PLUGIN,
+ "EPluginPython", &type_info, 0);
+
+ /* TODO Does this mean I can cache the instance of pyobjects? */
+ Py_Initialize ();
+}
diff --git a/modules/plugin-python/e-plugin-python.h b/modules/plugin-python/e-plugin-python.h
new file mode 100644
index 0000000000..9ee780c76c
--- /dev/null
+++ b/modules/plugin-python/e-plugin-python.h
@@ -0,0 +1,70 @@
+/*
+ * e-plugin-python.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_PLUGIN_PYTHON_H
+#define E_PLUGIN_PYTHON_H
+
+#include <e-util/e-plugin.h>
+
+/* Standard GObject macros */
+#define E_TYPE_PLUGIN_PYTHON \
+ (e_plugin_python_get_type ())
+#define E_PLUGIN_PYTHON(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), E_TYPE_PLUGIN_PYTHON, EPluginPython))
+#define E_PLUGIN_PYTHON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), E_TYPE_PLUGIN_PYTHON, EPluginPythonClass))
+#define E_IS_PLUGIN_PYTHON(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), E_TYPE_PLUGIN_PYTHON))
+#define E_IS_PLUGIN_PYTHON_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), E_TYPE_PLUGIN_PYTHON))
+#define E_PLUGIN_PYTHON_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), E_TYPE_PLUGIN_PYTHON, EPluginPythonClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EPluginPython EPluginPython;
+typedef struct _EPluginPythonClass EPluginPythonClass;
+typedef struct _EPluginPythonPrivate EPluginPythonPrivate;
+
+struct _EPluginPython {
+ EPlugin parent;
+ EPluginPythonPrivate *priv;
+
+ gchar *location;
+ gchar *pClass;
+ gchar *module_name;
+};
+
+struct _EPluginPythonClass {
+ EPluginClass parent_class;
+};
+
+GType e_plugin_python_get_type (void);
+void e_plugin_python_register_type (GTypeModule *type_module);
+
+G_END_DECLS
+
+#endif /* E_PLUGIN_PYTHON_H */
diff --git a/modules/plugin-python/evolution-module-plugin-python.c b/modules/plugin-python/evolution-module-plugin-python.c
new file mode 100644
index 0000000000..84ab3b3e8c
--- /dev/null
+++ b/modules/plugin-python/evolution-module-plugin-python.c
@@ -0,0 +1,41 @@
+/*
+ * evolution-module-plugin-python.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <config.h>
+
+#include "e-plugin-python.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+ /* Register dynamically loaded types. */
+
+ e_plugin_python_register_type (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --git a/modules/plugin-python/example/Makefile.am b/modules/plugin-python/example/Makefile.am
new file mode 100644
index 0000000000..cc14dc94d9
--- /dev/null
+++ b/modules/plugin-python/example/Makefile.am
@@ -0,0 +1,29 @@
+AM_CPPFLAGS = \
+ -DEVOLUTION_GLADEDIR=\""$(gladedir)"\" \
+ -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\"
+
+@EVO_PLUGIN_RULE@
+
+plugin_DATA = \
+ hello_python.py \
+ org-gnome-hello-python-ui.xml \
+ org-gnome-hello-python.eplug
+
+liborg_gnome_py_plug_test_la_LDFLAGS = -module -avoid-version $(NO_UNDEFINED)
+
+errordir = $(privdatadir)/errors
+
+BUILDME = org-gnome-hello-python.eplug \
+$(error_i18n)
+
+BUILT_SOURCES = \
+ $(BUILDME)
+
+EXTRA_DIST = \
+ hello_python.py \
+ org-gnome-hello-python-ui.xml \
+ org-gnome-hello-python.eplug.xml
+
+CLEANFILES = $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/modules/plugin-python/example/hello_python.py b/modules/plugin-python/example/hello_python.py
new file mode 100644
index 0000000000..16dc2a12f8
--- /dev/null
+++ b/modules/plugin-python/example/hello_python.py
@@ -0,0 +1,5 @@
+'''hello_python.py - Python source designed to '''
+'''demonstrate the use of python Eplugins'''
+
+def say_hello():
+ print 'Hello ! From python'
diff --git a/modules/plugin-python/example/org-gnome-hello-python-ui.xml b/modules/plugin-python/example/org-gnome-hello-python-ui.xml
new file mode 100644
index 0000000000..074960e84d
--- /dev/null
+++ b/modules/plugin-python/example/org-gnome-hello-python-ui.xml
@@ -0,0 +1,16 @@
+<Root>
+ <commands>
+ <cmd name="HelloPy" _label="Hello Python"
+ _tip="Python Plugin Loader tests"
+ />
+ </commands>
+
+ <menu>
+ <placeholder name="MessagePlaceholder">
+ <submenu name="Message">
+ <separator f="" name="sep"/>
+ <menuitem name="HelloPy" verb=""/>
+ </submenu>
+ </placeholder>
+ </menu>
+</Root>
diff --git a/modules/plugin-python/example/org-gnome-hello-python.eplug.xml b/modules/plugin-python/example/org-gnome-hello-python.eplug.xml
new file mode 100644
index 0000000000..8f77d5ba01
--- /dev/null
+++ b/modules/plugin-python/example/org-gnome-hello-python.eplug.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0"?>
+<e-plugin-list>
+ <e-plugin id="org.gnome.evolution.hello_python" type="python" _name="Python Test Plugin" location="@PLUGINDIR@" module_name="hello_python">
+
+ <author name="Johnny Jacob" email="jjohnny@novell.com"/>
+
+ <_description>
+ Test Plugin for Python EPlugin loader.
+ </_description>
+
+ <hook class="org.gnome.evolution.mail.bonobomenu:1.0">
+ <menu id="org.gnome.evolution.mail.browser" target="select">
+ <!-- the path to the bonobo menu description. Any UI items on Evolution should come here -->
+ <ui file="@PLUGINDIR@/org-gnome-hello-python-ui.xml"/>
+ <item type="item" verb="HelloPy" path="/commands/HelloPy" enable="one" activate="say_hello"/>
+ </menu>
+ </hook>
+
+ </e-plugin>
+</e-plugin-list>