From d7ede72c4351b11c064ccfee7036c7d8461ad2e8 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 21 May 2023 00:22:47 +0200
Subject: Simplify the Python plugins interface by deleting one of the relative
 GLib type.

---
 plugins/pychrysalide/core.c           |   6 +-
 plugins/pychrysalide/helpers.h        |  29 +-
 plugins/pychrysalide/plugins/plugin.c | 592 +++++++++++++---------------------
 plugins/pychrysalide/plugins/plugin.h |  32 +-
 4 files changed, 250 insertions(+), 409 deletions(-)

diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c
index d4f2292..c3a6cf2 100644
--- a/plugins/pychrysalide/core.c
+++ b/plugins/pychrysalide/core.c
@@ -312,7 +312,7 @@ static bool install_metaclass_for_python_gobjects(void)
 
     /**
      * Les extensions Python sont chargées à partir de la fonction load_python_plugins(),
-     * qui fait appel à g_python_plugin_new(). Une instance y est construite via un
+     * qui fait appel à create_python_plugin(). Une instance y est construite via un
      * appel à PyObject_CallFunction() avec la classe spécifiée par l'alias AutoLoad
      * dans le fichier __init__.py présent dans chaque module d'extension.
      *
@@ -862,7 +862,7 @@ static void load_python_plugins(GPluginModule *plugin)
             filename = stradd(filename, G_DIR_SEPARATOR_S);
             filename = stradd(filename, entry->d_name);
 
-            pyplugin = g_python_plugin_new(modname, filename);
+            pyplugin = create_python_plugin(modname, filename);
 
             if (pyplugin == NULL)
             {
@@ -1227,7 +1227,7 @@ void log_pychrysalide_exception(const char *prefix, ...)
          *
          * C'est par exemple le cas quand un greffon Python ne peut se lancer
          * correctement ; l'exception est alors levée à partir de la fonction
-         * g_python_plugin_new() et le plantage intervient en sortie d'exécution,
+         * create_python_plugin() et le plantage intervient en sortie d'exécution,
          * au moment de la libération de l'extension Python :
          *
          *    ==14939== Jump to the invalid address stated on the next line
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index 348c110..c9cc098 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -87,26 +87,21 @@ bool register_python_module_object(PyObject *, PyTypeObject *);
         #name "(" args ")\n--\n\n" doc                  \
     }
 
-#define PYTHON_VOID_WRAPPER_DEF(name, args, flags, doc) \
-    {                                                   \
-        #name, (PyCFunction)py_return_none,             \
-        flags,                                          \
-        #name "(" args ")\n--\n\n" doc                  \
+#define PYTHON_WRAPPER_DEF_WITH(name, args, flags, defcb, doc)  \
+    {                                                           \
+        #name, (PyCFunction)defcb,                              \
+        flags,                                                  \
+        #name "(" args ")\n--\n\n" doc                          \
     }
 
-#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc)\
-    {                                                   \
-        #name, (PyCFunction)py_return_false,            \
-        flags,                                          \
-        #name "(" args ")\n--\n\n" doc                  \
-    }
+#define PYTHON_VOID_WRAPPER_DEF(name, args, flags, doc) \
+    PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_none, doc)
 
-#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc)\
-    {                                                   \
-        #name, (PyCFunction)py_return_true,             \
-        flags,                                          \
-        #name "(" args ")\n--\n\n" doc                  \
-    }
+#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc) \
+    PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_false, doc)
+
+#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc) \
+    PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_true, doc)
 
 /**
  * Il ne semble pas exister de moyen de déterminer
diff --git a/plugins/pychrysalide/plugins/plugin.c b/plugins/pychrysalide/plugins/plugin.c
index a87d0a6..06bbd83 100644
--- a/plugins/pychrysalide/plugins/plugin.c
+++ b/plugins/pychrysalide/plugins/plugin.c
@@ -51,21 +51,29 @@
 /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */
 
 
-/* Accompagne la création d'une instance dérivée en Python. */
-static PyObject *py_plugin_module_new(PyTypeObject *, PyObject *, PyObject *);
-
 /* Initialise la classe des greffons d'extension. */
 static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer);
 
+CREATE_DYN_ABSTRACT_CONSTRUCTOR(plugin_module, G_TYPE_PLUGIN_MODULE, py_plugin_module_init_gclass);
+
 /* Initialise une instance sur la base du dérivé de GObject. */
 static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds);
 
 /* Encadre une étape de la vie d'un greffon. */
 static bool py_plugin_module_manage_wrapper(GPluginModule *);
 
+/* Assiste la désactivation d'un greffon. */
+static bool py_plugin_module_exit(GPluginModule *);
+
 /* Accompagne la fin du chargement des modules natifs. */
 static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *, PluginAction);
 
+/* Fournit le nom brut associé au greffon par défaut. */
+static PyObject *py_plugin_module_get_modname_by_default(PyObject *, PyObject *);
+
+/* Fournit le nom brut associé au greffon. */
+static char *py_plugin_module_get_modname_wrapper(const GPluginModule *);
+
 #ifdef HAVE_GTK_SUPPORT
 
 /* Complète une liste de resources pour thème. */
@@ -102,42 +110,6 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *
 
 
 
-/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */
-
-
-/* Ligne de représentation de code binaire (instance) */
-struct _GPythonPlugin
-{
-    GPluginModule parent;                   /* Instance parente            */
-
-};
-
-
-/* Ligne de représentation de code binaire (classe) */
-struct _GPythonPluginClass
-{
-    GPluginModuleClass parent;              /* Classe parente              */
-
-};
-
-
-/* Initialise la classe des greffons Python. */
-static void g_python_plugin_class_init(GPythonPluginClass *);
-
-/* Initialise l'instance d'un greffon Python. */
-static void g_python_plugin_init(GPythonPlugin *);
-
-/* Supprime toutes les références externes. */
-static void g_python_plugin_dispose(GPythonPlugin *);
-
-/* Description : Procède à la libération totale de la mémoire. */
-static void g_python_plugin_finalize(GPythonPlugin *);
-
-/* Fournit le nom brut associé au greffon. */
-static char *g_python_plugin_get_modname(const GPythonPlugin *);
-
-
-
 /* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
 
 
@@ -165,69 +137,6 @@ static PyObject *py_plugin_module_get_interface(PyObject *, void *);
 
 /******************************************************************************
 *                                                                             *
-*  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_plugin_module_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    PyObject *result;                       /* Objet à retourner           */
-    PyTypeObject *base;                     /* Type de base à dériver      */
-    bool first_time;                        /* Evite les multiples passages*/
-    GType gtype;                            /* Nouveau type de processeur  */
-    bool status;                            /* Bilan d'un enregistrement   */
-
-    /* Validations diverses */
-
-    base = get_python_plugin_module_type();
-
-    if (type == base)
-    {
-        result = NULL;
-        PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name);
-        goto exit;
-    }
-
-    /* Mise en place d'un type dédié */
-
-    first_time = (g_type_from_name(type->tp_name) == 0);
-
-    gtype = build_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name,
-                               (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL);
-
-    if (first_time)
-    {
-        status = register_class_for_dynamic_pygobject(gtype, type, base);
-
-        if (!status)
-        {
-            result = NULL;
-            goto exit;
-        }
-
-    }
-
-    /* On crée, 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.                          *
 *                                                                             *
@@ -243,10 +152,12 @@ static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unu
 {
     class->init = NULL;
     class->manage = py_plugin_module_manage_wrapper;
-    class->exit = NULL;
+    class->exit = py_plugin_module_exit;
 
     class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper;
 
+    class->get_modname = py_plugin_module_get_modname_wrapper;
+
 #ifdef HAVE_GTK_SUPPORT
     class->include_theme = py_plugin_module_include_theme_wrapper;
     class->notify_panel = py_plugin_module_notify_panel_creation_wrapper;
@@ -504,6 +415,51 @@ static bool py_plugin_module_manage_wrapper(GPluginModule *plugin)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : plugin = greffon à manipuler.                                *
+*                                                                             *
+*  Description : Assiste la désactivation d'un greffon.                       *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool py_plugin_module_exit(GPluginModule *plugin)
+{
+    bool result;                            /* Bilan à faire remonter      */
+    plugin_interface *final;                /* Interface finale conservée  */
+
+    result = true;
+
+    final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
+
+    if (final != NULL)
+    {
+        if (final->name != NULL) free(final->name);
+        if (final->desc != NULL) free(final->desc);
+        if (final->version != NULL) free(final->version);
+        if (final->url != NULL) free(final->url);
+
+        assert(final->required_count == 1);
+
+        if (final->required != NULL)
+            free(final->required);
+
+        if (final->actions != NULL)
+            free(final->actions);
+
+        free(final);
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à manipuler.                                *
 *                action = type d'action attendue.                             *
 *                                                                             *
 *  Description : Accompagne la fin du chargement des modules natifs.          *
@@ -559,6 +515,98 @@ static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet Python concerné par l'appel.                    *
+*                args = arguments fournis à l'appel.                          *
+*                                                                             *
+*  Description : Fournit le nom brut associé au greffon par défaut.           *
+*                                                                             *
+*  Retour      : Désignation brute du greffon.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_plugin_module_get_modname_by_default(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Bilan à retourner           */
+    GPluginModule *plugin;                  /* Version native du greffon   */
+    char *path;                             /* Chemin à traiter            */
+
+    plugin = G_PLUGIN_MODULE(pygobject_get(self));
+
+    path = strdup(g_plugin_module_get_filename(plugin));
+
+    result = PyUnicode_FromString(basename(path));
+
+    free(path);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plugin = greffon à valider.                                  *
+*                                                                             *
+*  Description : Fournit le nom brut associé au greffon.                      *
+*                                                                             *
+*  Retour      : Désignation brute du greffon.                                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *py_plugin_module_get_modname_wrapper(const GPluginModule *plugin)
+{
+    char *result;                           /* Désignation brute à renvoyer*/
+    PyGILState_STATE gstate;                /* Sauvegarde d'environnement  */
+    PyObject *pyobj;                        /* Objet Python concerné       */
+    PyObject *pyret;                        /* Bilan d'exécution           */
+
+#define PLUGIN_MODULE_GET_MODNAME_WRAPPER PYTHON_WRAPPER_DEF_WITH       \
+(                                                                       \
+    _get_modname, "$self, /",                                           \
+    METH_VARARGS, py_plugin_module_get_modname_by_default,              \
+    "(Abstract) method providing the raw module name of the plugin.\n"  \
+    " loaded.\n"                                                        \
+    "\n"                                                                \
+    "The result should be a short string value.\n"                      \
+    "\n"                                                                \
+    "A default implementation builds the module name from the Python"   \
+    " script filename."                                                 \
+)
+
+    gstate = PyGILState_Ensure();
+
+    pyobj = pygobject_new(G_OBJECT(plugin));
+
+    if (has_python_method(pyobj, "_get_modname"))
+    {
+        pyret = run_python_method(pyobj, "_get_modname", NULL);
+
+        if (!PyUnicode_Check(pyret))
+            g_plugin_module_log_variadic_message(plugin, LMT_ERROR,
+                                                 _("The returned raw name must be a string"));
+
+        else
+            result = strdup(PyUnicode_DATA(pyret));
+
+        Py_XDECREF(pyret);
+
+    }
+
+    Py_DECREF(pyobj);
+
+    PyGILState_Release(gstate);
+
+    return result;
+
+}
+
+
 #ifdef HAVE_GTK_SUPPORT
 
 
@@ -1312,262 +1360,6 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule *
 
 
 /* ---------------------------------------------------------------------------------- */
-/*                       INTERFACE INTERNE POUR GREFFONS PYTHON                       */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini par la GLib pour le greffon Python. */
-G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE);
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : klass = classe à initialiser.                                *
-*                                                                             *
-*  Description : Initialise la classe des greffons Python.                    *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_python_plugin_class_init(GPythonPluginClass *klass)
-{
-    GObjectClass *object;                   /* Autre version de la classe  */
-    GPluginModuleClass *plugin;             /* Version parente de la classe*/
-
-    object = G_OBJECT_CLASS(klass);
-
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize;
-
-    plugin = G_PLUGIN_MODULE_CLASS(klass);
-
-    plugin->get_modname = (pg_get_modname_fc)g_python_plugin_get_modname;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = instance à initialiser.                             *
-*                                                                             *
-*  Description : Initialise l'instance d'un greffon Python.                   *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_python_plugin_init(GPythonPlugin *plugin)
-{
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
-*                                                                             *
-*  Description : Supprime toutes les références externes.                     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_python_plugin_dispose(GPythonPlugin *plugin)
-{
-#if 0
-    PyThreadState *tstate;                  /* Contexte d'environnement    */
-
-    /**
-     * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock
-     *
-     * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur,
-     * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante :
-     *
-     *    Fatal Python error: drop_gil: GIL is not locked
-     *
-     * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée
-     * comme dépréciée depuis Python 3.2.
-     *
-     * Donc on choisit les alternatives officielles.
-     *
-     * Cependant, PyThreadState_Get() renvoit l'erreur suivante :
-     *
-     *    Fatal Python error: PyThreadState_Get: no current thread
-     *
-     * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur
-     * est intégré dans l'éditeur.
-     */
-
-    tstate = get_pychrysalide_main_tstate();
-
-    if (tstate != NULL)
-        PyEval_RestoreThread(tstate);
-
-    if (tstate != NULL)
-        PyEval_SaveThread();
-#endif
-
-    G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
-*                                                                             *
-*  Description : Procède à la libération totale de la mémoire.                *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_python_plugin_finalize(GPythonPlugin *plugin)
-{
-    plugin_interface *final;                /* Interface finale conservée  */
-
-    final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface;
-
-    if (final != NULL)
-    {
-        if (final->name != NULL) free(final->name);
-        if (final->desc != NULL) free(final->desc);
-        if (final->version != NULL) free(final->version);
-        if (final->url != NULL) free(final->url);
-
-        assert(final->required_count == 1);
-
-        if (final->required != NULL)
-            free(final->required);
-
-        if (final->actions != NULL)
-            free(final->actions);
-
-        free(final);
-
-    }
-
-    G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : plugin = greffon à valider.                                  *
-*                                                                             *
-*  Description : Fournit le nom brut associé au greffon.                      *
-*                                                                             *
-*  Retour      : Désignation brute du greffon.                                *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static char *g_python_plugin_get_modname(const GPythonPlugin *plugin)
-{
-    char *result;                           /* Désignation brute à renvoyer*/
-    char *path;                             /* Chemin à traiter            */
-
-    path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin)));
-
-    result = strdup(basename(path));
-
-    free(path);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : modname  = nom du module à charger.                          *
-*                filename = chemin d'accès au code Python à charger.          *
-*                                                                             *
-*  Description : Crée un greffon à partir de code Python.                     *
-*                                                                             *
-*  Retour      : Adresse de la structure mise en place ou NULL si erreur.     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GPluginModule *g_python_plugin_new(const char *modname, const char *filename)
-{
-    GPythonPlugin *result;                  /* Structure à retourner       */
-    PyObject *name;                         /* Chemin d'accès pour Python  */
-    PyObject *module;                       /* Script Python chargé        */
-    PyObject *dict;                         /* Dictionnaire associé        */
-    PyObject *class;                        /* Classe à instancier         */
-    PyObject *instance;                     /* Instance Python du greffon  */
-
-    name = PyUnicode_FromString(modname);
-    if (name == NULL) goto bad_exit;
-
-    module = PyImport_Import(name);
-    Py_DECREF(name);
-
-    if (module == NULL) goto no_import;
-
-    dict = PyModule_GetDict(module);
-    class = PyDict_GetItemString(dict, "AutoLoad");
-
-    if (class == NULL) goto no_class;
-    if (!PyType_Check(class->ob_type)) goto no_class;
-
-    instance = PyObject_CallFunction(class, NULL);
-    if (instance == NULL) goto no_instance;
-
-    result = G_PYTHON_PLUGIN(pygobject_get(instance));
-
-    G_PLUGIN_MODULE(result)->filename = strdup(filename);
-
-    /**
-     * L'instance Python et l'objet GLib résultante sont un même PyGObject.
-     *
-     * Donc pas besoin de toucher au comptage des références ici, la libération
-     * se réalisera à la fin, quand l'objet GLib sera libéré.
-     */
-
-    Py_DECREF(module);
-
-    return G_PLUGIN_MODULE(result);
-
- no_instance:
-
-    log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance"));
-
- no_class:
-
-    if (class == NULL)
-        log_plugin_simple_message(LMT_ERROR,
-                                  _("An error occured when looking for the 'AutoLoad': item not found!"));
-
- no_import:
-
-    Py_XDECREF(module);
-
-    log_pychrysalide_exception(_("An error occured when importing '%s'"), modname);
-
- bad_exit:
-
-    return NULL;
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
 /*                           MODULE PYTHON POUR LES SCRIPTS                           */
 /* ---------------------------------------------------------------------------------- */
 
@@ -1877,6 +1669,7 @@ PyTypeObject *get_python_plugin_module_type(void)
     static PyMethodDef py_plugin_module_methods[] = {
         PLUGIN_MODULE_MANAGE_WRAPPER,
         PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER,
+        PLUGIN_MODULE_GET_MODNAME_WRAPPER,
 #ifdef HAVE_GTK_SUPPORT
         PLUGIN_MODULE_INCLUDE_THEME_WRAPPER,
         PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER,
@@ -1952,7 +1745,7 @@ bool ensure_python_plugin_module_is_registered(void)
 
         dict = PyModule_GetDict(module);
 
-        if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type))
+        if (!register_class_for_pygobject(dict, G_TYPE_PLUGIN_MODULE, type, &PyGObject_Type))
             return false;
 
         if (!define_plugin_module_constants(type))
@@ -1963,3 +1756,82 @@ bool ensure_python_plugin_module_is_registered(void)
     return true;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modname  = nom du module à charger.                          *
+*                filename = chemin d'accès au code Python à charger.          *
+*                                                                             *
+*  Description : Crée un greffon à partir de code Python.                     *
+*                                                                             *
+*  Retour      : Adresse de la structure mise en place ou NULL si erreur.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GPluginModule *create_python_plugin(const char *modname, const char *filename)
+{
+    GPluginModule *result;                  /* Structure à retourner       */
+    PyObject *name;                         /* Chemin d'accès pour Python  */
+    PyObject *module;                       /* Script Python chargé        */
+    PyObject *dict;                         /* Dictionnaire associé        */
+    PyObject *class;                        /* Classe à instancier         */
+    PyObject *instance;                     /* Instance Python du greffon  */
+
+    name = PyUnicode_FromString(modname);
+    if (name == NULL) goto bad_exit;
+
+    module = PyImport_Import(name);
+    Py_DECREF(name);
+
+    if (module == NULL) goto no_import;
+
+    dict = PyModule_GetDict(module);
+    class = PyDict_GetItemString(dict, "AutoLoad");
+
+    if (class == NULL) goto no_class;
+    if (!PyType_Check(class->ob_type)) goto no_class;
+
+    Py_INCREF(class);
+
+    instance = PyObject_CallFunction(class, NULL);
+    if (instance == NULL) goto no_instance;
+
+    result = G_PLUGIN_MODULE(pygobject_get(instance));
+
+    result->filename = strdup(filename);
+
+    /**
+     * L'instance Python et l'objet GLib résultante sont un même PyGObject.
+     *
+     * Donc pas besoin de toucher au comptage des références ici, la libération
+     * se réalisera à la fin, quand l'objet GLib sera libéré.
+     */
+
+    Py_DECREF(module);
+
+    return result;
+
+ no_instance:
+
+    log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance"));
+
+ no_class:
+
+    if (class == NULL)
+        log_plugin_simple_message(LMT_ERROR,
+                                  _("An error occured when looking for the 'AutoLoad': item not found!"));
+
+ no_import:
+
+    Py_XDECREF(module);
+
+    log_pychrysalide_exception(_("An error occured when importing '%s'"), modname);
+
+ bad_exit:
+
+    return NULL;
+
+}
diff --git a/plugins/pychrysalide/plugins/plugin.h b/plugins/pychrysalide/plugins/plugin.h
index ff805f4..ad54b8e 100644
--- a/plugins/pychrysalide/plugins/plugin.h
+++ b/plugins/pychrysalide/plugins/plugin.h
@@ -35,41 +35,15 @@
 
 
 
-/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */
-
-
-#define G_TYPE_PYTHON_PLUGIN                (g_python_plugin_get_type())
-#define G_PYTHON_PLUGIN(obj)                (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYTHON_PLUGIN, GPythonPlugin))
-#define G_IS_PYTHON_PLUGIN(obj)             (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYTHON_PLUGIN))
-#define G_PYTHON_PLUGIN_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass))
-#define G_IS_PYTHON_PLUGIN_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYTHON_PLUGIN))
-#define G_PYTHON_PLUGIN_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass))
-
-
-/* Ligne de représentation de code binaire (instance) */
-typedef struct _GPythonPlugin GPythonPlugin;
-
-/* Ligne de représentation de code binaire (classe) */
-typedef struct _GPythonPluginClass GPythonPluginClass;
-
-
-/* Indique le type défini par la GLib pour le greffon Python. */
-GType g_python_plugin_get_type(void);
-
-/* Crée un greffon à partir de code Python. */
-GPluginModule *g_python_plugin_new(const char *, const char *);
-
-
-
-/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */
-
-
 /* Fournit un accès à une définition de type à diffuser. */
 PyTypeObject *get_python_plugin_module_type(void);
 
 /* Prend en charge l'objet 'pychrysalide.plugins.PluginModule'. */
 bool ensure_python_plugin_module_is_registered(void);
 
+/* Crée un greffon à partir de code Python. */
+GPluginModule *create_python_plugin(const char *, const char *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H */
-- 
cgit v0.11.2-87-g4458