/* * 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 * * * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) * */ /* Include first to avoid: * warning: "_POSIX_C_SOURCE" redefined */ #include #include "e-plugin-python.h" #include #include #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 *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)) { PyObject *pInstance; 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 (); }