diff options
| -rw-r--r-- | plugins/pychrysalide/gui/core/Makefile.am | 3 | ||||
| -rw-r--r-- | plugins/pychrysalide/gui/core/module.c | 2 | ||||
| -rw-r--r-- | plugins/pychrysalide/gui/core/panels.c | 122 | ||||
| -rw-r--r-- | plugins/pychrysalide/gui/core/panels.h | 39 | ||||
| -rw-r--r-- | plugins/pychrysalide/gui/editem.c | 296 | ||||
| -rw-r--r-- | plugins/pychrysalide/gui/editem.h | 14 | ||||
| -rw-r--r-- | plugins/pychrysalide/gui/panels/panel.c | 213 | ||||
| -rw-r--r-- | plugins/pychrysalide/gui/panels/panel.h | 3 | ||||
| -rw-r--r-- | plugins/pychrysalide/helpers.c | 5 | ||||
| -rw-r--r-- | plugins/pychrysalide/plugin.c | 9 | 
10 files changed, 522 insertions, 184 deletions
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 <pygobject.h> + + +#include <core/params.h> +#include <gui/core/panels.h> + + +#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 <Python.h> +#include <stdbool.h> + + + +/* 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 <stdbool.h> +#include <gui/editem.h> + + + +/* ------------------------ 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 <pygobject.h> +#include <i18n.h>  #include <core/params.h>  #include <gui/core/panels.h> -#include <gui/panels/panel.h> +#include <gui/panels/panel-int.h>  #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 <string.h> +#include <common/extstr.h> + +  #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;  }  | 
