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.
This commit is contained in:
31
modules/plugin-python/Makefile.am
Normal file
31
modules/plugin-python/Makefile.am
Normal file
@ -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
|
||||
230
modules/plugin-python/e-plugin-python.c
Normal file
230
modules/plugin-python/e-plugin-python.c
Normal file
@ -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 ();
|
||||
}
|
||||
70
modules/plugin-python/e-plugin-python.h
Normal file
70
modules/plugin-python/e-plugin-python.h
Normal file
@ -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 */
|
||||
41
modules/plugin-python/evolution-module-plugin-python.c
Normal file
41
modules/plugin-python/evolution-module-plugin-python.c
Normal file
@ -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)
|
||||
{
|
||||
}
|
||||
29
modules/plugin-python/example/Makefile.am
Normal file
29
modules/plugin-python/example/Makefile.am
Normal file
@ -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
|
||||
5
modules/plugin-python/example/hello_python.py
Normal file
5
modules/plugin-python/example/hello_python.py
Normal file
@ -0,0 +1,5 @@
|
||||
'''hello_python.py - Python source designed to '''
|
||||
'''demonstrate the use of python Eplugins'''
|
||||
|
||||
def say_hello():
|
||||
print 'Hello ! From python'
|
||||
16
modules/plugin-python/example/org-gnome-hello-python-ui.xml
Normal file
16
modules/plugin-python/example/org-gnome-hello-python-ui.xml
Normal file
@ -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>
|
||||
@ -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>
|
||||
Reference in New Issue
Block a user