From a6a88792bc866d8a1d7cabd50a93374da5dd1e7a Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Mon, 28 Dec 2020 22:44:27 +0100
Subject: Improved the API for configuration and its Python documentation.

---
 plugins/pychrysalide/glibext/configuration.c | 869 ++++++++++++++++++++-------
 plugins/pychrysalide/glibext/configuration.h |   6 +
 plugins/pychrysalide/glibext/constants.c     | 116 ++++
 plugins/pychrysalide/glibext/constants.h     |   6 +
 plugins/pychrysalide/gtkext/easygtk.c        |  40 +-
 plugins/pychrysalide/helpers.c               | 124 ++++
 plugins/pychrysalide/helpers.h               |   7 +
 src/glibext/Makefile.am                      |   1 +
 src/glibext/configuration-int.h              | 121 ++++
 src/glibext/configuration.c                  | 209 ++++---
 src/glibext/configuration.h                  |   2 +-
 tests/glibext/configuration.py               |  71 +++
 12 files changed, 1218 insertions(+), 354 deletions(-)
 create mode 100644 src/glibext/configuration-int.h
 create mode 100644 tests/glibext/configuration.py

diff --git a/plugins/pychrysalide/glibext/configuration.c b/plugins/pychrysalide/glibext/configuration.c
index 192f602..b7d8f82 100644
--- a/plugins/pychrysalide/glibext/configuration.c
+++ b/plugins/pychrysalide/glibext/configuration.c
@@ -28,9 +28,11 @@
 #include <pygobject.h>
 
 
-#include <glibext/configuration.h>
+#include <glibext/configuration-int.h>
+#include <plugins/dt.h>
 
 
+#include "constants.h"
 #include "../access.h"
 #include "../helpers.h"
 
@@ -42,6 +44,9 @@
 /* Crée un nouvel objet Python de type 'ConfigParam'. */
 static PyObject *py_config_param_new(PyTypeObject *, PyObject *, PyObject *);
 
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_config_param_init(PyObject *, PyObject *, PyObject *);
+
 /* Efface toute valeur courante d'un paramètre de configuration. */
 static PyObject *py_config_param_make_empty(PyObject *, PyObject *);
 
@@ -63,9 +68,6 @@ static PyObject *py_config_param_get_value(PyObject *, void *);
 /* Modifie la valeur courante d'un paramètre de configuration. */
 static int py_config_param_set_value(PyObject *, PyObject *, void *);
 
-/* Définit les constantes pour les paramètres. */
-static bool py_config_param_define_constants(PyObject *);
-
 
 
 /* ----------------------------- PARCOURS DE PARAMETRES ----------------------------- */
@@ -98,9 +100,15 @@ static int py_config_param_iterator_init(PyObject *, PyObject *, PyObject *);
 /* ----------------------- GESTION GENERIQUE DE CONFIGURATION ----------------------- */
 
 
-/* Crée un nouvel objet Python de type 'GenConfig'. */
+/* Accompagne la création d'une instance dérivée en Python. */
 static PyObject *py_generic_config_new(PyTypeObject *, PyObject *, PyObject *);
 
+/* Initialise une instance sur la base du dérivé de GObject. */
+static int py_generic_config_init(PyObject *, PyObject *, PyObject *);
+
+/* Met à disposition un encadrement des accès aux paramètres. */
+static PyObject *py_generic_config_lock_unlock(PyObject *, PyObject *);
+
 /* Lit la configuration depuis un fichier. */
 static PyObject *py_generic_config_read(PyObject *, PyObject *);
 
@@ -116,9 +124,12 @@ static PyObject *py_generic_config_add(PyObject *, PyObject *);
 /* Retire un paramètre d'une configuration. */
 static PyObject *py_generic_config_delete(PyObject *, PyObject *);
 
-/* Fournit le chemin d'accès au binaire représenté. */
+/* Indique le fichier utilisé pour l'enregistrement XML. */
 static PyObject *py_generic_config_get_filename(PyObject *, void *);
 
+/* Renvoie la liste des paramètres de configuration. */
+static PyObject *py_generic_config_get_params(PyObject *, void *);
+
 
 
 /* ---------------------------------------------------------------------------------- */
@@ -128,73 +139,173 @@ static PyObject *py_generic_config_get_filename(PyObject *, void *);
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : type = type de l'objet à instancier.                         *
+*  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_config_param_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_config_param_type();
+
+    if (type == base)
+        goto simple_way;
+
+    /* Mise en place d'un type dédié */
+
+    first_time = (g_type_from_name(type->tp_name) == 0);
+
+    gtype = build_dynamic_type(G_TYPE_CFG_PARAM, type->tp_name, NULL, 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() */
+
+ simple_way:
+
+    result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet à initialiser (théoriquement).                  *
 *                args = arguments fournis à l'appel.                          *
 *                kwds = arguments de type key=val fournis.                    *
 *                                                                             *
-*  Description : Crée un nouvel objet Python de type 'ConfigParam'.           *
+*  Description : Initialise une instance sur la base du dérivé de GObject.    *
 *                                                                             *
-*  Retour      : Instance Python mise en place.                               *
+*  Retour      : 0.                                                           *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_config_param_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_config_param_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    PyObject *result;                       /* Instance à retourner        */
     const char *path;                       /* Accès au paramètre          */
-    unsigned int ptype;                     /* Type de paramètre           */
-    PyObject *value;                        /* Valeur par défaut éventuelle*/
+    ConfigParamType ptype;                  /* Type de paramètre           */
+    PyObject *py_value;                     /* Valeur par défaut éventuelle*/
     int ret;                                /* Bilan de lecture des args.  */
+    bool valid;                             /* Validité des transmissions  */
+    param_value value;                      /* Valeur de paramètre         */
     GCfgParam *param;                       /* Paramètre mis en place      */
 
-    value = NULL;
-
-    ret = PyArg_ParseTuple(args, "sI|O", &path, &ptype, &value);
-    if (!ret) return NULL;
-
-    if (value == NULL || value == Py_None)
-        param = g_config_param_new_empty(path, ptype);
+#define CONFIG_PARAM_DOC                                                        \
+    "ConfigParam holds a configuration parameter with its default and current"  \
+    " values.\n"                                                                \
+    "\n"                                                                        \
+    "Parameters are aimed to join a pychrysalide.glibext.GenConfig instance.\n" \
+    "\n"                                                                        \
+    "Instances can be created using the following constructor:\n"               \
+    "\n"                                                                        \
+    "    ConfigParam(path, type, value=None)"                                   \
+    "\n"                                                                        \
+    "Where *path* is dot separated string items serving as a parameter key,"    \
+    " *type* is a pychrysalide.glibext.ConfigParam.ConfigParamType value and"   \
+    " *value* is an optional default value if the parameter initial value"      \
+    " has not to be empty."
+
+    /* Récupération des paramètres */
+
+    py_value = NULL;
+
+    ret = PyArg_ParseTuple(args, "sO&|O", &path, convert_to_config_param_type, &ptype, &py_value);
+    if (!ret) return -1;
 
-    else
+    if (py_value != NULL && py_value != Py_None)
+    {
         switch (ptype)
         {
             case CPT_BOOLEAN:
-                if (PyBool_Check(value))
-                    param = g_config_param_new(path, CPT_BOOLEAN, (bool)(value == Py_True));
-                else
-                    param = NULL;
+                valid = PyBool_Check(py_value);
+                if (valid)
+                    value.boolean = (bool)(py_value == Py_True);
                 break;
 
             case CPT_INTEGER:
-                if (PyLong_Check(value))
-                    param = g_config_param_new(path, CPT_INTEGER, (int)PyLong_AsLong(value));
-                else
-                    param = NULL;
+                valid = PyLong_Check(py_value);
+                if (valid)
+                    value.integer = (int)PyLong_AsLong(py_value);
+                break;
+
+            case CPT_ULONG:
+                valid = PyLong_Check(py_value);
+                if (valid)
+                    value.ulong = (unsigned long)PyLong_AsUnsignedLong(py_value);
                 break;
 
             case CPT_STRING:
-                if (PyUnicode_Check(value))
-                    param = g_config_param_new(path, CPT_STRING, PyUnicode_DATA(value));
-                else
-                    param = NULL;
+                valid = PyUnicode_Check(py_value);
+                if (valid)
+                    value.string = PyUnicode_DATA(py_value);
+                break;
+
+            case CPT_COLOR:
+                valid = (convert_to_gdk_rgba(py_value, &value.color) == 1);
                 break;
 
             default:
-                param = NULL;
+                assert(false);
+                valid = false;
                 break;
 
         }
 
-    if (param != NULL)
-    {
-        result = pygobject_new(G_OBJECT(param));
-        g_object_unref(param);
+        if (!valid)
+        {
+            PyErr_SetString(PyExc_TypeError, "invalid value for the specified parameter type");
+            return -1;
+        }
+
     }
-    else result = NULL;
 
-    return result;
+    /* Initialisation d'un objet GLib */
+
+    ret = forward_pygobjet_init(self);
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
+
+    param = G_CFG_PARAM(pygobject_get(self));
+
+    if (py_value == NULL || py_value == Py_None)
+        g_config_param_build_empty(param, path, ptype);
+
+    else
+        g_config_param_build(param, path, ptype, &value);
+
+    return 0;
 
 }
 
@@ -216,6 +327,13 @@ static PyObject *py_config_param_make_empty(PyObject *self, PyObject *args)
 {
     GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
 
+#define CONFIG_PARAM_MAKE_EMPTY_METHOD PYTHON_METHOD_DEF        \
+(                                                               \
+    make_empty, "$self, /",                                     \
+    METH_NOARGS, py_config_param,                               \
+    "Unset the value of the current parameter."                 \
+)
+
     param = G_CFG_PARAM(pygobject_get(self));
 
     g_config_param_make_empty(param);
@@ -242,6 +360,13 @@ static PyObject *py_config_param_reset(PyObject *self, PyObject *args)
 {
     GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
 
+#define CONFIG_PARAM_RESET_METHOD PYTHON_METHOD_DEF \
+(                                                   \
+    reset, "$self, /",                              \
+    METH_NOARGS, py_config_param,                   \
+    "Reset the content of the current parameter."   \
+)
+
     param = G_CFG_PARAM(pygobject_get(self));
 
     g_config_param_reset(param);
@@ -269,6 +394,13 @@ static PyObject *py_config_param_get_path(PyObject *self, void *closure)
     GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
     const char *path;                       /* Chemin d'accès à diffuser   */
 
+#define CONFIG_PARAM_PATH_ATTRIB PYTHON_GET_DEF_FULL    \
+(                                                       \
+    path, py_config_param,                              \
+    "Dot separated string items used as key for a"      \
+    " configuration parameter."                         \
+)
+
     param = G_CFG_PARAM(pygobject_get(self));
     path = g_config_param_get_path(param);
 
@@ -292,13 +424,25 @@ static PyObject *py_config_param_get_path(PyObject *self, void *closure)
 
 static PyObject *py_config_param_get_type(PyObject *self, void *closure)
 {
+    PyObject *result;                       /* Type de paramètre à renvoyer*/
     GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
     ConfigParamType type;                   /* Type de paramètre           */
 
+#define CONFIG_PARAM_TYPE_ATTRIB PYTHON_GET_DEF_FULL            \
+(                                                               \
+    type, py_config_param,                                      \
+    "Type of value provided by a configuration parameter.\n"    \
+    "\n"                                                        \
+    "The attribute carries a"                                   \
+    " pychrysalide.glibext.ConfigParam.ConfigParamType value."  \
+)
+
     param = G_CFG_PARAM(pygobject_get(self));
     type = g_config_param_get_ptype(param);
 
-    return PyLong_FromLong(type);
+    result = cast_with_constants_group_from_type(get_python_config_param_type(), "ConfigParamType", type);
+
+    return result;
 
 }
 
@@ -318,13 +462,25 @@ static PyObject *py_config_param_get_type(PyObject *self, void *closure)
 
 static PyObject *py_config_param_get_state(PyObject *self, void *closure)
 {
+    PyObject *result;                       /* Etat à retourner            */
     GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
     ConfigParamState state;                 /* Statut de paramètre         */
 
+#define CONFIG_PARAM_STATE_ATTRIB PYTHON_GET_DEF_FULL           \
+(                                                               \
+    state, py_config_param,                                     \
+    "State of a configuration parameter.\n"                     \
+    "\n"                                                        \
+    "The attribute carries a"                                   \
+    " pychrysalide.glibext.ConfigParam.ConfigParamState value." \
+)
+
     param = G_CFG_PARAM(pygobject_get(self));
     state = g_config_param_get_state(param);
 
-    return PyLong_FromLong(state);
+    result = cast_with_constants_group_from_type(get_python_config_param_type(), "ConfigParamState", state);
+
+    return result;
 
 }
 
@@ -347,9 +503,16 @@ static PyObject *py_config_param_get_value(PyObject *self, void *closure)
     PyObject *result;                       /* Valeur à retourner          */
     GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
     ConfigParamType type;                   /* Type de paramètre manipulé  */
-    bool boolean;                           /* Valeur booléenne            */
-    int integer;                            /* Valeur entière              */
-    char *string;                           /* Chaîne de caractères        */
+    param_value value;                      /* Valeur de paramètre         */
+
+#define CONFIG_PARAM_VALUE_ATTRIB PYTHON_GETSET_DEF_FULL        \
+(                                                               \
+    value, py_config_param,                                     \
+    "Value of a configuration parameter.\n"                     \
+    "\n"                                                        \
+    "The type of the value carried by the attribute depends on" \
+    " pychrysalide.glibext.ConfigParam.type value."             \
+)
 
     param = G_CFG_PARAM(pygobject_get(self));
     type = g_config_param_get_ptype(param);
@@ -357,20 +520,25 @@ static PyObject *py_config_param_get_value(PyObject *self, void *closure)
     switch (type)
     {
         case CPT_BOOLEAN:
-            g_config_param_get_value(param, &boolean);
-            result = (boolean ? Py_True : Py_False);
+            g_config_param_get_value(param, &value.boolean);
+            result = (value.boolean ? Py_True : Py_False);
             Py_INCREF(result);
             break;
 
         case CPT_INTEGER:
-            g_config_param_get_value(param, &integer);
-            result = PyLong_FromLong(integer);
+            g_config_param_get_value(param, &value.integer);
+            result = PyLong_FromLong(value.integer);
+            break;
+
+        case CPT_ULONG:
+            g_config_param_get_value(param, &value.ulong);
+            result = PyLong_FromUnsignedLong(value.ulong);
             break;
 
         case CPT_STRING:
-            g_config_param_get_value(param, &string);
-            if (string != NULL)
-                result = PyUnicode_FromString(string);
+            g_config_param_get_value(param, &value.string);
+            if (value.string != NULL)
+                result = PyUnicode_FromString(value.string);
             else
             {
                 result = Py_None;
@@ -378,6 +546,11 @@ static PyObject *py_config_param_get_value(PyObject *self, void *closure)
             }
             break;
 
+        case CPT_COLOR:
+            g_config_param_get_value(param, &value.color);
+            result = create_gdk_rgba(&value.color);
+            break;
+
         default:
             result = NULL;
             break;
@@ -408,6 +581,7 @@ static int py_config_param_set_value(PyObject *self, PyObject *value, void *clos
     int result;                             /* Conclusion à remonter       */
     GCfgParam *param;                       /* Paramètre visé par l'opérat°*/
     ConfigParamType type;                   /* Type de paramètre manipulé  */
+    param_value pvalue;                     /* Valeur de paramètre         */
 
     result = -1;
 
@@ -428,7 +602,7 @@ static int py_config_param_set_value(PyObject *self, PyObject *value, void *clos
             case CPT_BOOLEAN:
                 if (PyBool_Check(value))
                 {
-                    g_config_param_set_value(param, (bool)(value == Py_True));
+                    pvalue.boolean = (value == Py_True);
                     result = 0;
                 }
                 break;
@@ -436,7 +610,15 @@ static int py_config_param_set_value(PyObject *self, PyObject *value, void *clos
             case CPT_INTEGER:
                 if (PyLong_Check(value))
                 {
-                    g_config_param_set_value(param, (int)PyLong_AsLong(value));
+                    pvalue.integer = PyLong_AsLong(value);
+                    result = 0;
+                }
+                break;
+
+            case CPT_ULONG:
+                if (PyLong_Check(value))
+                {
+                    pvalue.ulong = PyLong_AsUnsignedLong(value);
                     result = 0;
                 }
                 break;
@@ -444,16 +626,25 @@ static int py_config_param_set_value(PyObject *self, PyObject *value, void *clos
             case CPT_STRING:
                 if (PyUnicode_Check(value))
                 {
-                    g_config_param_set_value(param, PyUnicode_DATA(value));
+                    pvalue.string = PyUnicode_DATA(value);
                     result = 0;
                 }
                 break;
 
+            case CPT_COLOR:
+                if (convert_to_gdk_rgba(value, &pvalue.color) == 1)
+                    result = 0;
+                break;
+
             default:
+                assert(false);
                 break;
 
         }
 
+        if (result == 0)
+            g_config_param_set_value(param, &pvalue);
+
     }
 
     return result;
@@ -476,36 +667,17 @@ static int py_config_param_set_value(PyObject *self, PyObject *value, void *clos
 PyTypeObject *get_python_config_param_type(void)
 {
     static PyMethodDef py_config_param_methods[] = {
-        {
-            "make_empty", py_config_param_make_empty,
-            METH_NOARGS,
-            "make_empty($self, /)\n--\n\nUnset the value of the current parameter."
-        },
-        {
-            "reset", py_config_param_reset,
-            METH_NOARGS,
-            "reset($self, /)\n--\n\nReset the content of the current parameter."
-        },
+        CONFIG_PARAM_MAKE_EMPTY_METHOD,
+        CONFIG_PARAM_RESET_METHOD,
         { NULL }
     };
 
     static PyGetSetDef py_config_param_getseters[] = {
-        {
-            "path", py_config_param_get_path, NULL,
-            "Show the path used as key for a configuration parameter.", NULL
-        },
-        {
-            "type", py_config_param_get_type, NULL,
-            "Show the type of value provided by a configuration parameter.", NULL
-        },
-        {
-            "state", py_config_param_get_state, NULL,
-            "Show the state of a configuration parameter.", NULL
-        },
-        {
-            "value", py_config_param_get_value, py_config_param_set_value,
-            "Handle the value of a configuration parameter.", NULL
-        },
+        CONFIG_PARAM_PATH_ATTRIB,
+        CONFIG_PARAM_TYPE_ATTRIB,
+        CONFIG_PARAM_STATE_ATTRIB,
+        CONFIG_PARAM_VALUE_ATTRIB,
+        CONFIG_PARAM_VALUE_ATTRIB,
         { NULL }
     };
 
@@ -518,10 +690,12 @@ PyTypeObject *get_python_config_param_type(void)
 
         .tp_flags       = Py_TPFLAGS_DEFAULT,
 
-        .tp_doc         = "PyChrysalide generic configuration",
+        .tp_doc         = CONFIG_PARAM_DOC,
 
         .tp_methods     = py_config_param_methods,
         .tp_getset      = py_config_param_getseters,
+
+        .tp_init        = py_config_param_init,
         .tp_new         = py_config_param_new
 
     };
@@ -533,33 +707,37 @@ PyTypeObject *get_python_config_param_type(void)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : dict = dictionnaire à compléter.                             *
+*  Paramètres  : module = module dont la définition est à compléter.          *
 *                                                                             *
-*  Description : Définit les constantes pour les paramètres.                  *
+*  Description : Prend en charge l'objet 'pychrysalide.glibext.ConfigParam'.  *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static bool py_config_param_define_constants(PyObject *dict)
+bool ensure_python_config_param_is_registered(void)
 {
-    int ret;                                /* Bilan d'un ajout            */
+    PyTypeObject *type;                     /* Type Python 'ConfigParam'   */
+    PyObject *module;                       /* Module à recompléter        */
+    PyObject *dict;                         /* Dictionnaire du module      */
 
-#define DEF_ULONG_CONST(name)                                               \
-    ret = PyDict_SetItemString(dict, #name, PyLong_FromUnsignedLong(name)); \
-    if (ret == -1) return false;
+    type = get_python_config_param_type();
+
+    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    {
+        module = get_access_to_python_module("pychrysalide.glibext");
 
-    DEF_ULONG_CONST(CPT_BOOLEAN);
-    DEF_ULONG_CONST(CPT_INTEGER);
-    DEF_ULONG_CONST(CPT_STRING);
-    DEF_ULONG_CONST(CPT_COUNT);
+        dict = PyModule_GetDict(module);
 
-    DEF_ULONG_CONST(CPS_UNDEFINED);
-    DEF_ULONG_CONST(CPS_CHANGED);
-    DEF_ULONG_CONST(CPS_DEFAULT);
-    DEF_ULONG_CONST(CPS_EMPTY);
+        if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type, &PyGObject_Type))
+            return false;
+
+        if (!define_config_param_constants(type))
+            return false;
+
+    }
 
     return true;
 
@@ -568,39 +746,45 @@ static bool py_config_param_define_constants(PyObject *dict)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : module = module dont la définition est à compléter.          *
+*  Paramètres  : arg = argument quelconque à tenter de convertir.             *
+*                dst = destination des valeurs récupérées en cas de succès.   *
 *                                                                             *
-*  Description : Prend en charge l'objet 'pychrysalide.glibext.ConfigParam'.  *
+*  Description : Tente de convertir en paramètre de configuration.            *
 *                                                                             *
-*  Retour      : Bilan de l'opération.                                        *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool ensure_python_config_param_is_registered(void)
+int convert_to_config_param(PyObject *arg, void *dst)
 {
-    PyTypeObject *type;                     /* Type Python 'ConfigParam'   */
-    PyObject *module;                       /* Module à recompléter        */
-    PyObject *dict;                         /* Dictionnaire du module      */
+    int result;                             /* Bilan à retourner           */
 
-    type = get_python_config_param_type();
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_config_param_type());
 
-    if (!PyType_HasFeature(type, Py_TPFLAGS_READY))
+    switch (result)
     {
-        module = get_access_to_python_module("pychrysalide.glibext");
+        case -1:
+            /* L'exception est déjà fixée par Python */
+            result = 0;
+            break;
 
-        dict = PyModule_GetDict(module);
+        case 0:
+            PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to configuration parameter");
+            break;
 
-        if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type, &PyGObject_Type))
-            return false;
+        case 1:
+            *((GCfgParam **)dst) = G_CFG_PARAM(pygobject_get(arg));
+            break;
 
-        if (!py_config_param_define_constants(type->tp_dict))
-            return false;
+        default:
+            assert(false);
+            break;
 
     }
 
-    return true;
+    return result;
 
 }
 
@@ -701,19 +885,22 @@ static PyObject *py_config_param_iterator_next(PyObject *self)
 
 static int py_config_param_iterator_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    pyConfigParamIterator *iterator;        /* Références pour le parcours */
-    PyObject *config;                       /* Configuration format Python */
+    GGenConfig *config;                     /* Configuration format natif  */
     int ret;                                /* Bilan de lecture des args.  */
+    pyConfigParamIterator *iterator;        /* Références pour le parcours */
 
-    ret = PyArg_ParseTuple(args, "O", &config);
-    if (!ret) return -1;
+#define CONFIG_PARAM_ITERATOR_DOC                                           \
+    "ConfigParamIterator is an iterator for configuration parameters.\n"    \
+    "\n"                                                                    \
+    "This kind of iterator is provided by the"                              \
+    " pychrysalide.glibext.GenConfig.params attribute."
 
-    ret = PyObject_IsInstance(config, (PyObject *)get_python_generic_config_type());
+    ret = PyArg_ParseTuple(args, "O&", convert_to_generic_config, &config);
     if (!ret) return -1;
 
     iterator = (pyConfigParamIterator *)self;
 
-    iterator->config = G_GEN_CONFIG(pygobject_get(config));
+    iterator->config = config;
     g_object_ref(G_OBJECT(iterator->config));
 
     g_generic_config_rlock(iterator->config);
@@ -752,7 +939,7 @@ PyTypeObject *get_python_config_param_iterator_type(void)
 
         .tp_flags       = Py_TPFLAGS_DEFAULT,
 
-        .tp_doc         = "Iterator for configuration parameters",
+        .tp_doc         = CONFIG_PARAM_ITERATOR_DOC,
 
         .tp_iter        = PyObject_SelfIter,
         .tp_iternext    = py_config_param_iterator_next,
@@ -814,38 +1001,163 @@ bool ensure_python_config_param_iterator_is_registered(void)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : type = type de l'objet à instancier.                         *
+*  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_generic_config_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_generic_config_type();
+
+    if (type == base)
+        goto simple_way;
+
+    /* Mise en place d'un type dédié */
+
+    first_time = (g_type_from_name(type->tp_name) == 0);
+
+    gtype = build_dynamic_type(G_TYPE_GEN_CONFIG, type->tp_name, NULL, 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() */
+
+ simple_way:
+
+    result = PyType_GenericNew(type, args, kwds);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = objet à initialiser (théoriquement).                  *
 *                args = arguments fournis à l'appel.                          *
 *                kwds = arguments de type key=val fournis.                    *
 *                                                                             *
-*  Description : Crée un nouvel objet Python de type 'GenConfig'.             *
+*  Description : Initialise une instance sur la base du dérivé de GObject.    *
 *                                                                             *
-*  Retour      : Instance Python mise en place.                               *
+*  Retour      : 0.                                                           *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+static int py_generic_config_init(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    PyObject *result;                       /* Instance à retourner        */
-    const char *name;                       /* Nom du fichier à charger    */
+    const char *name;                       /* Désignation de configuration*/
     int ret;                                /* Bilan de lecture des args.  */
-    GGenConfig *config;                     /* Version GLib du format      */
+    GGenConfig *config;                     /* Configuration en place      */
+
+#define GENERIC_CONFIG_DOC                                                  \
+    "The GenConfig class defines a generic way to load, provide and store"  \
+    " configuration items. Each of these items is handled with a"           \
+    " pychrysalide.glibext.ConfigParam object.\n"                           \
+    "\n"                                                                    \
+    "Instances can be created using the following constructor:\n"           \
+    "\n"                                                                    \
+    "    GenConfig(name=None)"                                              \
+    "\n"                                                                    \
+    "Where *name* is a suitable storage filename for the configuration. If" \
+    " no *name* is defined, the configuration is expected to be"            \
+    " memory-only resident."
+
+    /* Récupération des paramètres */
 
     name = NULL;
 
-    ret = PyArg_ParseTuple(args, "|s", &name);
+    ret = PyArg_ParseTuple(args, "s", &name);
+    if (!ret) return -1;
+
+    /* Initialisation d'un objet GLib */
+
+    ret = forward_pygobjet_init(self);
+    if (ret == -1) return -1;
+
+    /* Eléments de base */
+
+    config = G_GEN_CONFIG(pygobject_get(self));
+
+    g_generic_config_build(config, name);
+
+    return 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : self = configuration à manipuler.                            *
+*                args = paramètres liés à l'appel.                            *
+*                                                                             *
+*  Description : Met à disposition un encadrement des accès aux paramètres.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static PyObject *py_generic_config_lock_unlock(PyObject *self, PyObject *args)
+{
+    PyObject *result;                       /* Instance à retourner        */
+    bool write;                             /* Accès en lecture / écriture */
+    bool lock;                              /* Pose ou retrait du verrou ? */
+    int ret;                                /* Bilan de lecture des args.  */
+    GGenConfig *config;                     /* Version GLib de la config.  */
+
+#define GENERIC_CONFIG_LOCK_UNLOCK_METHOD PYTHON_METHOD_DEF     \
+(                                                               \
+    lock_unlock, "$self, write, lock",                          \
+    METH_VARARGS, py_generic_config,                            \
+    "Lock or unlock access to the configuration internals.\n"   \
+    "\n"                                                        \
+    "The *write* argument states if the operation targets read" \
+    " or write accesses, and the *lock* value defines the"      \
+    " state to achieve.\n"                                      \
+    "\n"                                                        \
+    "Both arguments are boolean values."                        \
+)
+
+    ret = PyArg_ParseTuple(args, "pp", &write, &lock);
     if (!ret) return NULL;
 
-    if (name == NULL)
-        config = g_generic_config_new();
-    else
-        config = g_generic_config_new_from_file(name);
+    config = G_GEN_CONFIG(pygobject_get(self));
+
+    g_generic_config_lock_unlock(config, write, lock);
 
-    g_object_ref_sink(G_OBJECT(config));
-    result = pygobject_new(G_OBJECT(config));
-    g_object_unref(G_OBJECT(config));
+    result = Py_None;
+    Py_INCREF(result);
 
     return result;
 
@@ -868,9 +1180,19 @@ static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObj
 static PyObject *py_generic_config_read(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance à retourner        */
-    GGenConfig *config;                     /* Version GLib du format      */
+    GGenConfig *config;                     /* Version GLib de la config.  */
     bool status;                            /* Bilan de l'opération        */
 
+#define GENERIC_CONFIG_READ_METHOD PYTHON_METHOD_DEF            \
+(                                                               \
+    read, "$self, /",                                           \
+    METH_NOARGS, py_generic_config,                             \
+    "Read the configuration from its relative XML file.\n"      \
+    "\n"                                                        \
+    "The returned value is True if the operation terminated"    \
+    " with success, or False in case of failure."               \
+)
+
     config = G_GEN_CONFIG(pygobject_get(self));
 
     status = g_generic_config_read(config);
@@ -899,9 +1221,19 @@ static PyObject *py_generic_config_read(PyObject *self, PyObject *args)
 static PyObject *py_generic_config_write(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance à retourner        */
-    GGenConfig *config;                     /* Version GLib du format      */
+    GGenConfig *config;                     /* Version GLib de la config.  */
     bool status;                            /* Bilan de l'opération        */
 
+#define GENERIC_CONFIG_WRITE_METHOD PYTHON_METHOD_DEF           \
+(                                                               \
+    write, "$self, /",                                          \
+    METH_NOARGS, py_generic_config,                             \
+    "Write the configuration to its relative XML file.\n"       \
+    "\n"                                                        \
+    "The returned value is True if the operation terminated"    \
+    " with success, or False in case of failure."               \
+)
+
     config = G_GEN_CONFIG(pygobject_get(self));
 
     status = g_generic_config_write(config);
@@ -930,20 +1262,49 @@ static PyObject *py_generic_config_write(PyObject *self, PyObject *args)
 static PyObject *py_generic_config_search(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance à retourner        */
-    GGenConfig *config;                     /* Version GLib du format      */
+    int lock;                               /* Ordre de pose de verrou     */
     const char *path;                       /* Chemin d'accès du paramètre */
     int ret;                                /* Bilan de lecture des args.  */
+    GGenConfig *config;                     /* Version GLib de la config.  */
     GCfgParam *param;                       /* Paramètre trouvé ou NULL    */
 
-    config = G_GEN_CONFIG(pygobject_get(self));
-
-    ret = PyArg_ParseTuple(args, "s", &path);
+#define GENERIC_CONFIG_SEARCH_METHOD PYTHON_METHOD_DEF                      \
+(                                                                           \
+    search, "$self, path, /, lock=True",                                    \
+    METH_VARARGS, py_generic_config,                                        \
+    "Look for a given configuration parameter.\n"                           \
+    "\n"                                                                    \
+    "The *path* argument is a string used as key pointing to a parameter."  \
+    " The *lock* boolean value is an optional order handling the way"       \
+    " configuration parameters are accessed.\n"                             \
+    "\n"                                                                    \
+    "The configuration has to be locked while accessing its content. This"  \
+    " lock can be managed with the *lock* argument of this function or"     \
+    " thanks to the pychrysalide.glibext.GenConfig.lock_unlock method().\n" \
+    "\n"                                                                    \
+    "The returned value is a pychrysalide.glibext.ConfigParam instance in"  \
+    " case of success or None if the parameter is not found."               \
+)
+
+    lock = 1;
+
+    ret = PyArg_ParseTuple(args, "s|p", &path, &lock);
     if (!ret) return NULL;
 
-    param = g_generic_config_search(config, path);
+    config = G_GEN_CONFIG(pygobject_get(self));
+
+    param = _g_generic_config_search(config, path, lock);
 
-    result = pygobject_new(G_OBJECT(param));
-    Py_XINCREF(result);
+    if (param == NULL)
+    {
+        result = Py_None;
+        Py_INCREF(result);
+    }
+    else
+    {
+        result = pygobject_new(G_OBJECT(param));
+        g_object_unref(G_OBJECT(param));
+    }
 
     return result;
 
@@ -966,28 +1327,50 @@ static PyObject *py_generic_config_search(PyObject *self, PyObject *args)
 static PyObject *py_generic_config_add(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Instance à retourner        */
-    GGenConfig *config;                     /* Version GLib du format      */
-    PyObject *param;                        /* Paramètre transmis          */
+    int lock;                               /* Ordre de pose de verrou     */
+    GCfgParam *param;                       /* Paramètre GLib transmis     */
     int ret;                                /* Bilan de lecture des args.  */
+    GGenConfig *config;                     /* Version GLib de la config.  */
     GCfgParam *added;                       /* Elément ajouté ou NULL      */
 
-    config = G_GEN_CONFIG(pygobject_get(self));
-
-    ret = PyArg_ParseTuple(args, "O", &param);
+#define GENERIC_CONFIG_ADD_METHOD PYTHON_METHOD_DEF                         \
+(                                                                           \
+    add, "$self, param, /, lock=True",                                      \
+    METH_VARARGS, py_generic_config,                                        \
+    "Add an existing parameter to a configuration.\n"                       \
+    "\n"                                                                    \
+    "The *param* argument has to be a pychrysalide.glibext.ConfigParam"     \
+    " instance. The *lock* boolean value is an optional order handling"     \
+    " the way configuration parameters are accessed.\n"                     \
+    "\n"                                                                    \
+    "The configuration has to be locked while accessing its content. This"  \
+    " lock can be managed with the *lock* argument of this function or"     \
+    " thanks to the pychrysalide.glibext.GenConfig.lock_unlock method().\n" \
+    "\n"                                                                    \
+    "The returned value is a pychrysalide.glibext.ConfigParam instance in"  \
+    " case of success or None if the parameter already exists in the"       \
+    " configuration."                                                       \
+)
+
+    lock = 1;
+
+    ret = PyArg_ParseTuple(args, "O&|p", convert_to_config_param, &param, &lock);
     if (!ret) return NULL;
 
-    ret = PyObject_IsInstance(param, (PyObject *)get_python_config_param_type());
-    if (!ret) Py_RETURN_NONE;
+    config = G_GEN_CONFIG(pygobject_get(self));
 
-    added = g_generic_config_add_param(config, G_CFG_PARAM(pygobject_get(param)));
+    added = _g_generic_config_add_param(config, param, lock);
 
-    if (added != NULL)
+    if (added == NULL)
     {
-        result = pygobject_new(G_OBJECT(added));
-        Py_XINCREF(result);
+        result = Py_None;
+        Py_INCREF(result);
     }
     else
-        result = NULL;
+    {
+        result = pygobject_new(G_OBJECT(added));
+        g_object_unref(G_OBJECT(added));
+    }
 
     return result;
 
@@ -1009,15 +1392,25 @@ static PyObject *py_generic_config_add(PyObject *self, PyObject *args)
 
 static PyObject *py_generic_config_delete(PyObject *self, PyObject *args)
 {
-    GGenConfig *config;                     /* Version GLib du format      */
     const char *path;                       /* Chemin d'accès du paramètre */
     int ret;                                /* Bilan de lecture des args.  */
-
-    config = G_GEN_CONFIG(pygobject_get(self));
+    GGenConfig *config;                     /* Version GLib de la config.  */
+
+#define GENERIC_CONFIG_DELETE_METHOD PYTHON_METHOD_DEF                      \
+(                                                                           \
+    delete, "$self, path",                                                  \
+    METH_VARARGS, py_generic_config,                                        \
+    "Delete an existing parameter from a configuration.\n"                  \
+    "\n"                                                                    \
+    "The *path* argument is a string used as key pointing to the parameter" \
+    " to process."                                                          \
+)
 
     ret = PyArg_ParseTuple(args, "s", &path);
     if (!ret) return NULL;
 
+    config = G_GEN_CONFIG(pygobject_get(self));
+
     g_generic_config_delete_param(config, path);
 
     Py_RETURN_NONE;
@@ -1027,33 +1420,37 @@ static PyObject *py_generic_config_delete(PyObject *self, PyObject *args)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : self = configuration à manipuler.                            *
-*                args = non utilisé ici.                                      *
+*  Paramètres  : self    = NULL car méthode statique.                         *
+*                closure = non utilisé ici.                                   *
 *                                                                             *
-*  Description : Renvoie la liste des paramètres de configuration.            *
+*  Description : Indique le fichier utilisé pour l'enregistrement XML.        *
 *                                                                             *
-*  Retour      : Itérateur pour la liste des paramètres.                      *
+*  Retour      : Chemin d'accès, potentiellement non existant.                *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_generic_config_list_params(PyObject *self, PyObject *args)
+static PyObject *py_generic_config_get_filename(PyObject *self, void *closure)
 {
-    PyObject *result;                       /* Instance à retourner        */
-    PyTypeObject *iterator_type;            /* Type Python de l'itérateur  */
-    PyObject *args_list;                    /* Arguments de mise en place  */
-
-    iterator_type = get_python_config_param_iterator_type();
+    GGenConfig *config;                     /* Version GLib de la config.  */
+    const char *filename;                   /* Chemin d'accès au fichier   */
 
-    Py_INCREF(self);
+#define GENERIC_CONFIG_FILENAME_ATTRIB PYTHON_GET_DEF_FULL      \
+(                                                               \
+    filename, py_generic_config,                                \
+    "Path to the file used as storage backend for the"          \
+    " configuration.\n"                                         \
+    "\n"                                                        \
+    "The result is a string pointing to a file which may not"   \
+    " (yet) exist."                                             \
+)
 
-    args_list = Py_BuildValue("(O)", self);
-    result = PyObject_CallObject((PyObject *)iterator_type, args_list);
+    config = G_GEN_CONFIG(pygobject_get(self));
 
-    Py_DECREF(args_list);
+    filename = g_generic_config_get_filename(config);
 
-    return result;
+    return PyUnicode_FromString(filename);
 
 }
 
@@ -1063,24 +1460,39 @@ static PyObject *py_generic_config_list_params(PyObject *self, PyObject *args)
 *  Paramètres  : self    = NULL car méthode statique.                         *
 *                closure = non utilisé ici.                                   *
 *                                                                             *
-*  Description : Fournit le chemin d'accès au binaire représenté.             *
+*  Description : Renvoie la liste des paramètres de configuration.            *
 *                                                                             *
-*  Retour      : Chemin d'accès en Python.                                    *
+*  Retour      : Liste d'éléments à parcourir.                                *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static PyObject *py_generic_config_get_filename(PyObject *self, void *closure)
+static PyObject *py_generic_config_get_params(PyObject *self, void *closure)
 {
-    GGenConfig *config;                     /* Version GLib du format      */
-    const char *filename;                   /* Chemin d'accès au fichier   */
+    PyObject *result;                       /* Instance à retourner        */
+    PyTypeObject *iterator_type;            /* Type Python de l'itérateur  */
+    PyObject *args_list;                    /* Arguments de mise en place  */
 
-    config = G_GEN_CONFIG(pygobject_get(self));
+#define GENERIC_CONFIG_PARAMS_ATTRIB PYTHON_GET_DEF_FULL        \
+(                                                               \
+    params, py_generic_config,                                  \
+    "List of all registered configuration parameters.\n"        \
+    "\n"                                                        \
+    "The result is a pychrysalide.glibext.ConfigParamIterator"  \
+    " over pychrysalide.glibext.ConfigParam instances."         \
+)
 
-    filename = g_generic_config_get_filename(config);
+    iterator_type = get_python_config_param_iterator_type();
 
-    return PyUnicode_FromString(filename);
+    Py_INCREF(self);
+
+    args_list = Py_BuildValue("(O)", self);
+    result = PyObject_CallObject((PyObject *)iterator_type, args_list);
+
+    Py_DECREF(args_list);
+
+    return result;
 
 }
 
@@ -1100,44 +1512,18 @@ static PyObject *py_generic_config_get_filename(PyObject *self, void *closure)
 PyTypeObject *get_python_generic_config_type(void)
 {
     static PyMethodDef py_generic_config_methods[] = {
-        {
-            "read", py_generic_config_read,
-            METH_NOARGS,
-            "read(, /)\n--\n\nRead the configuration from its relative XML file."
-        },
-        {
-            "write", py_generic_config_write,
-            METH_NOARGS,
-            "write(, /)\n--\n\nWrite the configuration to its relative XML file."
-        },
-        {
-            "search", py_generic_config_search,
-            METH_VARARGS,
-            "search($self, path, /)\n--\n\nLook for a given configuration parameter."
-        },
-        {
-            "add", py_generic_config_add,
-            METH_VARARGS,
-            "add($self, param, /)\n--\n\nAdd an existing parameter to a configuration."
-        },
-        {
-            "delete", py_generic_config_delete,
-            METH_VARARGS,
-            "delete($self, path, /)\n--\n\nDelete an existing parameter from a configuration."
-        },
-        {
-            "params", py_generic_config_list_params,
-            METH_NOARGS,
-            "params($self, /)\n--\n\nList all registered configuration parameters."
-        },
+        GENERIC_CONFIG_LOCK_UNLOCK_METHOD,
+        GENERIC_CONFIG_READ_METHOD,
+        GENERIC_CONFIG_WRITE_METHOD,
+        GENERIC_CONFIG_SEARCH_METHOD,
+        GENERIC_CONFIG_ADD_METHOD,
+        GENERIC_CONFIG_DELETE_METHOD,
         { NULL }
     };
 
     static PyGetSetDef py_generic_config_getseters[] = {
-        {
-            "filename", py_generic_config_get_filename, NULL,
-            "Show the filename of the loaded binary file.", NULL
-        },
+        GENERIC_CONFIG_FILENAME_ATTRIB,
+        GENERIC_CONFIG_PARAMS_ATTRIB,
         { NULL }
     };
 
@@ -1150,10 +1536,12 @@ PyTypeObject *get_python_generic_config_type(void)
 
         .tp_flags       = Py_TPFLAGS_DEFAULT,
 
-        .tp_doc         = "PyChrysalide generic configuration",
+        .tp_doc         = GENERIC_CONFIG_DOC,
 
         .tp_methods     = py_generic_config_methods,
         .tp_getset      = py_generic_config_getseters,
+
+        .tp_init        = py_generic_config_init,
         .tp_new         = py_generic_config_new
 
     };
@@ -1197,3 +1585,48 @@ bool ensure_python_generic_config_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 configuration générique.               *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_generic_config(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+
+    result = PyObject_IsInstance(arg, (PyObject *)get_python_generic_config_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 generic configuration");
+            break;
+
+        case 1:
+            *((GGenConfig **)dst) = G_GEN_CONFIG(pygobject_get(arg));
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
diff --git a/plugins/pychrysalide/glibext/configuration.h b/plugins/pychrysalide/glibext/configuration.h
index a4e141a..a82b177 100644
--- a/plugins/pychrysalide/glibext/configuration.h
+++ b/plugins/pychrysalide/glibext/configuration.h
@@ -40,6 +40,9 @@ PyTypeObject *get_python_config_param_type(void);
 /* Prend en charge l'objet 'pychrysalide.glibext.ConfigParam'. */
 bool ensure_python_config_param_is_registered(void);
 
+/* Tente de convertir en paramètre de configuration. */
+int convert_to_config_param(PyObject *, void *);
+
 
 
 /* ----------------------------- PARCOURS DE PARAMETRES ----------------------------- */
@@ -61,6 +64,9 @@ PyTypeObject *get_python_generic_config_type(void);
 /* Prend en charge l'objet 'pychrysalide.glibext.GenConfig'. */
 bool ensure_python_generic_config_is_registered(void);
 
+/* Tente de convertir en configuration générique. */
+int convert_to_generic_config(PyObject *, void *);
+
 
 
 #endif  /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONFIGURATION_H */
diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c
index 3f657e2..373d1bf 100644
--- a/plugins/pychrysalide/glibext/constants.c
+++ b/plugins/pychrysalide/glibext/constants.c
@@ -27,6 +27,7 @@
 
 #include <i18n.h>
 #include <glibext/bufferline.h>
+#include <glibext/configuration.h>
 #include <glibext/linesegment.h>
 #include <glibext/gbinportion.h>
 #include <glibext/gloadedpanel.h>
@@ -249,6 +250,121 @@ int convert_to_buffer_line_flags(PyObject *arg, void *dst)
 *                                                                             *
 *  Paramètres  : type = type dont le dictionnaire est à compléter.            *
 *                                                                             *
+*  Description : Définit les constantes relatives aux paramètres de config.   *
+*                                                                             *
+*  Retour      : true en cas de succès de l'opération, false sinon.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool define_config_param_constants(PyTypeObject *type)
+{
+    bool result;                            /* Bilan à retourner           */
+    PyObject *values;                       /* Groupe de valeurs à établir */
+
+    values = PyDict_New();
+
+    result = add_const_to_group(values, "BOOLEAN", CPT_BOOLEAN);
+    if (result) result = add_const_to_group(values, "INTEGER", CPT_INTEGER);
+    if (result) result = add_const_to_group(values, "ULONG", CPT_ULONG);
+    if (result) result = add_const_to_group(values, "STRING", CPT_STRING);
+    if (result) result = add_const_to_group(values, "COLOR", CPT_COLOR);
+    if (result) result = add_const_to_group(values, "COUNT", CPT_COUNT);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, false, "ConfigParamType", values,
+                                            "Kind of value available for configuration parameter types.");
+
+    values = PyDict_New();
+
+    result = add_const_to_group(values, "UNDEFINED", CPS_UNDEFINED);
+    if (result) result = add_const_to_group(values, "CHANGED", CPS_CHANGED);
+    if (result) result = add_const_to_group(values, "DEFAULT", CPS_DEFAULT);
+    if (result) result = add_const_to_group(values, "EMPTY", CPS_EMPTY);
+
+    if (!result)
+    {
+        Py_DECREF(values);
+        goto exit;
+    }
+
+    result = attach_constants_group_to_type(type, true, "ConfigParamState", values,
+                                            "States of a value carried by a configuration parameter.");
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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 constante ConfigParamType.             *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_config_param_type(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+    unsigned long value;                    /* Valeur récupérée            */
+
+    result = PyObject_IsInstance(arg, (PyObject *)&PyLong_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 ConfigParamType");
+            break;
+
+        case 1:
+
+            value = PyLong_AsUnsignedLong(arg);
+
+            if (value > CPT_COUNT)
+            {
+                result = 0;
+                PyErr_SetString(PyExc_ValueError, _("invalid configuration parameter type"));
+            }
+
+            else
+                *((ConfigParamType *)dst) = value;
+
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : type = type dont le dictionnaire est à compléter.            *
+*                                                                             *
 *  Description : Définit les constantes relatives aux segments de ligne.      *
 *                                                                             *
 *  Retour      : true en cas de succès de l'opération, false sinon.           *
diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h
index f509866..342b7ad 100644
--- a/plugins/pychrysalide/glibext/constants.h
+++ b/plugins/pychrysalide/glibext/constants.h
@@ -43,6 +43,12 @@ bool define_buffer_line_constants(PyTypeObject *);
 /* Tente de convertir en constante BufferLineFlags. */
 int convert_to_buffer_line_flags(PyObject *, void *);
 
+/* Définit les constantes relatives aux paramètres de configuration. */
+bool define_config_param_constants(PyTypeObject *);
+
+/* Tente de convertir en constante ConfigParamType. */
+int convert_to_config_param_type(PyObject *, void *);
+
 /* Définit les constantes relatives aux segments de ligne. */
 bool define_line_segment_constants(PyTypeObject *);
 
diff --git a/plugins/pychrysalide/gtkext/easygtk.c b/plugins/pychrysalide/gtkext/easygtk.c
index a489cd1..34b917f 100644
--- a/plugins/pychrysalide/gtkext/easygtk.c
+++ b/plugins/pychrysalide/gtkext/easygtk.c
@@ -67,19 +67,16 @@ static PyObject *py_easygtk_get_nth_contained_child(PyObject *, PyObject *);
 
 static PyObject *py_easygtk_get_color_from_style(PyObject *self, PyObject *args)
 {
-    PyObject *result;                       /* Désignation à retourner     */
+    PyObject *result;                       /* Coloration à retourner      */
     const char *class;                      /* Classe de style GTK         */
     int background;                         /* Nature du traitement        */
     int ret;                                /* Bilan de lecture des args.  */
     GdkRGBA color;                          /* Couleur obtenue             */
     bool status;                            /* Bilan de la récupération    */
-    PyObject *gdk_mod;                      /* Module Python Gdk           */
-    PyObject *rgba_type;                    /* Classe "GtkRGBA"            */
-    PyObject *rgba_args;                    /* Arguments pour l'appel      */
 
-#define EASYGTK_GET_COLOR_FROM_STYLE_METHOD PYTHON_METHOD_DEF     \
+#define EASYGTK_GET_COLOR_FROM_STYLE_METHOD PYTHON_METHOD_DEF           \
 (                                                                       \
-    get_color_from_style, "cls, background, /",                  \
+    get_color_from_style, "cls, background, /",                         \
     METH_VARARGS | METH_STATIC, py_easygtk,                             \
     "Find the index of a given child widget inside a GTK container"     \
     " children.\n"                                                      \
@@ -96,37 +93,10 @@ static PyObject *py_easygtk_get_color_from_style(PyObject *self, PyObject *args)
     status = get_color_from_style(class, background, &color);
 
     if (status)
-    {
-        gdk_mod = PyImport_ImportModule("gi.repository.Gdk");
-
-        if (gdk_mod == NULL)
-        {
-            PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module");
-            goto done;
-        }
-
-        rgba_type = PyObject_GetAttrString(gdk_mod, "RGBA");
-
-        Py_DECREF(gdk_mod);
-
-        rgba_args = PyTuple_New(4);
-        PyTuple_SetItem(rgba_args, 0, PyFloat_FromDouble(color.red));
-        PyTuple_SetItem(rgba_args, 1, PyFloat_FromDouble(color.green));
-        PyTuple_SetItem(rgba_args, 2, PyFloat_FromDouble(color.blue));
-        PyTuple_SetItem(rgba_args, 3, PyFloat_FromDouble(color.alpha));
-
-        result = PyObject_CallObject(rgba_type, rgba_args);
-
-        Py_DECREF(rgba_args);
-
-    }
+        result = create_gdk_rgba(&color);
 
     else
-    {
- done:
-        result = Py_None;
-        Py_INCREF(result);
-    }
+        result = NULL;
 
     return result;
 
diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c
index b2ecbec..92a5db9 100644
--- a/plugins/pychrysalide/helpers.c
+++ b/plugins/pychrysalide/helpers.c
@@ -1299,6 +1299,130 @@ int convert_to_gtk_container(PyObject *arg, void *dst)
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : color = couleur dans sa définition native à copier.          *
+*                                                                             *
+*  Description : Construit un objet Python pour une couleur RGBA.             *
+*                                                                             *
+*  Retour      : Objet Python prêt à emploi ou NULL en cas d'échec.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+PyObject *create_gdk_rgba(const GdkRGBA *color)
+{
+    PyObject *result;                       /* Coloration à retourner      */
+    PyObject *gdk_mod;                      /* Module Python Gdk           */
+    PyObject *rgba_type;                    /* Classe "GtkRGBA"            */
+    PyObject *rgba_args;                    /* Arguments pour l'appel      */
+
+    result = NULL;
+
+    gdk_mod = PyImport_ImportModule("gi.repository.Gdk");
+
+    if (gdk_mod == NULL)
+    {
+        PyErr_SetString(PyExc_TypeError, "unable to find the Gtk Python module");
+        goto done;
+    }
+
+    rgba_type = PyObject_GetAttrString(gdk_mod, "RGBA");
+
+    Py_DECREF(gdk_mod);
+
+    rgba_args = PyTuple_New(4);
+    PyTuple_SetItem(rgba_args, 0, PyFloat_FromDouble(color->red));
+    PyTuple_SetItem(rgba_args, 1, PyFloat_FromDouble(color->green));
+    PyTuple_SetItem(rgba_args, 2, PyFloat_FromDouble(color->blue));
+    PyTuple_SetItem(rgba_args, 3, PyFloat_FromDouble(color->alpha));
+
+    result = PyObject_CallObject(rgba_type, rgba_args);
+
+    Py_DECREF(rgba_args);
+
+ done:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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 instance de couleur RGBA.              *
+*                                                                             *
+*  Retour      : Bilan de l'opération, voire indications supplémentaires.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int convert_to_gdk_rgba(PyObject *arg, void *dst)
+{
+    int result;                             /* Bilan à retourner           */
+    PyObject *gdk_mod;                      /* Module Python Gdk           */
+    PyObject *rgba_type;                    /* Module "RGBA"               */
+    int ret;                                /* Bilan d'une conversion      */
+    PyObject *value;                        /* Valeur d'une composante     */
+
+    result = 0;
+
+    gdk_mod = PyImport_ImportModule("gi.repository.Gdk");
+
+    if (gdk_mod == NULL)
+    {
+        PyErr_SetString(PyExc_TypeError, "unable to find the Gdk Python module");
+        goto done;
+    }
+
+    rgba_type = PyObject_GetAttrString(gdk_mod, "RGBA");
+
+    Py_DECREF(gdk_mod);
+
+    ret = PyObject_TypeCheck(arg, (PyTypeObject *)rgba_type);
+
+    Py_DECREF(rgba_type);
+
+    if (!ret)
+    {
+        PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to GDK RGBA color");
+        goto done;
+    }
+
+    value = PyObject_GetAttrString(arg, "red");
+    assert(PyFloat_Check(value));
+
+    ((GdkRGBA *)dst)->red = PyFloat_AsDouble(value);
+
+    value = PyObject_GetAttrString(arg, "blue");
+    assert(PyFloat_Check(value));
+
+    ((GdkRGBA *)dst)->blue = PyFloat_AsDouble(value);
+
+    value = PyObject_GetAttrString(arg, "green");
+    assert(PyFloat_Check(value));
+
+    ((GdkRGBA *)dst)->green = PyFloat_AsDouble(value);
+
+    value = PyObject_GetAttrString(arg, "alpha");
+    assert(PyFloat_Check(value));
+
+    ((GdkRGBA *)dst)->alpha = PyFloat_AsDouble(value);
+
+    result = 1;
+
+ done:
+
+    return result;
+
+}
+
+
 
 /* ---------------------------------------------------------------------------------- */
 /*                         TRANSFERT DES VALEURS CONSTANTES                           */
diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h
index 226071c..72a5489 100644
--- a/plugins/pychrysalide/helpers.h
+++ b/plugins/pychrysalide/helpers.h
@@ -29,6 +29,7 @@
 #include <assert.h>
 #include <glib-object.h>
 #include <stdbool.h>
+#include <gdk/gdk.h>
 
 
 
@@ -225,6 +226,12 @@ int convert_to_gtk_widget(PyObject *, void *);
 /* Tente de convertir en instance de conteneur GTK. */
 int convert_to_gtk_container(PyObject *, void *);
 
+/* Construit un objet Python pour une couleur RGBA. */
+PyObject *create_gdk_rgba(const GdkRGBA *);
+
+/* Tente de convertir en instance de couleur RGBA. */
+int convert_to_gdk_rgba(PyObject *, void *);
+
 
 
 /* ----------------------- TRANSFERT DES VALEURS CONSTANTES ------------------------- */
diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index df05de3..2ab27f0 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -9,6 +9,7 @@ libglibext_la_SOURCES =					\
 	bufferline.h bufferline.c			\
 	bufferview.h bufferview.c			\
 	chrysamarshal.h chrysamarshal.c		\
+	configuration-int.h					\
 	configuration.h configuration.c		\
 	delayed-int.h						\
 	delayed.h delayed.c					\
diff --git a/src/glibext/configuration-int.h b/src/glibext/configuration-int.h
new file mode 100644
index 0000000..2ddeb4f
--- /dev/null
+++ b/src/glibext/configuration-int.h
@@ -0,0 +1,121 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * configuration-int.h - accès interne aux éléments de configuration du programme
+ *
+ * Copyright (C) 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_CONFIGURATION_INT_H
+#define _GLIBEXT_CONFIGURATION_INT_H
+
+
+#include "configuration.h"
+
+
+#include "../common/fnv1a.h"
+
+
+
+/* ---------------------------- ELEMENT DE CONFIGURATION ---------------------------- */
+
+
+/* Valeurs supportées par les paramètres */
+typedef union _param_value
+{
+    bool boolean;                           /* Valeur booléenne            */
+    int integer;                            /* Valeur entière              */
+    unsigned long ulong;                    /* Valeur entière positive     */
+    char *string;                           /* Chaîne de caractères        */
+    GdkRGBA color;                          /* Couleur avec transparence   */
+
+} param_value;
+
+/* Configuration générique quelconque (instance) */
+struct _GCfgParam
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    char *path;                             /* Chemin d'accès XML          */
+    fnv64_t hash;                           /* Empreinte pour accès rapide */
+
+    ConfigParamType type;                   /* Type de valeur              */
+
+    ConfigParamState cached_state;          /* Etat du paramétrage         */
+
+    param_value def;                        /* Valeur par défaut           */
+    bool def_empty;                         /* Non défini par défaut ?     */
+    param_value cur;                        /* Valeur courante             */
+    bool cur_empty;                         /* Actuellement non défini ?   */
+
+};
+
+/* Configuration générique quelconque (classe) */
+struct _GCfgParamClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+    /* Signaux */
+
+    void (* modified) (GCfgParam *);
+
+};
+
+
+/* Construit un paramètre de configuration. */
+void g_config_param_build(GCfgParam *, const char *, ConfigParamType, const param_value *);
+
+/* Construit un paramètre de configuration sans valeur. */
+void g_config_param_build_empty(GCfgParam *, const char *, ConfigParamType);
+
+
+
+/* ----------------------- GESTION GENERIQUE DE CONFIGURATION ----------------------- */
+
+
+/* Configuration générique quelconque (instance) */
+struct _GGenConfig
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    char *filename;                         /* CHemin d'accès complet      */
+
+    GList *groups;                          /* Groupes d'éléments non fixés*/
+    GList *params;                          /* Eléments de configuration   */
+    GRWLock params_access;                  /* Verrou de protection        */
+
+};
+
+/* Configuration générique quelconque (classe) */
+struct _GGenConfigClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+    /* Signaux */
+
+    void (* modified) (GGenConfig *, GCfgParam *);
+
+};
+
+
+/* Crée un gestionnaire configuration générique. */
+void g_generic_config_build(GGenConfig *, const char *);
+
+
+
+#endif  /* _GLIBEXT_CONFIGURATION_INT_H */
diff --git a/src/glibext/configuration.c b/src/glibext/configuration.c
index 7fd9a98..1fa2968 100644
--- a/src/glibext/configuration.c
+++ b/src/glibext/configuration.c
@@ -33,9 +33,9 @@
 #include <unistd.h>
 
 
+#include "configuration-int.h"
 #include "../common/cpp.h"
 #include "../common/extstr.h"
-#include "../common/fnv1a.h"
 #include "../common/io.h"
 #include "../common/xdg.h"
 #include "../common/xml.h"
@@ -45,48 +45,6 @@
 /* ---------------------------- ELEMENT DE CONFIGURATION ---------------------------- */
 
 
-/* Valeurs supportées par les paramètres */
-typedef union _param_value
-{
-    bool boolean;                           /* Valeur booléenne            */
-    int integer;                            /* Valeur entière              */
-    unsigned long ulong;                    /* Valeur entière positive     */
-    char *string;                           /* Chaîne de caractères        */
-    GdkRGBA color;                          /* Couleur avec transparence   */
-
-} param_value;
-
-/* Configuration générique quelconque (instance) */
-struct _GCfgParam
-{
-    GObject parent;                         /* A laisser en premier        */
-
-    char *path;                             /* Chemin d'accès XML          */
-    fnv64_t hash;                           /* Empreinte pour accès rapide */
-
-    ConfigParamType type;                   /* Type de valeur              */
-
-    ConfigParamState cached_state;          /* Etat du paramétrage         */
-
-    param_value def;                        /* Valeur par défaut           */
-    bool def_empty;                         /* Non défini par défaut ?     */
-    param_value cur;                        /* Valeur courante             */
-    bool cur_empty;                         /* Actuellement non défini ?   */
-
-};
-
-/* Configuration générique quelconque (classe) */
-struct _GCfgParamClass
-{
-    GObjectClass parent;                    /* A laisser en premier        */
-
-    /* Signaux */
-
-    void (* modified) (GCfgParam *);
-
-};
-
-
 /* Initialise la classe des blocs de données binaires. */
 static void g_config_param_class_init(GCfgParamClass *);
 
@@ -148,31 +106,6 @@ static void g_config_group_load(GCfgGroup *, GGenConfig *, xmlXPathContextPtr);
 /* ----------------------- GESTION GENERIQUE DE CONFIGURATION ----------------------- */
 
 
-/* Configuration générique quelconque (instance) */
-struct _GGenConfig
-{
-    GObject parent;                         /* A laisser en premier        */
-
-    char *filename;                         /* CHemin d'accès complet      */
-
-    GList *groups;                          /* Groupes d'éléments non fixés*/
-    GList *params;                          /* Eléments de configuration   */
-    GRWLock params_access;                  /* Verrou de protection        */
-
-};
-
-/* Configuration générique quelconque (classe) */
-struct _GGenConfigClass
-{
-    GObjectClass parent;                    /* A laisser en premier        */
-
-    /* Signaux */
-
-    void (* modified) (GGenConfig *, GCfgParam *);
-
-};
-
-
 /* Initialise la classe des blocs de données binaires. */
 static void g_generic_config_class_init(GGenConfigClass *);
 
@@ -321,51 +254,50 @@ GCfgParam *g_config_param_new(const char *path, ConfigParamType type, ...)
 {
     GCfgParam *result;                      /* Structure à retourner       */
     va_list ap;                             /* Liste d'arguments           */
+    param_value value;                      /* Valeur par défaut           */
 
-    result = g_object_new(G_TYPE_CFG_PARAM, NULL);
-
-    result->path = strdup(path);
-    result->hash = fnv_64a_hash(path);
-
-    result->type = type;
+    result = NULL;
 
     va_start(ap, type);
 
-    switch (result->type)
+    switch (type)
     {
         case CPT_BOOLEAN:
-            result->def.boolean = va_arg(ap, /*bool*/int);
+            value.boolean = va_arg(ap, /*bool*/int);
             break;
 
         case CPT_INTEGER:
-            result->def.integer = va_arg(ap, int);
+            value.integer = va_arg(ap, int);
             break;
 
         case CPT_ULONG:
-            result->def.ulong = va_arg(ap, unsigned long);
+            value.ulong = va_arg(ap, unsigned long);
             break;
 
         case CPT_STRING:
-            result->def.string = va_arg(ap, char *);
-            if (result->def.string != NULL)
-                result->def.string = strdup(result->def.string);
+            value.string = va_arg(ap, char *);
+            if (value.string != NULL)
+                value.string = strdup(value.string);
             break;
 
         case CPT_COLOR:
-            result->def.color = *va_arg(ap, GdkRGBA *);
+            value.color = *va_arg(ap, GdkRGBA *);
             break;
 
         default:
-            g_object_unref(G_OBJECT(result));
-            result = NULL;
             assert(false);
+            goto quick_exit;
             break;
 
     }
 
     va_end(ap);
 
-    g_config_param_reset(result);
+    result = g_object_new(G_TYPE_CFG_PARAM, NULL);
+
+    g_config_param_build(result, path, type, &value);
+
+ quick_exit:
 
     return result;
 
@@ -374,8 +306,37 @@ GCfgParam *g_config_param_new(const char *path, ConfigParamType type, ...)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : path   = chemin d'accès à un paramètre en guise de clef.     *
-*                type   = type de paramètre à installer.                      *
+*  Paramètres  : param = paramètre de configuration à construire.             *
+*                path  = chemin d'accès à un paramètre en guise de clef.      *
+*                type  = type de paramètre à installer.                       *
+*                value = valeur par défaut à appliquer.                       *
+*                                                                             *
+*  Description : Construit un paramètre de configuration.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_config_param_build(GCfgParam *param, const char *path, ConfigParamType type, const param_value *value)
+{
+    param->path = strdup(path);
+    param->hash = fnv_64a_hash(path);
+
+    param->type = type;
+
+    param->def = *value;
+
+    g_config_param_reset(param);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : path = chemin d'accès à un paramètre en guise de clef.       *
+*                type = type de paramètre à installer.                        *
 *                                                                             *
 *  Description : Crée un paramètre de configuration sans valeur.              *
 *                                                                             *
@@ -391,17 +352,38 @@ GCfgParam *g_config_param_new_empty(const char *path, ConfigParamType type)
 
     result = g_object_new(G_TYPE_CFG_PARAM, NULL);
 
-    result->path = strdup(path);
-    result->hash = fnv_64a_hash(path);
+    g_config_param_build_empty(result, path, type);
 
-    result->type = type;
+    return result;
 
-    g_config_param_make_empty(result);
+}
 
-    result->def = result->cur;
-    result->def_empty = true;
 
-    return result;
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : param = paramètre de configuration à construire.             *
+*                path  = chemin d'accès à un paramètre en guise de clef.      *
+*                type  = type de paramètre à installer.                       *
+*                                                                             *
+*  Description : Construit un paramètre de configuration sans valeur.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_config_param_build_empty(GCfgParam *param, const char *path, ConfigParamType type)
+{
+    param->path = strdup(path);
+    param->hash = fnv_64a_hash(path);
+
+    param->type = type;
+
+    g_config_param_make_empty(param);
+
+    param->def = param->cur;
+    param->def_empty = true;
 
 }
 
@@ -645,7 +627,11 @@ const char *g_config_param_get_path(const GCfgParam *param)
 
 ConfigParamType g_config_param_get_ptype(const GCfgParam *param)
 {
-    return param->type;
+    ConfigParamType result;                 /* Type de paramètre à renvoyer*/
+
+    result = param->type;
+
+    return result;
 
 }
 
@@ -892,6 +878,7 @@ void g_config_param_set_value(GCfgParam *param, ...)
 
         case CPT_STRING:
             old_string = param->cur.string;
+
             param->cur.string = va_arg(ap, char *);
             if (param->cur.string != NULL)
                 param->cur.string = strdup(param->cur.string);
@@ -1261,7 +1248,8 @@ static void g_generic_config_dispose(GGenConfig *config)
 
 static void g_generic_config_finalize(GGenConfig *config)
 {
-    free(config->filename);
+    if (config->filename != NULL)
+        free(config->filename);
 
     g_rw_lock_clear(&config->params_access);
 
@@ -1308,21 +1296,42 @@ GGenConfig *g_generic_config_new(void)
 GGenConfig *g_generic_config_new_from_file(const char *name)
 {
     GGenConfig *result;                     /* Structure à retourner       */
-    char *suffix;                           /* Fin du nom de fichier       */
 
     result = g_object_new(G_TYPE_GEN_CONFIG, NULL);
 
+    g_generic_config_build(result, name);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : config = ensemble de paramètres de configuration à manipuler.*
+*                name   = désignation de la configuration.                    *
+*                                                                             *
+*  Description : Crée un gestionnaire configuration générique.                *
+*                                                                             *
+*  Retour      : Elément mis en place.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_generic_config_build(GGenConfig *config, const char *name)
+{
+    char *suffix;                           /* Fin du nom de fichier       */
+
     suffix = strdup("chrysalide");
     suffix = stradd(suffix, G_DIR_SEPARATOR_S);
     suffix = stradd(suffix, name);
     suffix = stradd(suffix, ".xml");
 
-    result->filename = get_xdg_config_dir(suffix);
+    config->filename = get_xdg_config_dir(suffix);
 
     free(suffix);
 
-    return result;
-
 }
 
 
diff --git a/src/glibext/configuration.h b/src/glibext/configuration.h
index 49a289b..afefed1 100644
--- a/src/glibext/configuration.h
+++ b/src/glibext/configuration.h
@@ -52,7 +52,7 @@ typedef enum _ConfigParamType
 typedef enum _ConfigParamState
 {
     CPS_UNDEFINED = (0 << 0),               /* Etat non déterminé          */
-    CPS_CHANGED   = (0 << 1),               /* Modification utilisateur    */
+    CPS_CHANGED   = (1 << 0),               /* Modification utilisateur    */
     CPS_DEFAULT   = (1 << 1),               /* Valeur par défaut           */
     CPS_EMPTY     = (1 << 2)                /* Valeur vide                 */
 
diff --git a/tests/glibext/configuration.py b/tests/glibext/configuration.py
new file mode 100644
index 0000000..786fc9e
--- /dev/null
+++ b/tests/glibext/configuration.py
@@ -0,0 +1,71 @@
+
+import gi
+gi.require_version('Gdk', '3.0')
+from gi.repository import Gdk
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.glibext import ConfigParam
+
+
+class TestConfiguration(ChrysalideTestCase):
+    """TestCase for configuration related items.*"""
+
+
+    def testCfgParamValues(self):
+        """Set and unset configuration parameter values."""
+
+        color = Gdk.RGBA()
+        color.parse('#3465A4')
+
+        param = ConfigParam('config.color', ConfigParam.ConfigParamType.COLOR, color)
+
+        self.assertEqual(param.value, color)
+
+        param.make_empty()
+
+        void = Gdk.RGBA(red=0, green=0, blue=0, alpha=0)
+        self.assertEqual(param.value, void)
+
+        param.value = color
+
+        self.assertEqual(param.value, color)
+
+
+    def testCfgParamStates(self):
+        """Validate all states of an evolving parameter."""
+
+        param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER)
+
+        self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.DEFAULT)
+
+        param.make_empty()
+
+        self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.DEFAULT)
+
+        param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER, 0x123)
+
+        self.assertEqual(param.value, 0x123)
+
+        self.assertEqual(param.state, ConfigParam.ConfigParamState.DEFAULT)
+
+        param.make_empty()
+
+        self.assertEqual(param.state, ConfigParam.ConfigParamState.EMPTY | ConfigParam.ConfigParamState.CHANGED)
+
+        param.value = 0x1
+
+        self.assertEqual(param.state, ConfigParam.ConfigParamState.CHANGED)
+
+        param.reset()
+
+        self.assertEqual(param.state, ConfigParam.ConfigParamState.DEFAULT)
+
+
+    def testCfgParamDesc(self):
+        """Export types and states as strings when needed."""
+
+        param = ConfigParam('config.int', ConfigParam.ConfigParamType.INTEGER)
+
+        self.assertTrue('|' in str(param.state))
+
+        self.assertTrue('.' in str(param.type))
-- 
cgit v0.11.2-87-g4458