medit/moo/moopython/mooplugin-python.c

1220 lines
34 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; coding: utf-8 -*-
*
* mooplugin-python.c
*
* Copyright (C) 2004-2005 by Yevgen Muntyan <muntyan@math.tamu.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* See COPYING file that comes with this distribution.
*/
#include <Python.h>
#define NO_IMPORT_PYGOBJECT
#include "pygobject.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "moopython/mooplugin-python.h"
#include "mooedit/mooplugin-macro.h"
#include "mooutils/mooutils-python.h"
#ifndef MOO_VERSION
#define MOO_VERSION NULL
#endif
#define MOO_PYTHON_PLUGIN_ID "moo-python"
#define MOO_TYPE_PYTHON_PLUGIN (moo_python_plugin_get_type())
#define MOO_IS_PYTHON_PLUGIN(obj_) (G_TYPE_CHECK_INSTANCE_TYPE (obj_, MOO_TYPE_PYTHON_PLUGIN))
#define MOO_PYTHON_PLUGIN(obj_) (G_TYPE_CHECK_INSTANCE_CAST ((obj_), MOO_TYPE_PYTHON_PLUGIN, MooPythonPlugin))
#define PLUGIN_SUFFIX ".py"
typedef enum {
HOOK_NEW_WINDOW = 0,
HOOK_CLOSE_WINDOW,
HOOK_NEW_DOC,
HOOK_CLOSE_DOC,
HOOK_LAST
} HookType;
typedef struct {
HookType type;
PyObject *callback;
PyObject *data;
} Hook;
typedef struct _MooPyPluginData MooPyPluginData;
typedef struct {
MooPlugin parent;
GHashTable *hook_ids;
GSList *hooks[HOOK_LAST];
int last_id;
GSList *plugins; /* MooPyPluginInfo* */
} MooPythonPlugin;
static Hook *hook_new (HookType type,
PyObject *callback,
PyObject *data);
static void hook_free (Hook *hook);
static GType moo_python_plugin_get_type (void);
static PyObject *moo_python_plugin_add_hook (MooPythonPlugin *plugin,
HookType type,
PyObject *callback,
PyObject *data);
static void moo_python_plugin_remove_hook (MooPythonPlugin *plugin,
int id);
static void moo_py_plugin_delete (MooPyPluginData *data);
static gboolean
moo_python_plugin_init (MooPythonPlugin *plugin)
{
g_return_val_if_fail (MOO_IS_PYTHON_PLUGIN (plugin), FALSE);
g_return_val_if_fail (plugin->hook_ids == NULL, FALSE);
plugin->hook_ids = g_hash_table_new (g_direct_hash, g_direct_equal);
return TRUE;
}
static void
prepend_id (gpointer id,
G_GNUC_UNUSED gpointer hook,
GSList **list)
{
*list = g_slist_prepend (*list, id);
}
static void
moo_python_plugin_deinit (MooPythonPlugin *plugin)
{
GSList *ids = NULL, *l;
g_hash_table_foreach (plugin->hook_ids, (GHFunc) prepend_id, &ids);
for (l = ids; l != NULL; l = l->next)
moo_python_plugin_remove_hook (plugin, GPOINTER_TO_INT (l->data));
g_hash_table_destroy (plugin->hook_ids);
plugin->hook_ids = NULL;
g_slist_free (ids);
g_slist_foreach (plugin->plugins, (GFunc) moo_py_plugin_delete, NULL);
g_slist_free (plugin->plugins);
plugin->plugins = NULL;
}
static void
call_hooks (MooPythonPlugin *plugin,
MooEditWindow *window,
MooEdit *doc,
HookType type)
{
GSList *l;
PyObject *py_win, *py_doc;
g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin));
g_return_if_fail (MOO_IS_EDIT_WINDOW (window));
g_return_if_fail (!doc || MOO_IS_EDIT (doc));
g_return_if_fail (type < HOOK_LAST);
py_win = pygobject_new (G_OBJECT (window));
py_doc = doc ? pygobject_new (G_OBJECT (doc)) : NULL;
for (l = plugin->hooks[type]; l != NULL; l = l->next)
{
PyObject *result;
Hook *hook = l->data;
PyTuple_SET_ITEM (hook->data, 0, py_win);
if (py_doc)
PyTuple_SET_ITEM (hook->data, 1, py_doc);
result = PyObject_Call (hook->callback, hook->data, NULL);
PyTuple_SET_ITEM (hook->data, 0, NULL);
if (py_doc)
PyTuple_SET_ITEM (hook->data, 1, NULL);
if (result)
{
Py_DECREF (result);
}
else
{
PyErr_Print ();
}
}
Py_XDECREF (py_win);
Py_XDECREF (py_doc);
}
static void
moo_python_plugin_attach_win (MooPythonPlugin *plugin,
MooEditWindow *window)
{
g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin));
g_return_if_fail (MOO_IS_EDIT_WINDOW (window));
call_hooks (plugin, window, NULL, HOOK_NEW_WINDOW);
}
static void
moo_python_plugin_detach_win (MooPythonPlugin *plugin,
MooEditWindow *window)
{
g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin));
g_return_if_fail (MOO_IS_EDIT_WINDOW (window));
call_hooks (plugin, window, NULL, HOOK_CLOSE_WINDOW);
}
static void
moo_python_plugin_attach_doc (MooPythonPlugin *plugin,
MooEdit *doc,
MooEditWindow *window)
{
g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin));
g_return_if_fail (MOO_IS_EDIT_WINDOW (window));
g_return_if_fail (MOO_IS_EDIT (doc));
call_hooks (plugin, window, doc, HOOK_NEW_DOC);
}
static void
moo_python_plugin_detach_doc (MooPythonPlugin *plugin,
MooEdit *doc,
MooEditWindow *window)
{
g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin));
g_return_if_fail (MOO_IS_EDIT_WINDOW (window));
g_return_if_fail (MOO_IS_EDIT (doc));
call_hooks (plugin, window, doc, HOOK_CLOSE_DOC);
}
static void
moo_python_plugin_read_file (G_GNUC_UNUSED MooPythonPlugin *plugin,
const char *path)
{
PyObject *mod, *code;
char *modname = NULL, *content = NULL;
GError *error = NULL;
g_return_if_fail (path != NULL);
if (!g_file_get_contents (path, &content, NULL, &error))
{
g_warning ("%s: could not read plugin file", G_STRLOC);
g_warning ("%s: %s", G_STRLOC, error->message);
g_error_free (error);
return;
}
modname = g_strdup_printf ("moo_plugin_%08x%08x", g_random_int (), g_random_int ());
code = Py_CompileString (content, path, Py_file_input);
if (!code)
{
PyErr_Print ();
goto out;
}
mod = PyImport_ExecCodeModule (modname, code);
Py_DECREF (code);
if (!mod)
{
PyErr_Print ();
goto out;
}
Py_DECREF (mod);
out:
g_free (content);
g_free (modname);
}
static void
moo_python_plugin_read_dir (MooPythonPlugin *plugin,
const char *path)
{
GDir *dir;
const char *name;
g_return_if_fail (path != NULL);
dir = g_dir_open (path, 0, NULL);
if (!dir)
return;
while ((name = g_dir_read_name (dir)))
{
char *file_path, *prefix, *suffix;
if (!g_str_has_suffix (name, PLUGIN_SUFFIX))
continue;
suffix = g_strrstr (name, PLUGIN_SUFFIX);
prefix = g_strndup (name, suffix - name);
file_path = g_build_filename (path, name, NULL);
moo_python_plugin_read_file (plugin, file_path);
g_free (prefix);
g_free (file_path);
}
g_dir_close (dir);
}
static void
moo_python_plugin_read_dirs (MooPythonPlugin *plugin,
char **dirs)
{
for ( ; dirs && *dirs; ++dirs)
moo_python_plugin_read_dir (plugin, *dirs);
}
MOO_PLUGIN_DEFINE_INFO (moo_python, MOO_PYTHON_PLUGIN_ID,
"Python plugin loader", "A snake",
"Yevgen Muntyan <muntyan@tamu.edu>",
MOO_VERSION);
MOO_PLUGIN_DEFINE_FULL (MooPython, moo_python,
moo_python_plugin_init, moo_python_plugin_deinit,
moo_python_plugin_attach_win, moo_python_plugin_detach_win,
moo_python_plugin_attach_doc, moo_python_plugin_detach_doc,
NULL, 0, 0);
gboolean
_moo_python_plugin_init (char **dirs)
{
gboolean result;
moo_python_plugin_params.visible = FALSE;
result = moo_plugin_register (MOO_TYPE_PYTHON_PLUGIN);
if (result)
{
MooPythonPlugin *plugin = moo_plugin_lookup (MOO_PYTHON_PLUGIN_ID);
g_return_val_if_fail (MOO_IS_PYTHON_PLUGIN (plugin), FALSE);
moo_python_plugin_read_dirs (plugin, dirs);
}
return result;
}
gboolean
_moo_python_plugin_reload (char **dirs)
{
MooPlugin *plugin = moo_plugin_get (MOO_TYPE_PYTHON_PLUGIN);
g_return_val_if_fail (plugin != NULL, FALSE);
if (moo_plugin_set_enabled (plugin, FALSE) &&
moo_plugin_set_enabled (plugin, TRUE))
{
moo_python_plugin_read_dirs (MOO_PYTHON_PLUGIN (plugin), dirs);
return TRUE;
}
else
{
return FALSE;
}
}
static PyObject*
moo_python_plugin_add_hook (MooPythonPlugin *plugin,
HookType type,
PyObject *callback,
PyObject *data)
{
int id = ++plugin->last_id;
Hook *hook = hook_new (type, callback, data);
plugin->hooks[type] = g_slist_prepend (plugin->hooks[type], hook);
g_hash_table_insert (plugin->hook_ids, GINT_TO_POINTER (id), hook);
return_Int (id);
}
PyObject*
_moo_python_plugin_hook (const char *event,
PyObject *callback,
PyObject *data)
{
MooPythonPlugin *plugin;
PyObject *result;
plugin = moo_plugin_lookup (MOO_PYTHON_PLUGIN_ID);
g_return_val_if_fail (MOO_IS_PYTHON_PLUGIN (plugin), NULL);
if (!strcmp (event, "new-window"))
result = moo_python_plugin_add_hook (plugin, HOOK_NEW_WINDOW, callback, data);
else if (!strcmp (event, "close-window"))
result = moo_python_plugin_add_hook (plugin, HOOK_CLOSE_WINDOW, callback, data);
else if (!strcmp (event, "new-doc"))
result = moo_python_plugin_add_hook (plugin, HOOK_NEW_DOC, callback, data);
else if (!strcmp (event, "close-doc"))
result = moo_python_plugin_add_hook (plugin, HOOK_CLOSE_DOC, callback, data);
else
return_TypeErr ("invalid event type");
return result;
}
static Hook*
hook_new (HookType type,
PyObject *callback,
PyObject *data)
{
int data_len, extra, i;
Hook *hook = g_new0 (Hook, 1);
hook->type = type;
hook->callback = callback;
Py_INCREF (callback);
data_len = data ? PyTuple_GET_SIZE (data) : 0;
switch (type)
{
case HOOK_NEW_WINDOW:
case HOOK_CLOSE_WINDOW:
extra = 1;
break;
case HOOK_NEW_DOC:
case HOOK_CLOSE_DOC:
extra = 2;
break;
case HOOK_LAST:
g_return_val_if_reached (NULL);
}
hook->data = PyTuple_New (data_len + extra);
for (i = 0; i < data_len; ++i)
{
PyTuple_SET_ITEM (hook->data, i + extra,
PyTuple_GET_ITEM (data, i));
Py_INCREF (PyTuple_GET_ITEM (data, i));
}
return hook;
}
static void
moo_python_plugin_remove_hook (MooPythonPlugin *plugin,
int id)
{
Hook *hook;
g_return_if_fail (MOO_IS_PYTHON_PLUGIN (plugin));
g_return_if_fail (id > 0);
hook = g_hash_table_lookup (plugin->hook_ids, GINT_TO_POINTER (id));
g_return_if_fail (hook != NULL);
plugin->hooks[hook->type] = g_slist_remove (plugin->hooks[hook->type], hook);
g_hash_table_remove (plugin->hook_ids, GINT_TO_POINTER (id));
hook_free (hook);
}
static void
hook_free (Hook *hook)
{
if (hook)
{
int i, extra = 0;
switch (hook->type)
{
case HOOK_NEW_WINDOW:
case HOOK_CLOSE_WINDOW:
extra = 1;
break;
case HOOK_NEW_DOC:
case HOOK_CLOSE_DOC:
extra = 2;
break;
case HOOK_LAST:
g_critical ("%s: oops", G_STRLOC);
extra = 0;
break;
}
for (i = 0; i < extra; ++i)
{
PyTuple_SET_ITEM (hook->data, i, Py_None);
Py_INCREF (Py_None);
}
Py_XDECREF (hook->callback);
Py_XDECREF (hook->data);
g_free (hook);
}
}
/***************************************************************************/
/* Python plugins
*/
#define MOO_PY_PLUGIN(obj_) ((MooPyPlugin*)obj_)
#define MOO_PY_WIN_PLUGIN(obj_) ((MooPyWinPlugin*)obj_)
#define MOO_PY_DOC_PLUGIN(obj_) ((MooPyDocPlugin*)obj_)
typedef struct _MooPyPlugin MooPyPlugin;
typedef struct _MooPyPluginClass MooPyPluginClass;
typedef struct _MooPyWinPlugin MooPyWinPlugin;
typedef struct _MooPyWinPluginClass MooPyWinPluginClass;
typedef struct _MooPyDocPlugin MooPyDocPlugin;
typedef struct _MooPyDocPluginClass MooPyDocPluginClass;
struct _MooPyPluginData {
PyObject *py_plugin_type;
PyObject *py_win_plugin_type;
PyObject *py_doc_plugin_type;
GType plugin_type;
GType win_plugin_type;
GType doc_plugin_type;
};
struct _MooPyPlugin {
MooPlugin base;
MooPyPluginData *class_data;
PyObject *instance;
};
struct _MooPyPluginClass {
MooPluginClass base_class;
MooPyPluginData *data;
};
struct _MooPyWinPlugin {
MooWinPlugin base;
MooPyPluginData *class_data;
PyObject *instance;
};
struct _MooPyWinPluginClass {
MooWinPluginClass base_class;
MooPyPluginData *data;
};
struct _MooPyDocPlugin {
MooDocPlugin base;
MooPyPluginData *class_data;
PyObject *instance;
};
struct _MooPyDocPluginClass {
MooDocPluginClass base_class;
MooPyPluginData *data;
};
static gpointer moo_py_plugin_parent_class;
static gpointer moo_py_win_plugin_parent_class;
static gpointer moo_py_doc_plugin_parent_class;
static void moo_py_plugin_class_init (MooPyPluginClass *klass,
MooPyPluginData *data);
static void moo_py_plugin_instance_init (MooPyPlugin *plugin,
MooPyPluginClass *klass);
static void moo_py_plugin_finalize (GObject *object);
static void moo_py_win_plugin_class_init (MooPyWinPluginClass *klass,
MooPyPluginData *data);
static void moo_py_win_plugin_instance_init (MooPyWinPlugin *plugin,
MooPyWinPluginClass *klass);
static void moo_py_win_plugin_finalize (GObject *object);
static void moo_py_doc_plugin_class_init (MooPyDocPluginClass *klass,
MooPyPluginData *data);
static void moo_py_doc_plugin_instance_init (MooPyDocPlugin *plugin,
MooPyDocPluginClass *klass);
static void moo_py_doc_plugin_finalize (GObject *object);
static gboolean moo_py_plugin_init (MooPlugin *plugin);
static void moo_py_plugin_deinit (MooPlugin *plugin);
static void moo_py_plugin_attach_win (MooPlugin *plugin,
MooEditWindow *window);
static void moo_py_plugin_detach_win (MooPlugin *plugin,
MooEditWindow *window);
static void moo_py_plugin_attach_doc (MooPlugin *plugin,
MooEdit *doc,
MooEditWindow *window);
static void moo_py_plugin_detach_doc (MooPlugin *plugin,
MooEdit *doc,
MooEditWindow *window);
static gboolean moo_py_win_plugin_create (MooWinPlugin *plugin);
static void moo_py_win_plugin_destroy (MooWinPlugin *plugin);
static gboolean moo_py_doc_plugin_create (MooDocPlugin *plugin);
static void moo_py_doc_plugin_destroy (MooDocPlugin *plugin);
static MooPluginInfo *get_plugin_info (PyObject *object);
static GType generate_win_plugin_type (PyObject *py_type,
MooPyPluginData *data);
static GType generate_doc_plugin_type (PyObject *py_type,
MooPyPluginData *data);
static GtkWidget *moo_py_plugin_create_prefs_page (MooPlugin *plugin);
static void plugin_info_free (MooPluginInfo *info);
static void
moo_py_plugin_class_init (MooPyPluginClass *klass,
MooPyPluginData *data)
{
MooPluginClass *plugin_class = MOO_PLUGIN_CLASS (klass);
GObjectClass *gobj_class = G_OBJECT_CLASS (klass);
moo_py_plugin_parent_class = g_type_class_peek_parent (klass);
klass->data = data;
gobj_class->finalize = moo_py_plugin_finalize;
plugin_class->plugin_system_version = MOO_PLUGIN_CURRENT_VERSION;
if (data->py_plugin_type)
{
plugin_class->init = moo_py_plugin_init;
plugin_class->deinit = moo_py_plugin_deinit;
plugin_class->attach_win = moo_py_plugin_attach_win;
plugin_class->detach_win = moo_py_plugin_detach_win;
plugin_class->attach_doc = moo_py_plugin_attach_doc;
plugin_class->detach_doc = moo_py_plugin_detach_doc;
plugin_class->create_prefs_page = moo_py_plugin_create_prefs_page;
}
}
static void
moo_py_plugin_instance_init (MooPyPlugin *plugin,
MooPyPluginClass *klass)
{
MooPlugin *moo_plugin = MOO_PLUGIN (plugin);
plugin->class_data = klass->data;
plugin->instance = PyObject_CallObject (klass->data->py_plugin_type, NULL);
if (!plugin->instance)
{
PyErr_Print ();
g_warning ("%s: could not create plugin instance", G_STRLOC);
}
moo_plugin->info = get_plugin_info (plugin->instance);
if (klass->data->py_win_plugin_type && !klass->data->win_plugin_type)
klass->data->win_plugin_type = generate_win_plugin_type (klass->data->py_win_plugin_type, klass->data);
if (klass->data->py_doc_plugin_type && !klass->data->doc_plugin_type)
klass->data->doc_plugin_type = generate_doc_plugin_type (klass->data->py_doc_plugin_type, klass->data);
moo_plugin->win_plugin_type = klass->data->win_plugin_type;
moo_plugin->doc_plugin_type = klass->data->doc_plugin_type;
}
static void
moo_py_plugin_finalize (GObject *object)
{
MooPyPlugin *py_plugin = MOO_PY_PLUGIN (object);
MooPlugin *plugin = MOO_PLUGIN (object);
Py_XDECREF (py_plugin->instance);
plugin_info_free (plugin->info);
G_OBJECT_CLASS(moo_py_plugin_parent_class)->finalize (object);
}
PyObject*
_moo_python_plugin_register (PyObject *py_plugin_type,
PyObject *py_win_plugin_type,
PyObject *py_doc_plugin_type)
{
char *plugin_type_name = NULL;
static GTypeInfo plugin_type_info;
MooPyPluginData *class_data;
MooPlugin *base;
int i;
g_return_val_if_fail (py_plugin_type != NULL, NULL);
g_return_val_if_fail (PyType_Check (py_plugin_type), NULL);
g_return_val_if_fail (!py_win_plugin_type || PyType_Check (py_win_plugin_type), NULL);
g_return_val_if_fail (!py_doc_plugin_type || PyType_Check (py_doc_plugin_type), NULL);
base = moo_plugin_get (MOO_TYPE_PYTHON_PLUGIN);
g_return_val_if_fail (base != NULL, NULL);
g_return_val_if_fail (moo_plugin_initialized (base), NULL);
for (i = 0; i < 1000; ++i)
{
plugin_type_name = g_strdup_printf ("MooPyPlugin-%08x", g_random_int ());
if (!g_type_from_name (plugin_type_name))
break;
g_free (plugin_type_name);
plugin_type_name = NULL;
}
if (!plugin_type_name)
return_RuntimeErr ("could not find name for plugin class");
class_data = g_new0 (MooPyPluginData, 1);
class_data->py_plugin_type = py_plugin_type;
class_data->py_win_plugin_type = py_win_plugin_type;
class_data->py_doc_plugin_type = py_doc_plugin_type;
Py_XINCREF (py_plugin_type);
Py_XINCREF (py_win_plugin_type);
Py_XINCREF (py_doc_plugin_type);
plugin_type_info.class_size = sizeof (MooPyPluginClass);
plugin_type_info.class_init = (GClassInitFunc) moo_py_plugin_class_init;
plugin_type_info.class_data = class_data;
plugin_type_info.instance_size = sizeof (MooPyPlugin);
plugin_type_info.instance_init = (GInstanceInitFunc) moo_py_plugin_instance_init;
class_data->plugin_type = g_type_register_static (MOO_TYPE_PLUGIN, plugin_type_name,
&plugin_type_info, 0);
g_free (plugin_type_name);
if (!moo_plugin_register (class_data->plugin_type))
{
Py_XDECREF (class_data->py_plugin_type);
Py_XDECREF (class_data->py_win_plugin_type);
Py_XDECREF (class_data->py_doc_plugin_type);
g_free (class_data);
return_RuntimeErr ("could not register plugin");
}
MOO_PYTHON_PLUGIN(base)->plugins =
g_slist_prepend (MOO_PYTHON_PLUGIN(base)->plugins, class_data);
return_None;
}
static void
moo_py_plugin_delete (MooPyPluginData *data)
{
g_return_if_fail (data != NULL);
moo_plugin_unregister (data->plugin_type);
Py_XDECREF (data->py_plugin_type);
Py_XDECREF (data->py_win_plugin_type);
Py_XDECREF (data->py_doc_plugin_type);
g_free (data);
}
static void
plugin_info_free (MooPluginInfo *info)
{
if (info)
{
g_free ((char*) info->id);
g_free ((char*) info->name);
g_free ((char*) info->description);
g_free ((char*) info->author);
g_free ((char*) info->version);
g_free (info->params);
g_free (info->prefs_params);
g_free (info);
}
}
static char *
dict_get_string (PyObject *dict,
const char *key)
{
PyObject *val, *strval;
char *result;
val = PyDict_GetItemString (dict, (char*) key);
if (!val)
return NULL;
strval = PyObject_Str (val);
Py_DECREF (val);
if (!strval)
{
PyErr_Print ();
return NULL;
}
result = g_strdup (PyString_AS_STRING (strval));
Py_DECREF (strval);
return result;
}
static gboolean
dict_get_bool (PyObject *dict,
const char *key,
gboolean default_val)
{
PyObject *val;
gboolean result;
val = PyDict_GetItemString (dict, (char*) key);
if (!val)
return default_val;
result = PyObject_IsTrue (val);
Py_DECREF (val);
return result;
}
static MooPluginInfo*
get_plugin_info (PyObject *object)
{
MooPluginInfo *info;
PyObject *result, *meth;
if (!PyObject_HasAttrString (object, (char*) "get_info"))
{
g_critical ("%s: no get_info attribute", G_STRLOC);
return NULL;
}
meth = PyObject_GetAttrString (object, (char*) "get_info");
if (!meth)
{
PyErr_Print ();
return NULL;
}
if (!PyCallable_Check (meth))
{
g_critical ("%s: get_info is not callable", G_STRLOC);
Py_DECREF (meth);
return NULL;
}
result = PyObject_CallObject (meth, NULL);
Py_DECREF (meth);
if (!result)
{
PyErr_Print ();
return NULL;
}
if (!PyDict_Check (result))
{
g_critical ("%s: not a dict", G_STRLOC);
Py_DECREF (result);
return NULL;
}
info = g_new0 (MooPluginInfo, 1);
info->params = g_new0 (MooPluginParams, 1);
info->prefs_params = g_new0 (MooPluginPrefsParams, 1);
info->id = dict_get_string (result, "id");
info->name = dict_get_string (result, "name");
info->description = dict_get_string (result, "description");
info->author = dict_get_string (result, "author");
info->version = dict_get_string (result, "version");
info->params->enabled = dict_get_bool (result, "enabled", TRUE);
info->params->visible = dict_get_bool (result, "visible", TRUE);
return info;
}
static GType
generate_win_plugin_type (PyObject *py_type,
MooPyPluginData *class_data)
{
GType type;
char *type_name = NULL;
static GTypeInfo type_info;
int i;
g_return_val_if_fail (py_type != NULL, 0);
g_return_val_if_fail (PyType_Check (py_type), 0);
for (i = 0; i < 1000; ++i)
{
type_name = g_strdup_printf ("MooPyWinPlugin-%08x", g_random_int ());
if (!g_type_from_name (type_name))
break;
g_free (type_name);
type_name = NULL;
}
if (!type_name)
{
g_critical ("%s: could not find name for win plugin class", G_STRLOC);
return 0;
}
type_info.class_size = sizeof (MooPyWinPluginClass);
type_info.class_init = (GClassInitFunc) moo_py_win_plugin_class_init;
type_info.class_data = class_data;
type_info.instance_size = sizeof (MooPyWinPlugin);
type_info.instance_init = (GInstanceInitFunc) moo_py_win_plugin_instance_init;
type = g_type_register_static (MOO_TYPE_WIN_PLUGIN, type_name, &type_info, 0);
g_free (type_name);
return type;
}
static GType
generate_doc_plugin_type (PyObject *py_type,
MooPyPluginData *class_data)
{
char *type_name = NULL;
static GTypeInfo type_info;
int i;
GType type;
g_return_val_if_fail (py_type != NULL, 0);
g_return_val_if_fail (PyType_Check (py_type), 0);
for (i = 0; i < 1000; ++i)
{
type_name = g_strdup_printf ("MooPyDocPlugin-%08x", g_random_int ());
if (!g_type_from_name (type_name))
break;
g_free (type_name);
type_name = NULL;
}
if (!type_name)
{
g_critical ("%s: could not find name for doc plugin class", G_STRLOC);
return 0;
}
type_info.class_size = sizeof (MooPyDocPluginClass);
type_info.class_init = (GClassInitFunc) moo_py_doc_plugin_class_init;
type_info.class_data = class_data;
type_info.instance_size = sizeof (MooPyDocPlugin);
type_info.instance_init = (GInstanceInitFunc) moo_py_doc_plugin_instance_init;
type = g_type_register_static (MOO_TYPE_DOC_PLUGIN, type_name, &type_info, 0);
g_free (type_name);
return type;
}
static void
moo_py_win_plugin_class_init (MooPyWinPluginClass *klass,
MooPyPluginData *data)
{
MooWinPluginClass *plugin_class = MOO_WIN_PLUGIN_CLASS (klass);
GObjectClass *gobj_class = G_OBJECT_CLASS (klass);
moo_py_win_plugin_parent_class = g_type_class_peek_parent (klass);
klass->data = data;
gobj_class->finalize = moo_py_win_plugin_finalize;
plugin_class->create = moo_py_win_plugin_create;
plugin_class->destroy = moo_py_win_plugin_destroy;
}
static void
moo_py_win_plugin_instance_init (MooPyWinPlugin *plugin,
MooPyWinPluginClass *klass)
{
PyObject *args;
plugin->class_data = klass->data;
args = PyTuple_New (0);
plugin->instance = PyType_GenericNew ((PyTypeObject*) klass->data->py_win_plugin_type, args, NULL);
Py_DECREF (args);
}
static void
moo_py_win_plugin_finalize (GObject *object)
{
MooPyWinPlugin *plugin = MOO_PY_WIN_PLUGIN (object);
Py_XDECREF (plugin->instance);
G_OBJECT_CLASS(moo_py_win_plugin_parent_class)->finalize (object);
}
static void
moo_py_doc_plugin_class_init (MooPyDocPluginClass *klass,
MooPyPluginData *data)
{
MooDocPluginClass *plugin_class = MOO_DOC_PLUGIN_CLASS (klass);
GObjectClass *gobj_class = G_OBJECT_CLASS (klass);
moo_py_doc_plugin_parent_class = g_type_class_peek_parent (klass);
klass->data = data;
gobj_class->finalize = moo_py_doc_plugin_finalize;
plugin_class->create = moo_py_doc_plugin_create;
plugin_class->destroy = moo_py_doc_plugin_destroy;
}
static void
moo_py_doc_plugin_instance_init (MooPyDocPlugin *plugin,
MooPyDocPluginClass *klass)
{
PyObject *args;
plugin->class_data = klass->data;
args = PyTuple_New (0);
plugin->instance = PyType_GenericNew ((PyTypeObject*) klass->data->py_doc_plugin_type, args, NULL);
Py_DECREF (args);
}
static void
moo_py_doc_plugin_finalize (GObject *object)
{
MooPyDocPlugin *plugin = MOO_PY_DOC_PLUGIN (object);
Py_XDECREF (plugin->instance);
G_OBJECT_CLASS(moo_py_doc_plugin_parent_class)->finalize (object);
}
/**************************************************************************/
/* Plugin methods
*/
static gboolean
call_any_meth__ (PyObject *instance,
MooEdit *doc,
MooEditWindow *window,
const char *meth_name)
{
PyObject *result, *meth, *py_window, *py_doc;
if (!instance)
{
g_critical ("%s: oops", G_STRLOC);
return FALSE;
}
if (!PyObject_HasAttrString (instance, (char*) meth_name))
return TRUE;
meth = PyObject_GetAttrString (instance, (char*) meth_name);
if (!meth)
{
PyErr_Print ();
return FALSE;
}
if (!PyCallable_Check (meth))
{
g_critical ("%s: %s is not callable", G_STRLOC, meth_name);
Py_DECREF (meth);
return FALSE;
}
py_window = window ? pygobject_new (G_OBJECT (window)) : NULL;
py_doc = doc ? pygobject_new (G_OBJECT (doc)) : NULL;
if (window)
{
if (doc)
result = PyObject_CallFunction (meth, (char*) "(OO)", py_doc, py_window);
else
result = PyObject_CallFunction (meth, (char*) "(O)", py_window);
}
else
{
result = PyObject_CallObject (meth, NULL);
}
Py_XDECREF (meth);
Py_XDECREF (py_window);
Py_XDECREF (py_doc);
if (result)
{
gboolean bool_result = PyObject_IsTrue (result);
Py_DECREF (result);
return bool_result;
}
else
{
PyErr_Print ();
return FALSE;
}
}
static gboolean
call_bool_meth (PyObject *instance,
MooEdit *doc,
MooEditWindow *window,
const char *meth_name)
{
return call_any_meth__ (instance, doc, window, meth_name);
}
static void
call_meth (PyObject *instance,
MooEdit *doc,
MooEditWindow *window,
const char *meth_name)
{
call_any_meth__ (instance, doc, window, meth_name);
}
static gboolean
moo_py_plugin_init (MooPlugin *plugin)
{
return call_bool_meth (MOO_PY_PLUGIN(plugin)->instance, NULL, NULL, "init");
}
static void
moo_py_plugin_deinit (MooPlugin *plugin)
{
call_meth (MOO_PY_PLUGIN(plugin)->instance, NULL, NULL, "deinit");
}
static void
moo_py_plugin_attach_win (MooPlugin *plugin,
MooEditWindow *window)
{
call_meth (MOO_PY_PLUGIN(plugin)->instance, NULL, window, "attach_win");
}
static void
moo_py_plugin_detach_win (MooPlugin *plugin,
MooEditWindow *window)
{
call_meth (MOO_PY_PLUGIN(plugin)->instance, NULL, window, "detach_win");
}
static void
moo_py_plugin_attach_doc (MooPlugin *plugin,
MooEdit *doc,
MooEditWindow *window)
{
call_meth (MOO_PY_PLUGIN(plugin)->instance, doc, window, "attach_doc");
}
static void
moo_py_plugin_detach_doc (MooPlugin *plugin,
MooEdit *doc,
MooEditWindow *window)
{
call_meth (MOO_PY_PLUGIN(plugin)->instance, doc, window, "detach_doc");
}
static gboolean
moo_py_win_plugin_create (MooWinPlugin *plugin)
{
return call_bool_meth (MOO_PY_WIN_PLUGIN(plugin)->instance,
NULL, plugin->window, "create");
}
static void
moo_py_win_plugin_destroy (MooWinPlugin *plugin)
{
call_meth (MOO_PY_WIN_PLUGIN(plugin)->instance,
NULL, plugin->window, "destroy");
}
static gboolean
moo_py_doc_plugin_create (MooDocPlugin *plugin)
{
return call_bool_meth (MOO_PY_DOC_PLUGIN(plugin)->instance,
plugin->doc, plugin->window, "create");
}
static void
moo_py_doc_plugin_destroy (MooDocPlugin *plugin)
{
call_meth (MOO_PY_DOC_PLUGIN(plugin)->instance,
plugin->doc, plugin->window, "destroy");
}
static GtkWidget*
moo_py_plugin_create_prefs_page (MooPlugin *plugin)
{
PyObject *result, *meth;
MooPyPlugin *py_plugin = MOO_PY_PLUGIN (plugin);
g_return_val_if_fail (py_plugin->instance != NULL, NULL);
if (!PyObject_HasAttrString (py_plugin->instance, (char*) "create_prefs_page"))
return NULL;
meth = PyObject_GetAttrString (py_plugin->instance, (char*) "create_prefs_page");
if (!meth)
{
PyErr_Print ();
return NULL;
}
if (!PyCallable_Check (meth))
{
g_critical ("%s: create_prefs_page is not callable", G_STRLOC);
Py_DECREF (meth);
return NULL;
}
result = PyObject_CallObject (meth, NULL);
Py_DECREF (meth);
if (!result)
{
PyErr_Print ();
return NULL;
}
else
{
gpointer page = pygobject_get (result);
g_object_ref (page);
Py_DECREF (result);
return page;
}
}