From 97fa09113c7988e4b4639190ba9bc51f9ced4d33 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Fri, 14 Dec 2018 17:38:10 +0100 Subject: Extended the Python API to build custom GUI panels. --- plugins/pychrysalide/gui/core/Makefile.am | 3 +- plugins/pychrysalide/gui/core/module.c | 2 + plugins/pychrysalide/gui/core/panels.c | 122 ++++++++++++ plugins/pychrysalide/gui/core/panels.h | 39 ++++ plugins/pychrysalide/gui/editem.c | 296 +++++++++++++----------------- plugins/pychrysalide/gui/editem.h | 14 ++ plugins/pychrysalide/gui/panels/panel.c | 213 +++++++++++++++++++-- plugins/pychrysalide/gui/panels/panel.h | 3 + plugins/pychrysalide/helpers.c | 5 +- plugins/pychrysalide/plugin.c | 9 + 10 files changed, 522 insertions(+), 184 deletions(-) create mode 100644 plugins/pychrysalide/gui/core/panels.c create mode 100644 plugins/pychrysalide/gui/core/panels.h diff --git a/plugins/pychrysalide/gui/core/Makefile.am b/plugins/pychrysalide/gui/core/Makefile.am index 08e50f1..4f7e05b 100644 --- a/plugins/pychrysalide/gui/core/Makefile.am +++ b/plugins/pychrysalide/gui/core/Makefile.am @@ -3,7 +3,8 @@ noinst_LTLIBRARIES = libpychrysaguicore.la libpychrysaguicore_la_SOURCES = \ items.h items.c \ - module.h module.c + module.h module.c \ + panels.h panels.c libpychrysaguicore_la_LDFLAGS = diff --git a/plugins/pychrysalide/gui/core/module.c b/plugins/pychrysalide/gui/core/module.c index f90c70c..8a28c08 100644 --- a/plugins/pychrysalide/gui/core/module.c +++ b/plugins/pychrysalide/gui/core/module.c @@ -29,6 +29,7 @@ #include "items.h" +#include "panels.h" #include "../../helpers.h" @@ -89,6 +90,7 @@ bool populate_gui_core_module(void) result = true; if (result) result = ensure_python_items_is_registered(); + if (result) result = populate_gui_core_module_with_panels(); assert(result); diff --git a/plugins/pychrysalide/gui/core/panels.c b/plugins/pychrysalide/gui/core/panels.c new file mode 100644 index 0000000..3b88b18 --- /dev/null +++ b/plugins/pychrysalide/gui/core/panels.c @@ -0,0 +1,122 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * panels.c - équivalent Python du fichier "gui/core/panels.c" + * + * Copyright (C) 2018 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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 3 of the License, or + * (at your option) any later version. + * + * Chrysalide 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "panels.h" + + +#include + + +#include +#include + + +#include "../../access.h" +#include "../../helpers.h" +#include "../panels/panel.h" + + + +/* Enregistre un panneau comme partie intégrante de l'éditeur. */ +static PyObject *py_panels_register_item(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Enregistre un panneau comme partie intégrante de l'éditeur. * +* * +* Retour : None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_panels_register_item(PyObject *self, PyObject *args) +{ + GPanelItem *item; /* Panneau à traiter */ + GGenConfig *config; /* Configuration à consulter */ + int ret; /* Bilan de lecture des args. */ + + config = NULL; + + ret = PyArg_ParseTuple(args, "O&", convert_to_panel_item, &item); + if (!ret) return NULL; + + if (config == NULL) + config = get_main_configuration(); + + register_panel_item(item, config); + + /** + * Si Python ne voit plus la variable représentant le panneau utilisée, + * il va la supprimer, ce qui va supprimer le composant GTK. + * + * On sera donc en situation de Use-After-Free, dont les conséquences + * arrivent très vite. + */ + pygobject_new(G_OBJECT(item)); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Définit une extension du module 'gui.core' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_gui_core_module_with_panels(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + static PyMethodDef py_panels_methods[] = { + + { "register_panel", py_panels_register_item, + METH_VARARGS, + "register_panel(item, config, /)\n--\n\nRegister a panel for the GUI." + }, + { NULL } + + }; + + module = get_access_to_python_module("pychrysalide.gui.core"); + + result = register_python_module_methods(module, py_panels_methods); + + return result; + +} diff --git a/plugins/pychrysalide/gui/core/panels.h b/plugins/pychrysalide/gui/core/panels.h new file mode 100644 index 0000000..fd17908 --- /dev/null +++ b/plugins/pychrysalide/gui/core/panels.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * panels.h - prototypes pour l'équivalent Python du fichier "gui/core/panels.h" + * + * Copyright (C) 2018 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide 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 3 of the License, or + * (at your option) any later version. + * + * Chrysalide 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_GUI_CORE_PANELS_H +#define _PLUGINS_PYCHRYSALIDE_GUI_CORE_PANELS_H + + +#include +#include + + + +/* Définit une extension du module 'gui.core' à compléter. */ +bool populate_gui_core_module_with_panels(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GUI_CORE_PANELS_H */ diff --git a/plugins/pychrysalide/gui/editem.c b/plugins/pychrysalide/gui/editem.c index c60d678..986d1cb 100644 --- a/plugins/pychrysalide/gui/editem.c +++ b/plugins/pychrysalide/gui/editem.c @@ -33,41 +33,40 @@ #include "../access.h" #include "../helpers.h" +#include "../pychrysa.h" #include "../analysis/binary.h" #include "../gtkext/displaypanel.h" -/* Réagit à un changement du binaire courant. */ -static void _change_editor_item_content_python_wrapper(GEditorItem *, GLoadedContent *, GLoadedContent *); +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Réagit à un changement de vue. */ -static void _change_editor_item_view_python_wrapper(GEditorItem *, GLoadedPanel *, GLoadedPanel *); -/* Réagit à un changement de contenu. */ -static void _update_editor_item_view_python_wrapper(GEditorItem *, GLoadedPanel *); +/* Réagit à un changement de contenu chargé en cours d'analyse. */ +static void py_editor_item_change_content_wrapper(GEditorItem *, GLoadedContent *, GLoadedContent *); /* Réagit à un changement de contenu chargé en cours d'analyse. */ -static PyObject *py_editor_item_change_content(PyObject *, PyObject *); +static void py_editor_item_change_content_wrapper(GEditorItem *, GLoadedContent *, GLoadedContent *); /* Réagit à un changement de vue du contenu en cours d'analyse. */ -static PyObject *py_editor_item_change_view(PyObject *, PyObject *); +static void py_editor_item_change_view_wrapper(GEditorItem *, GLoadedPanel *, GLoadedPanel *); /* Réagit à une modification de la vue du contenu analysé. */ -static PyObject *py_editor_item_update_view(PyObject *, PyObject *); +static void py_editor_item_update_view_wrapper(GEditorItem *, GLoadedPanel *); + -/* Procède à l'enregistrement d'un élément reactif de l'éditeur. */ -static PyObject *py_editor_item_register(PyObject *, PyObject *); +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : item = élément à actualiser. * -* old = ancien contenu chargé analysé. * -* new = nouveau contenu chargé à analyser. * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * * * -* Description : Réagit à un changement du binaire courant. * +* Description : Initialise la classe des éléménts pour l'interface graphique.* * * * Retour : - * * * @@ -75,43 +74,22 @@ static PyObject *py_editor_item_register(PyObject *, PyObject *); * * ******************************************************************************/ -static void _change_editor_item_content_python_wrapper(GEditorItem *item, GLoadedContent *old, GLoadedContent *new) +void py_editor_item_init_gclass(GEditorItemClass *class, gpointer unused) { - PyObject *target; /* Version Python de l'élément */ - PyObject *args; /* Arguments pour l'appel */ - PyObject *value; /* Retour obtenu */ - - /** - * Normalement, l'objet Python est enregistré dans la liste de Chrysalide - * des éléments d'éditeur, via py_editor_item_register(), donc son compteur - * de références doit le maintenir en vie. - * - * On peut donc le récupérer directement depuis l'instance GLib, sans passer - * par la procédure de pygobject, qui obligerait à connaître le type précis - * de l'instance GLib manipulée. - */ - target = pygobject_new(G_OBJECT(item)); - - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(old))); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(new))); - - value = run_python_method(target, "change_content", args); - - Py_XDECREF(value); - Py_DECREF(args); - Py_DECREF(target); + class->change_content = py_editor_item_change_content_wrapper; + class->change_view = py_editor_item_change_view_wrapper; + class->update_view = py_editor_item_update_view_wrapper; } /****************************************************************************** * * -* Paramètres : item = élément à actualiser. * -* old = ancienne vue du contenu chargé analysé. * -* new = nouvelle vue du contenu chargé analysé. * +* Paramètres : item = instance à consulter. * +* old = ancien contenu chargé analysé. * +* new = nouveau contenu chargé à analyser. * * * -* Description : Réagit à un changement de vue. * +* Description : Réagit à un changement de contenu chargé en cours d'analyse. * * * * Retour : - * * * @@ -119,42 +97,64 @@ static void _change_editor_item_content_python_wrapper(GEditorItem *item, GLoade * * ******************************************************************************/ -static void _change_editor_item_view_python_wrapper(GEditorItem *item, GLoadedPanel *old, GLoadedPanel *new) +static void py_editor_item_change_content_wrapper(GEditorItem *item, GLoadedContent *old, GLoadedContent *new) { - PyObject *target; /* Version Python de l'élément */ + PyObject *pyobj; /* Objet Python concerné */ + PyThreadState *tstate; /* Contexte d'environnement */ + PyObject *pyold; /* Conversion ou None */ + PyObject *pynew; /* Conversion ou None */ PyObject *args; /* Arguments pour l'appel */ - PyObject *value; /* Retour obtenu */ + PyObject *pyret; /* Retour de Python */ + + pyobj = pygobject_new(G_OBJECT(item)); + + tstate = get_pychrysalide_main_tstate(); + + if (tstate != NULL) + PyEval_RestoreThread(tstate); + + if (has_python_method(pyobj, "_change_content")) + { + if (old != NULL) + pyold = pygobject_new(G_OBJECT(old)); + else + { + pyold = Py_None; + Py_INCREF(pyold); + } - /** - * Normalement, l'objet Python est enregistré dans la liste de Chrysalide - * des éléments d'éditeur, via py_editor_item_register(), donc son compteur - * de références doit le maintenir en vie. - * - * On peut donc le récupérer directement depuis l'instane GLib, sans passer - * par la procédure de pygobject, qui obligerait à connaître le type précis - * de l'instance GLib manipulée. - */ - target = pygobject_new(G_OBJECT(item)); + if (new != NULL) + pynew = pygobject_new(G_OBJECT(new)); + else + { + pynew = Py_None; + Py_INCREF(pynew); + } + + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, pyold); + PyTuple_SetItem(args, 1, pynew); - args = PyTuple_New(2); - PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(old))); - PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(new))); + pyret = run_python_method(pyobj, "_change_content", args); - value = run_python_method(target, "change_view", args); + Py_DECREF(args); + Py_DECREF(pyret); - Py_XDECREF(value); - Py_DECREF(args); - Py_DECREF(target); + } + + if (tstate != NULL) + PyEval_SaveThread(); } /****************************************************************************** * * -* Paramètres : item = élément à actualiser. * -* panel = vue du contenu chargé analysé modifiée. * +* Paramètres : item = instance à consulter. * +* old = ancienne vue du contenu chargé analysé. * +* new = nouvelle vue du contenu chargé analysé. * * * -* Description : Réagit à un changement de contenu. * +* Description : Réagit à un changement de vue du contenu en cours d'analyse. * * * * Retour : - * * * @@ -162,79 +162,61 @@ static void _change_editor_item_view_python_wrapper(GEditorItem *item, GLoadedPa * * ******************************************************************************/ -static void _update_editor_item_view_python_wrapper(GEditorItem *item, GLoadedPanel *panel) +static void py_editor_item_change_view_wrapper(GEditorItem *item, GLoadedPanel *old, GLoadedPanel *new) { - PyObject *target; /* Version Python de l'élément */ + PyObject *pyobj; /* Objet Python concerné */ + PyThreadState *tstate; /* Contexte d'environnement */ + PyObject *pyold; /* Conversion ou None */ + PyObject *pynew; /* Conversion ou None */ PyObject *args; /* Arguments pour l'appel */ - PyObject *value; /* Retour obtenu */ - - /** - * Normalement, l'objet Python est enregistré dans la liste de Chrysalide - * des éléments d'éditeur, via py_editor_item_register(), donc son compteur - * de références doit le maintenir en vie. - * - * On peut donc le récupérer directement depuis l'instane GLib, sans passer - * par la procédure de pygobject, qui obligerait à connaître le type précis - * de l'instance GLib manipulée. - */ - target = pygobject_new(G_OBJECT(item)); - - args = PyTuple_New(1); - PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(panel))); + PyObject *pyret; /* Retour de Python */ - value = run_python_method(target, "update_view", args); + pyobj = pygobject_new(G_OBJECT(item)); - Py_XDECREF(value); - Py_DECREF(args); - Py_DECREF(target); + tstate = get_pychrysalide_main_tstate(); -} + if (tstate != NULL) + PyEval_RestoreThread(tstate); + if (has_python_method(pyobj, "_change_view")) + { + if (old != NULL) + pyold = pygobject_new(G_OBJECT(old)); + else + { + pyold = Py_None; + Py_INCREF(pyold); + } -/****************************************************************************** -* * -* Paramètres : self = classe représentant un binaire. * -* args = arguments fournis à l'appel. * -* * -* Description : Réagit à un changement de contenu chargé en cours d'analyse. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + if (new != NULL) + pynew = pygobject_new(G_OBJECT(new)); + else + { + pynew = Py_None; + Py_INCREF(pynew); + } -static PyObject *py_editor_item_change_content(PyObject *self, PyObject *args) -{ - Py_RETURN_NONE; + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, pyold); + PyTuple_SetItem(args, 1, pynew); -} + pyret = run_python_method(pyobj, "_change_view", args); + Py_DECREF(args); + Py_DECREF(pyret); -/****************************************************************************** -* * -* Paramètres : self = classe représentant un binaire. * -* args = arguments fournis à l'appel. * -* * -* Description : Réagit à un changement de vue du contenu en cours d'analyse. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + } -static PyObject *py_editor_item_change_view(PyObject *self, PyObject *args) -{ - Py_RETURN_NONE; + if (tstate != NULL) + PyEval_SaveThread(); } /****************************************************************************** * * -* Paramètres : self = classe représentant un binaire. * -* args = arguments fournis à l'appel. * +* Paramètres : item = instance à consulter. * +* panel = vue du contenu chargé analysé modifiée. * * * * Description : Réagit à une modification de la vue du contenu analysé. * * * @@ -244,44 +226,44 @@ static PyObject *py_editor_item_change_view(PyObject *self, PyObject *args) * * ******************************************************************************/ -static PyObject *py_editor_item_update_view(PyObject *self, PyObject *args) +static void py_editor_item_update_view_wrapper(GEditorItem *item, GLoadedPanel *panel) { - Py_RETURN_NONE; + PyObject *pyobj; /* Objet Python concerné */ + PyThreadState *tstate; /* Contexte d'environnement */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Retour de Python */ -} + pyobj = pygobject_new(G_OBJECT(item)); + tstate = get_pychrysalide_main_tstate(); -/****************************************************************************** -* * -* Paramètres : self = classe représentant un binaire. * -* args = arguments fournis à l'appel. * -* * -* Description : Procède à l'enregistrement d'un élément reactif de l'éditeur.* -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + if (tstate != NULL) + PyEval_RestoreThread(tstate); -static PyObject *py_editor_item_register(PyObject *self, PyObject *args) -{ - //GEditorItem *item; /* Version GLib de l'élément */ + if (has_python_method(pyobj, "_update_view")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(panel))); - //item = G_EDITOR_ITEM(pygobject_get(self)); + pyret = run_python_method(pyobj, "_update_view", args); - //item->update_binary = _change_editor_item_content_python_wrapper; - //item->update_view = _change_editor_item_view_python_wrapper; - //item->update_content = _update_editor_item_view_python_wrapper; + Py_DECREF(args); + Py_DECREF(pyret); - Py_INCREF(self); - //register_editor_item(item); + } - Py_RETURN_NONE; + if (tstate != NULL) + PyEval_SaveThread(); } + +/* ---------------------------------------------------------------------------------- */ +/* FONCTIONNALITES D'UN ELEMENT */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : - * @@ -297,26 +279,6 @@ static PyObject *py_editor_item_register(PyObject *self, PyObject *args) PyTypeObject *get_python_editor_item_type(void) { static PyMethodDef py_editor_item_methods[] = { - { - "change_content", py_editor_item_change_content, - METH_VARARGS, - "change_content($self, /)\n--\n\nCalled by Chrysalide on each content change, if the item is registered." - }, - { - "change_view", py_editor_item_change_view, - METH_VARARGS, - "change_view($self, /)\n--\n\nCalled by Chrysalide on each view change, if the item is registered." - }, - { - "update_view", py_editor_item_update_view, - METH_VARARGS, - "update_view($self, /)\n--\n\nCalled by Chrysalide on each view content change, if the item is registered." - }, - { - "register", py_editor_item_register, - METH_NOARGS, - "register($self, /)\n--\n\nregister($self, /)\n--\n\nRegister the item as editor item." - }, { NULL } }; diff --git a/plugins/pychrysalide/gui/editem.h b/plugins/pychrysalide/gui/editem.h index 9baebee..c272d76 100644 --- a/plugins/pychrysalide/gui/editem.h +++ b/plugins/pychrysalide/gui/editem.h @@ -30,6 +30,20 @@ #include +#include + + + +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Initialise la classe des éléments pour l'interface graphique. */ +void py_editor_item_init_gclass(GEditorItemClass *, gpointer); + + + +/* -------------------------- FONCTIONNALITES D'UN ELEMENT -------------------------- */ + /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_editor_item_type(void); diff --git a/plugins/pychrysalide/gui/panels/panel.c b/plugins/pychrysalide/gui/panels/panel.c index 37b682f..1df0670 100644 --- a/plugins/pychrysalide/gui/panels/panel.c +++ b/plugins/pychrysalide/gui/panels/panel.c @@ -28,21 +28,37 @@ #include +#include #include #include -#include +#include #include "../editem.h" #include "../../access.h" +#include "../../dt.h" #include "../../helpers.h" #include "../../gtkext/dockable.h" +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Accompagne la création d'une instance dérivée en Python. */ +static PyObject *py_panel_item_new(PyTypeObject *, PyObject *, PyObject *); + +/* Initialise la classe des panneaux pour l'interface graphique. */ +static void py_panel_item_init_gclass(GPanelItemClass *, gpointer); + /* Initialise une instance sur la base du dérivé de GObject. */ static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds); + + +/* -------------------------- FONCTIONNALITES D'UN PANNEAU -------------------------- */ + + /* Place un panneau dans l'ensemble affiché. */ static PyObject *py_panel_item_dock(PyObject *, PyObject *); @@ -51,6 +67,102 @@ static bool py_panel_item_define_constants(PyTypeObject *); +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * +* * +* Description : Accompagne la création d'une instance dérivée en Python. * +* * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Objet à retourner */ + bool abstract; /* Validation du type parent */ + GType gtype; /* Nouveau type de processeur */ + PyObject *sys_mod_dict; /* Dictionnaire des modules */ + PyObject *modname; /* Nom du module du type */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire dudit module */ + + /* Validations diverses */ + + abstract = (type == get_python_panel_item_type()); + + if (abstract) + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); + goto exit; + } + + /* Mise en place d'un type dédié */ + + gtype = built_dynamic_type(G_TYPE_PANEL_ITEM, type->tp_name, + (GClassInitFunc)py_panel_item_init_gclass); + + /* Enregistrement du nouveau GType dans Python */ + + sys_mod_dict = PyImport_GetModuleDict(); + + modname = PyDict_GetItemString(type->tp_dict, "__module__"); + + module = PyObject_GetItem(sys_mod_dict, modname); + + dict = PyModule_GetDict(module); + + if (!_register_class_for_pygobject(dict, gtype, type, + &PyGObject_Type, get_python_panel_item_type(), NULL)) + { + result = NULL; + goto exit; + } + + Py_DECREF(module); + Py_DECREF(modname); + + /* On créé, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe des panneaux pour l'interface graphique.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_panel_item_init_gclass(GPanelItemClass *class, gpointer unused) +{ + py_editor_item_init_gclass(G_EDITOR_ITEM_CLASS(class), NULL); + +} + + /****************************************************************************** * * * Paramètres : self = objet à initialiser (théoriquement). * @@ -74,16 +186,41 @@ static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds) int startup; /* Recommandation au démarrage */ const char *path; /* Placement à l'affichage */ int ret; /* Bilan de lecture des args. */ - GPanelItem *item; /* Elément de l'éditeur */ + PyObject *new_kwds; /* Nouveau dictionnaire épuré */ + GPanelItem *panel; /* Panneau à manipuler */ + GEditorItem *item; /* Version basique d'instance */ + + static char *kwlist[] = { "name", "widget", "personality", "lname", "dock", "path", NULL }; + + /* Récupération des paramètres */ - ret = PyArg_ParseTuple(args, "kssOps", &personality, &name, &lname, &widget, &startup, &path); + ret = PyArg_ParseTupleAndKeywords(args, kwds, "sOksps", kwlist, + &name, &widget, &personality, &lname, &startup, &path); if (!ret) return -1; - item = g_panel_item_new(personality, name, lname, - GTK_WIDGET(pygobject_get(widget)), startup, path); + /* Initialisation d'un objet GLib */ - /* FIXME ? Est-ce à l'utilisateur de s'enregistrer ? */ - register_panel_item(item, get_main_configuration()); + new_kwds = PyDict_New(); + + ret = PyGObject_Type.tp_init(self, args, new_kwds); + + Py_DECREF(new_kwds); + + if (ret == -1) return -1; + + /* Eléments de base */ + + panel = G_PANEL_ITEM(pygobject_get(self)); + + item = G_EDITOR_ITEM(panel); + + item->name = strdup(name);; + item->widget = GTK_WIDGET(pygobject_get(widget)); + + panel->personality = personality; + panel->lname = strdup(lname); + panel->dock_at_startup = startup; + panel->path = strdup(path); /** * Si Python ne voit plus la variable représentant le panneau utilisée, @@ -92,18 +229,17 @@ static int py_panel_item_init(PyObject *self, PyObject *args, PyObject *kwds) * On sera donc en situation de Use-After-Free, dont les conséquences * arrivent très vite. */ - g_object_ref(GTK_WIDGET(pygobject_get(widget))); - Py_INCREF(self); + g_object_ref(G_OBJECT(item->widget)); - /* Enregistrement auprès de PyGObject */ + return 0; - ((PyGObject *)self)->obj = G_OBJECT(item); +} - pygobject_register_wrapper(self); - return 0; -} +/* ---------------------------------------------------------------------------------- */ +/* FONCTIONNALITES D'UN PANNEAU */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -172,7 +308,9 @@ PyTypeObject *get_python_panel_item_type(void) .tp_methods = py_panel_item_methods, .tp_getset = py_panel_item_getseters, - .tp_init = (initproc)py_panel_item_init + + .tp_init = py_panel_item_init, + .tp_new = py_panel_item_new, }; @@ -256,3 +394,48 @@ bool ensure_python_panel_item_is_registered(void) return true; } + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en panneau pour GUI. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_panel_item(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_panel_item_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to executable format"); + break; + + case 1: + *((GPanelItem **)dst) = G_PANEL_ITEM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/gui/panels/panel.h b/plugins/pychrysalide/gui/panels/panel.h index 7fb473b..907c650 100644 --- a/plugins/pychrysalide/gui/panels/panel.h +++ b/plugins/pychrysalide/gui/panels/panel.h @@ -37,6 +37,9 @@ PyTypeObject *get_python_panel_item_type(void); /* Prend en charge l'objet 'pychrysalide.gui.panels.PanelItem'. */ bool ensure_python_panel_item_is_registered(void); +/* Tente de convertir en panneau pour GUI. */ +int convert_to_panel_item(PyObject *, void *); + #endif /* _PLUGINS_PYCHRYSALIDE_GUI_PANELS_PANEL_H */ diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index ce3d0f4..9237aba 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -31,6 +31,9 @@ #include +#include + + #include "access.h" #include "constval.h" @@ -692,7 +695,7 @@ bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *ty * Création d'un dictionnaire complet pour la simulation d'un "import *". */ - if (result) + if (result && startswith(type->tp_name, "pychrysalide.")) result = include_python_type_into_features(dict, type); return result; diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c index 6b6060d..44f518e 100644 --- a/plugins/pychrysalide/plugin.c +++ b/plugins/pychrysalide/plugin.c @@ -586,8 +586,14 @@ static bool g_python_plugin_read_interface(GPythonPlugin *plugin) static bool g_python_plugin_do_init(GPythonPlugin *plugin) { bool result; /* Bilan à retourner */ + PyThreadState *tstate; /* Contexte d'environnement */ PyObject *value; /* Valeur obtenue */ + tstate = PyThreadState_Get(); + + if (tstate != NULL) + PyEval_RestoreThread(tstate); + if (!has_python_method(plugin->instance, "init")) result = true; @@ -601,6 +607,9 @@ static bool g_python_plugin_do_init(GPythonPlugin *plugin) } + if (tstate != NULL) + PyEval_SaveThread(); + return result; } -- cgit v0.11.2-87-g4458