From 97fa09113c7988e4b4639190ba9bc51f9ced4d33 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
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 <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;
 
 }
-- 
cgit v0.11.2-87-g4458