diff options
Diffstat (limited to 'plugins/pychrysalide/gui/item.c')
| -rw-r--r-- | plugins/pychrysalide/gui/item.c | 723 | 
1 files changed, 723 insertions, 0 deletions
| diff --git a/plugins/pychrysalide/gui/item.c b/plugins/pychrysalide/gui/item.c new file mode 100644 index 0000000..45190e4 --- /dev/null +++ b/plugins/pychrysalide/gui/item.c @@ -0,0 +1,723 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.c - prototypes pour l'équivalent Python du fichier "gui/item.c" + * + * Copyright (C) 2018-2020 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 "item.h" + + +#include <malloc.h> +#include <pygobject.h> + + +#include <gui/item-int.h> + + +#include "../access.h" +#include "../helpers.h" +#include "../pychrysa.h" +#include "../analysis/binary.h" +#include "../gtkext/displaypanel.h" + + + +#define EDITOR_ITEM_DOC                                                         \ +    "EditorItem is an abstract class for all items belonging to main interface" \ +    " of Chrysalide: panels, menus, aso.\n"                                     \ +    "\n"                                                                        \ +    "These objets do not offer functions as the pychrysalide.gui.core module"   \ +    " is aimed to deal with all editor items at once. Thus such functions are"  \ +    " located in this module."                                                  \ +    "\n"                                                                        \ +    "Several items have to be defined as class attributes in the final"         \ +    " class:\n"                                                                 \ +    "* *_key*: a string providing a small name used to identify the item;\n"    \ +    "* *_widget*: a Gtk.Widget instance for the content to display.\n"          \ +    "\n"                                                                        \ +    "The following special method can be overridden:\n"                         \ +    "* _change_content(self, old, new): get notified about a"                   \ +    " pychrysalide.analysis.LoadedContent change.\n"                            \ +    "* _change_view(self, old, new): get notified about a"                      \ +    " pychrysalide.glibext.LoadedPanel change.\n"                               \ +    "* _update_view(self, panel): get notified about a"                         \ +    " pychrysalide.glibext.LoadedPanel change.\n"                               \ +    "* _track_cursor(self, panel, cursor): get notified when the position of a" \ +    " pychrysalide.glibext.LineCursor evolves in a"                             \ +    " pychrysalide.glibext.LoadedPanel.\n"                                      \ +    "* _focus_cursor(self, content, cursor): place the current caret to a given"\ +    " pychrysalide.glibext.LineCursor inside a rendered"                        \ +    " pychrysalide.analysis.LoadedContent." + + + +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Fournit le nom interne attribué à l'élément réactif. */ +static char *py_editor_item_get_key_wrapper(const GEditorItem *); + +/* Fournit le composant GTK associé à l'élément réactif. */ +static GtkWidget *py_editor_item_get_widget_wrapper(const GEditorItem *); + +/* 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 vue du contenu en cours d'analyse. */ +static void py_editor_item_change_view_wrapper(GEditorItem *, GLoadedPanel *, GLoadedPanel *); + +/* Réagit à une modification de la vue du contenu analysé. */ +static void py_editor_item_update_view_wrapper(GEditorItem *, GLoadedPanel *); + +/* Réagit à une modification de la vue du contenu analysé. */ +static void py_editor_item_track_cursor_wrapper(GEditorItem *, GLoadedPanel *, const GLineCursor *); + +/* Réagit à une modification de la vue du contenu analysé. */ +static void py_editor_item_focus_cursor_wrapper(GEditorItem *, GLoadedContent *, const GLineCursor *); + + + +/* -------------------------- FONCTIONNALITES D'UN ELEMENT -------------------------- */ + + +/* Fournit le nom interne attribué à l'élément réactif. */ +static PyObject *py_editor_item_get_key(PyObject *, void *); + +/* Fournit le composant GTK associé à l'élément réactif. */ +static PyObject *py_editor_item_get_widget(PyObject *, void *); + + + +/* ---------------------------------------------------------------------------------- */ +/*                          GLUE POUR CREATION DEPUIS PYTHON                          */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : class  = classe à initialiser.                               * +*                unused = données non utilisées ici.                          * +*                                                                             * +*  Description : Initialise la classe des éléménts pour l'interface graphique.* +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void py_editor_item_init_gclass(GEditorItemClass *class, gpointer unused) +{ +    class->get_key = py_editor_item_get_key_wrapper; +    class->get_widget = py_editor_item_get_widget_wrapper; + +    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; + +    class->track_cursor = py_editor_item_track_cursor_wrapper; +    class->focus_cursor = py_editor_item_focus_cursor_wrapper; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : item = instance à consulter.                                 * +*                                                                             * +*  Description : Fournit le nom interne attribué à l'élément réactif.         * +*                                                                             * +*  Retour      : Désignation (courte) de l'élément de l'éditeur.              * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static char *py_editor_item_get_key_wrapper(const GEditorItem *item) +{ +    char *result;                           /* Désignation à retourner     */ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *pykey;                        /* Clef en objet Python        */ +    int ret;                                /* Bilan d'une conversion      */ + +#define EDITOR_ITEM_KEY_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF    \ +(                                                                   \ +    _key,                                                          \ +    "Provide the internal name to use for the editor item.\n"       \ +    "\n"                                                            \ +    "The result has to be a string."                                \ +) + +    result = NULL; + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(item)); + +    if (PyObject_HasAttrString(pyobj, "_key")) +    { +        pykey = PyObject_GetAttrString(pyobj, "_key"); + +        if (pykey != NULL) +        { +            ret = PyUnicode_Check(pykey); + +            if (ret) +                result = strdup(PyUnicode_AsUTF8(pykey)); + +            Py_DECREF(pykey); + +        } + +    } + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : item = instance à consulter.                                 * +*                                                                             * +*  Description : Fournit le composant GTK associé à l'élément réactif.        * +*                                                                             * +*  Retour      : Instance de composant graphique chargé.                      * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static GtkWidget *py_editor_item_get_widget_wrapper(const GEditorItem *item) +{ +    GtkWidget *result;                      /* Composant GTK à renvoyer    */ +    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */ +    PyObject *pyobj;                        /* Objet Python concerné       */ +    PyObject *pywidget;                     /* Composant en objet Python   */ +    PyObject *gtk_mod;                      /* Module Python Gtk           */ +    PyObject *type;                         /* Module "GtkWidget"          */ +    int ret;                                /* Bilan d'une conversion      */ + +#define EDITOR_ITEM_WIDGET_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF     \ +(                                                                       \ +    _widget,                                                            \ +    "Provide the Gtk widget base involved in the editor item.\n"        \ +    "\n"                                                                \ +    "The result has to be a Gtk.Widget instance."                       \ +) + +    result = NULL; + +    gstate = PyGILState_Ensure(); + +    pyobj = pygobject_new(G_OBJECT(item)); + +    if (PyObject_HasAttrString(pyobj, "_widget")) +    { +        pywidget = PyObject_GetAttrString(pyobj, "_widget"); + +        if (pywidget != NULL) +        { +            gtk_mod = PyImport_ImportModule("gi.repository.Gtk"); + +            if (gtk_mod == NULL) +            { +                PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module"); +                goto exit; +            } + +            type = PyObject_GetAttrString(gtk_mod, "Widget"); + +            Py_DECREF(gtk_mod); + +            ret = PyObject_TypeCheck(pywidget, (PyTypeObject *)type); + +            Py_DECREF(type); + +            if (ret) +                result = GTK_WIDGET(pygobject_get(pywidget)); + +            Py_DECREF(pywidget); + +        } + +    } + + exit: + +    Py_DECREF(pyobj); + +    PyGILState_Release(gstate); + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : item = instance à consulter.                                 * +*                old  = ancien contenu chargé analysé.                        * +*                new  = nouveau contenu chargé à analyser.                    * +*                                                                             * +*  Description : Réagit à un changement de contenu chargé en cours d'analyse. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void py_editor_item_change_content_wrapper(GEditorItem *item, GLoadedContent *old, GLoadedContent *new) +{ +    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 *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); +        } + +        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); + +        pyret = run_python_method(pyobj, "_change_content", args); + +        Py_DECREF(args); +        Py_DECREF(pyret); + +    } + +    if (tstate != NULL) +        PyEval_SaveThread(); + +} + + +/****************************************************************************** +*                                                                             * +*  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 vue du contenu en cours d'analyse. * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void py_editor_item_change_view_wrapper(GEditorItem *item, GLoadedPanel *old, GLoadedPanel *new) +{ +    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 *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_view")) +    { +        if (old != NULL) +            pyold = pygobject_new(G_OBJECT(old)); +        else +        { +            pyold = Py_None; +            Py_INCREF(pyold); +        } + +        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); + +        pyret = run_python_method(pyobj, "_change_view", args); + +        Py_DECREF(args); +        Py_DECREF(pyret); + +    } + +    if (tstate != NULL) +        PyEval_SaveThread(); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : item  = instance à consulter.                                * +*                panel = vue du contenu chargé analysé modifiée.              * +*                                                                             * +*  Description : Réagit à une modification de la vue du contenu analysé.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void py_editor_item_update_view_wrapper(GEditorItem *item, GLoadedPanel *panel) +{ +    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(); + +    if (tstate != NULL) +        PyEval_RestoreThread(tstate); + +    if (has_python_method(pyobj, "_update_view")) +    { +        args = PyTuple_New(1); +        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(panel))); + +        pyret = run_python_method(pyobj, "_update_view", args); + +        Py_DECREF(args); +        Py_DECREF(pyret); + +    } + +    if (tstate != NULL) +        PyEval_SaveThread(); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : item   = instance à consulter.                               * +*                panel  = composant d'affichage parcouru.                     * +*                cursor = nouvel emplacement du curseur courant.              * +*                                                                             * +*  Description : Réagit à une modification de la vue du contenu analysé.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void py_editor_item_track_cursor_wrapper(GEditorItem *item, GLoadedPanel *panel, const GLineCursor *cursor) +{ +    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(); + +    if (tstate != NULL) +        PyEval_RestoreThread(tstate); + +    if (has_python_method(pyobj, "_track_cursor")) +    { +        args = PyTuple_New(2); +        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(panel))); +        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(cursor))); + +        pyret = run_python_method(pyobj, "_track_cursor", args); + +        Py_DECREF(args); +        Py_DECREF(pyret); + +    } + +    if (tstate != NULL) +        PyEval_SaveThread(); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : item    = instance à consulter.                              * +*                content = contenu contenant le curseur à représenter.        * +*                cursor  = nouvel emplacement du curseur courant.             * +*                                                                             * +*  Description : Réagit à une modification de la vue du contenu analysé.      * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static void py_editor_item_focus_cursor_wrapper(GEditorItem *item, GLoadedContent *content, const GLineCursor *cursor) +{ +    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(); + +    if (tstate != NULL) +        PyEval_RestoreThread(tstate); + +    if (has_python_method(pyobj, "_focus_cursor")) +    { +        args = PyTuple_New(2); +        PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(content))); +        PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(cursor))); + +        pyret = run_python_method(pyobj, "_focus_cursor", args); + +        Py_DECREF(args); +        Py_DECREF(pyret); + +    } + +    if (tstate != NULL) +        PyEval_SaveThread(); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/*                            FONCTIONNALITES D'UN ELEMENT                            */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self    = objet Python concerné par l'appel.                 * +*                closure = non utilisé ici.                                   * +*                                                                             * +*  Description : Fournit le nom interne attribué à l'élément réactif.         * +*                                                                             * +*  Retour      : Désignation (courte) de l'élément de l'éditeur.              * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_editor_item_get_key(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Valeur à retourner          */ +    GEditorItem *item;                      /* Elément à consulter         */ +    char *key;                              /* Désignation humaine         */ + +#define EDITOR_ITEM_KEY_ATTRIB PYTHON_GET_DEF_FULL      \ +(                                                       \ +    key, py_editor_item,                                \ +    "Internal name given to the editor item."              \ +) + +    item = G_EDITOR_ITEM(pygobject_get(self)); +    key = g_editor_item_get_key(item); + +    if (key != NULL) +    { +        result = PyUnicode_FromString(key); +        free(key); +    } +    else +    { +        result = Py_None; +        Py_INCREF(result); +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : self    = objet Python concerné par l'appel.                 * +*                closure = non utilisé ici.                                   * +*                                                                             * +*  Description : Fournit le composant GTK associé à l'élément réactif.        * +*                                                                             * +*  Retour      : Instance de composant graphique chargé.                      * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static PyObject *py_editor_item_get_widget(PyObject *self, void *closure) +{ +    PyObject *result;                       /* Valeur à retourner          */ +    GEditorItem *item;                      /* Elément à consulter         */ +    GtkWidget *widget;                      /* Composant GTK employé       */ + +#define EDITOR_ITEM_WIDGET_ATTRIB PYTHON_GET_DEF_FULL   \ +(                                                       \ +    widget, py_editor_item,                             \ +    "GTK widget base involed in the editor item."       \ +) + +    item = G_EDITOR_ITEM(pygobject_get(self)); +    widget = g_editor_item_get_widget(item); + +    if (widget != NULL) +    { +        result = pygobject_new(G_OBJECT(widget)); +        g_object_unref(G_OBJECT(widget)); +    } + +    else +    { +        result = Py_None; +        Py_INCREF(result); +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : -                                                            * +*                                                                             * +*  Description : Fournit un accès à une définition de type à diffuser.        * +*                                                                             * +*  Retour      : Définition d'objet pour Python.                              * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +PyTypeObject *get_python_editor_item_type(void) +{ +    static PyMethodDef py_editor_item_methods[] = { +        { NULL } +    }; + +    static PyGetSetDef py_editor_item_getseters[] = { +        EDITOR_ITEM_KEY_ATTRIB_WRAPPER, +        EDITOR_ITEM_WIDGET_ATTRIB_WRAPPER, +        EDITOR_ITEM_KEY_ATTRIB, +        EDITOR_ITEM_WIDGET_ATTRIB, +        { NULL } +    }; + +    static PyTypeObject py_editor_item_type = { + +        PyVarObject_HEAD_INIT(NULL, 0) + +        .tp_name        = "pychrysalide.gui.EditorItem", + +        .tp_flags       = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + +        .tp_doc         = EDITOR_ITEM_DOC, + +        .tp_methods     = py_editor_item_methods, +        .tp_getset      = py_editor_item_getseters, + +    }; + +    return &py_editor_item_type; + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : module = module dont la définition est à compléter.          * +*                                                                             * +*  Description : Prend en charge l'objet 'pychrysalide.gui.EditorItem'.       * +*                                                                             * +*  Retour      : Bilan de l'opération.                                        * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +bool ensure_python_editor_item_is_registered(void) +{ +    PyTypeObject *type;                     /* Type Python 'EditorItem'  */ +    PyObject *module;                       /* Module à recompléter        */ +    PyObject *dict;                         /* Dictionnaire du module      */ + +    type = get_python_editor_item_type(); + +    if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) +    { +        module = get_access_to_python_module("pychrysalide.gui"); + +        dict = PyModule_GetDict(module); + +        if (!register_class_for_pygobject(dict, G_TYPE_EDITOR_ITEM, type, &PyGObject_Type)) +            return false; + +    } + +    return true; + +} | 
