From 421c9d8b228f4926fabe06a19fda86d9023f1e96 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 9 May 2018 15:33:10 +0200
Subject: Loaded binary contents using a dedicated global work group.

---
 src/analysis/project.c | 989 ++++++++++++++++++++++++++++---------------------
 src/core/queue.c       |  10 +-
 src/core/queue.h       |   3 +-
 3 files changed, 580 insertions(+), 422 deletions(-)

diff --git a/src/analysis/project.c b/src/analysis/project.c
index d2228e2..13887ee 100644
--- a/src/analysis/project.c
+++ b/src/analysis/project.c
@@ -37,25 +37,14 @@
 #include "../core/global.h"
 #include "../core/logs.h"
 #include "../core/params.h"
+#include "../core/queue.h"
+#include "../glibext/delayed-int.h"
 
 
 
 /* ------------------------- DEFINITION D'UN PROJET INTERNE ------------------------- */
 
 
-/* Suivi du chargement de contenus binaires */
-typedef struct _loading_params
-{
-    const wgroup_id_t **exp_wids;           /* Identifiants d'exploration  */
-    size_t exp_count;                       /* Quantitié d'identifiants    */
-
-    size_t resolved;                        /* Compteur de résolutions     */
-
-    xmlDoc *xdoc;                           /* Structure XML chargée ?     */
-    xmlXPathContext *context;               /* Eventuel contexte XML       */
-
-} loading_params;
-
 /* Projet d'étude regroupant les binaires analysés (instance) */
 struct _GStudyProject
 {
@@ -63,10 +52,6 @@ struct _GStudyProject
 
     char *filename;                         /* Lieu d'enregistrement       */
 
-    loading_params *ld_params;              /* Infos d'accompagnement      */
-    size_t ld_count;                        /* Quantité de ces infos       */
-    GMutex ld_mutex;                        /* Encadrement des accès       */
-
     GLoadedContent **contents;              /* Contenus chargés et intégrés*/
     size_t count;                           /* Quantité de ces contenus    */
     GMutex mutex;                           /* Encadrement des accès       */
@@ -104,26 +89,83 @@ static void g_study_project_finalize(GStudyProject *);
 /* ------------------------ INTEGRATION DE CONTENUS BINAIRES ------------------------ */
 
 
-/* Prépare le suivi d'une nouvelle phase d'intégration. */
-static loading_params *g_study_project_prepare_content_loading(GStudyProject *);
+/* Assure l'intégration de contenus listés dans du XML. */
+static void g_study_project_recover_binary_contents(GStudyProject *, xmlDoc *, xmlXPathContext *);
 
-/*  Efface le suivi d'une phase d'intégration obsolète. */
-static void g_study_project_destroy_content_loading(GStudyProject *, loading_params *);
+/* Réceptionne la recette d'une analyse de contenu. */
+static void on_loaded_content_analyzed(GLoadedContent *, gboolean, GStudyProject *);
 
-/* Retrouve les infos de chargements liées à une exploration. */
-static loading_params *g_study_project_find_exploration(GStudyProject *, wgroup_id_t, const wgroup_id_t **);
 
-/* Assure l'intégration de contenus listés dans du XML. */
-static void g_study_project_recover_binary_contents(GStudyProject *, xmlDoc *, xmlXPathContext *);
+
+/* ------------------------ CHARGEMENTS DE CONTENUS BINAIRES ------------------------ */
+
+
+#define G_TYPE_LOADING_HANDLER            g_loading_handler_get_type()
+#define G_LOADING_HANDLER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_LOADING_HANDLER, GLoadingHandler))
+#define G_IS_LOADING_HANDLER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_LOADING_HANDLER))
+#define G_LOADING_HANDLER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_LOADING_HANDLER, GLoadingHandlerClass))
+#define G_IS_LOADING_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_LOADING_HANDLER))
+#define G_LOADING_HANDLER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_LOADING_HANDLER, GLoadingHandlerClass))
+
+
+/* Chargement de contenus binaires (instance) */
+typedef struct _GLoadingHandler
+{
+    GDelayedWork parent;                    /* A laisser en premier        */
+
+    GStudyProject *project;                 /* Projet à compléter          */
+
+    xmlDoc *xdoc;                           /* Structure XML chargée ?     */
+    xmlXPathContext *context;               /* Eventuel contexte XML       */
+
+    const wgroup_id_t **exp_wids;           /* Identifiants d'exploration  */
+    size_t exp_count;                       /* Quantitié d'identifiants    */
+    size_t resolved;                        /* Compteur de résolutions     */
+    GCond wait_cond;                        /* Réveil d'attente de fin     */
+    GMutex mutex;                           /* Encadrement des accès       */
+
+} GLoadingHandler;
+
+/* Chargement de contenus binaires (classe) */
+typedef struct _GLoadingHandlerClass
+{
+    GDelayedWorkClass parent;               /* A laisser en premier        */
+
+} GLoadingHandlerClass;
+
+
+/* Indique le type défini pour les tâches de chargement de contenus binaires. */
+GType g_loading_handler_get_type(void);
+
+/* Initialise la classe des tâches de chargement de contenus. */
+static void g_loading_handler_class_init(GLoadingHandlerClass *);
+
+/* Initialise une tâche de chargement de contenus binaires. */
+static void g_loading_handler_init(GLoadingHandler *);
+
+/* Supprime toutes les références externes. */
+static void g_loading_handler_dispose(GLoadingHandler *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_loading_handler_finalize(GLoadingHandler *);
+
+/* Crée une tâche de chargement de contenu bianire. */
+static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *, GBinContent *);
+
+/* Crée une tâche de chargement de contenu bianire. */
+static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *, xmlDoc *, xmlXPathContext *);
+
+/* Assure le chargement de contenus binaires en différé. */
+static void g_loading_handler_process(GLoadingHandler *, GtkStatusStack *);
+
+/* Détermine si un encadrement est adapté pour un identifiant. */
+static bool g_loading_handler_check(GLoadingHandler *, wgroup_id_t, const wgroup_id_t **);
 
 /* Note la fin d'une phase d'exploration de contenu. */
-static void on_new_content_explored(GContentExplorer *, wgroup_id_t, GStudyProject *);
+static void on_new_content_explored(GContentExplorer *, wgroup_id_t, GLoadingHandler *);
 
 /* Note la fin d'une phase de resolution de contenu. */
-static void on_new_content_resolved(GContentResolver *, wgroup_id_t, GStudyProject *);
-
-/* Réceptionne la recette d'une analyse de contenu. */
-static void on_loaded_content_analyzed(GLoadedContent *, gboolean, GStudyProject *);
+static void on_new_content_resolved(GContentResolver *, wgroup_id_t, GLoadingHandler *);
 
 
 
@@ -190,27 +232,12 @@ static void g_study_project_class_init(GStudyProjectClass *klass)
 
 static void g_study_project_init(GStudyProject *project)
 {
-    GContentExplorer *explorer;             /* Explorateur de contenus     */
-    GContentResolver *resolver;             /* Resolveur de contenus       */
-
     project->filename = NULL;
 
-    project->ld_params = NULL;
-    project->ld_count = 0;
-    g_mutex_init(&project->ld_mutex);
-
     project->contents = NULL;
     project->count = 0;
     g_mutex_init(&project->mutex);
 
-    explorer = get_current_content_explorer();
-    g_signal_connect(explorer, "explored", G_CALLBACK(on_new_content_explored), project);
-    g_object_unref(G_OBJECT(explorer));
-
-    resolver = get_current_content_resolver();
-    g_signal_connect(resolver, "resolved", G_CALLBACK(on_new_content_resolved), project);
-    g_object_unref(G_OBJECT(resolver));
-
 }
 
 
@@ -228,30 +255,8 @@ static void g_study_project_init(GStudyProject *project)
 
 static void g_study_project_dispose(GStudyProject *project)
 {
-    GContentExplorer *explorer;             /* Explorateur de contenus     */
-    GContentResolver *resolver;             /* Resolveur de contenus       */
     size_t i;                               /* Boucle de parcours          */
 
-    explorer = get_current_content_explorer();
-    g_signal_handlers_disconnect_by_func(explorer, G_CALLBACK(on_new_content_explored), project);
-    g_object_unref(G_OBJECT(explorer));
-
-    resolver = get_current_content_resolver();
-    g_signal_handlers_disconnect_by_func(resolver, G_CALLBACK(on_new_content_resolved), project);
-    g_object_unref(G_OBJECT(resolver));
-
-    g_mutex_lock(&project->ld_mutex);
-
-    while (project->ld_count > 0)
-        g_study_project_destroy_content_loading(project, project->ld_params);
-
-    if (project->ld_params != NULL)
-        free(project->ld_params);
-
-    g_mutex_unlock(&project->ld_mutex);
-
-    g_mutex_clear(&project->ld_mutex);
-
     g_mutex_lock(&project->mutex);
 
     for (i = 0; i < project->count; i++)
@@ -513,36 +518,35 @@ const char *g_study_project_get_filename(const GStudyProject *project)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : project = projet dont le contenu est à compléter.            *
+*                xdoc    = structure XML en cours d'édition.                  *
+*                context = contexte à utiliser pour les recherches.           *
 *                                                                             *
-*  Description : Prépare le suivi d'une nouvelle phase d'intégration.         *
+*  Description : Assure l'intégration de contenus listés dans du XML.         *
 *                                                                             *
-*  Retour      : Nouvelle structure de suivi prête à être complétée.          *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static loading_params *g_study_project_prepare_content_loading(GStudyProject *project)
+static void g_study_project_recover_binary_contents(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context)
 {
-    loading_params *result;             /* Trouvaille à retourner      */
-
-    assert(!g_mutex_trylock(&project->ld_mutex));
+    GLoadingHandler *handler;               /* Encadrement du chargement   */
 
-    project->ld_params = (loading_params *)realloc(project->ld_params,
-                                                   ++project->ld_count * sizeof(loading_params));
+    handler = g_loading_handler_new_recovering(project, xdoc, context);
 
-    result = &project->ld_params[project->ld_count - 1];
-
-    return result;
+    if (handler != NULL)
+        g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(handler), LOADING_WORK_GROUP);
 
 }
 
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : project = projet dont le contenu est à compléter.            *
-*                params  = paramètres de chargemeent à supprimer.             *
+*                content = contenu binaire à mémoriser pour le projet.        *
 *                                                                             *
-*  Description : Efface le suivi d'une phase d'intégration obsolète.          *
+*  Description : Assure l'intégration de contenus binaires dans un projet.    *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -550,105 +554,57 @@ static loading_params *g_study_project_prepare_content_loading(GStudyProject *pr
 *                                                                             *
 ******************************************************************************/
 
-static void g_study_project_destroy_content_loading(GStudyProject *project, loading_params *params)
+void g_study_project_discover_binary_content(GStudyProject *project, GBinContent *content)
 {
-    GContentExplorer *explorer;             /* Explorateur de contenus     */
-    GContentResolver *resolver;             /* Resolveur de contenus       */
-    size_t i;                               /* Boucle de parcours          */
-    size_t index;                           /* Indice des paramètres       */
-
-    assert(!g_mutex_trylock(&project->ld_mutex));
-
-    /* Supression des groupes de travail */
-
-    explorer = get_current_content_explorer();
-    resolver = get_current_content_resolver();
-
-    for (i = 0; i < params->exp_count; i++)
-    {
-        g_content_resolver_delete_group(resolver, *params->exp_wids[i]);
-        g_content_explorer_delete_group(explorer, *params->exp_wids[i]);
-    }
-
-    free(params->exp_wids);
-
-    g_object_unref(G_OBJECT(explorer));
-    g_object_unref(G_OBJECT(resolver));
-
-    /* Fermture de l'éventuel fichier XML de chargement */
+    GLoadingHandler *handler;               /* Encadrement du chargement   */
 
-    if (params->xdoc != NULL)
-        close_xml_file(params->xdoc, params->context);
+    handler = g_loading_handler_new_discovering(project, content);
 
-    /* Réorganisation de la liste */
-
-    index = params - project->ld_params;
-
-    if ((index + 1) < project->ld_count)
-        memmove(&project->ld_params[index], &project->ld_params[index + 1],
-                (project->ld_count - index - 1) * sizeof(loading_params));
-
-    project->ld_params = (loading_params *)realloc(project->ld_params,
-                                                   --project->ld_count * sizeof(loading_params));
+    g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(handler), LOADING_WORK_GROUP);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project = projet dont le contenu est à consulter.            *
-*                wid     = identifiant du groupe d'exploration recherché.     *
-*                ptr     = pointeur vers la valeur d'origine externe.         *
+*  Paramètres  : content = contenu chargé et analysé.                         *
+*                success = bilan d'une analyse menée.                         *
+*                project = projet avide des résultats des opérations.         *
 *                                                                             *
-*  Description : Retrouve les infos de chargements liées à une exploration.   *
+*  Description : Réceptionne la recette d'une analyse de contenu.             *
 *                                                                             *
-*  Retour      : Informations trouvées ou NULL en cas d'échec.                *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static loading_params *g_study_project_find_exploration(GStudyProject *project, wgroup_id_t wid, const wgroup_id_t **ptr)
+static void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStudyProject *project)
 {
-    loading_params *result;             /* Trouvaille à retourner      */
-    const wgroup_id_t *value;           /* Raccourci de confort        */
-    size_t i;                           /* Boucle de parcours #1       */
-    size_t k;                           /* Boucle de parcours #2       */
-
-    assert(!g_mutex_trylock(&project->ld_mutex));
-
-    result = NULL;
-
-    value = NULL;
-
-    for (i = 0; i < project->ld_count && result == NULL; i++)
-        for (k = 0; k < project->ld_params[i].exp_count && result == NULL; k++)
-        {
-            value = project->ld_params[i].exp_wids[k];
-
-            if (*value == wid)
-                result = &project->ld_params[i];
+    const char *desc;                       /* Description du contenu      */
 
-        }
+    desc = g_loaded_content_describe(content, true);
 
-    if (ptr != NULL)
+    if (success)
     {
-        assert(result == NULL || value != NULL);
-        *ptr = (result == NULL ? NULL : value);
+        g_study_project_attach_content(project, content);
+        log_variadic_message(LMT_INFO, _("Content from '%s' has been analyzed successfully!"), desc);
     }
 
-    return result;
+    else
+        log_variadic_message(LMT_ERROR, _("Failed to load '%s'"), desc);
+
+    g_object_ref(G_OBJECT(content));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project = projet dont le contenu est à compléter.            *
-*                xdoc    = structure XML en cours d'édition.                  *
-*                context = contexte à utiliser pour les recherches.           *
+*  Paramètres  : project = project à manipuler.                               *
+*                content = contenu chargé à associer au projet actuel.        *
 *                                                                             *
-*  Description : Assure l'intégration de contenus listés dans du XML.         *
+*  Description : Attache un contenu donné à un projet donné.                  *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -656,78 +612,66 @@ static loading_params *g_study_project_find_exploration(GStudyProject *project,
 *                                                                             *
 ******************************************************************************/
 
-static void g_study_project_recover_binary_contents(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context)
+void g_study_project_attach_content(GStudyProject *project, GLoadedContent *content)
 {
-    loading_params *params;                 /* Informations de chargement  */
-    xmlXPathObjectPtr xobject;              /* Cible d'une recherche       */
-    size_t count;                           /* Nombre de contenus premiers */
-    GContentExplorer *explorer;             /* Explorateur de contenus     */
-    size_t explored;                        /* Qté. d'explorations lancées */
-    size_t i;                               /* Boucle de parcours          */
-    char *access;                           /* Chemin pour un contenu      */
-    GBinContent *content;                   /* Contenu binaire retrouvé    */
-
-    xobject = get_node_xpath_object(context, "/ChrysalideProject/RootContents/Content");
-
-    count = XPATH_OBJ_NODES_COUNT(xobject);
-
-    if (count > 0)
-    {
-        explorer = get_current_content_explorer();
-
-        g_mutex_lock(&project->ld_mutex);
-
-        params = g_study_project_prepare_content_loading(project);
-
-        params->exp_wids = (const wgroup_id_t **)malloc(count * sizeof(wgroup_id_t *));
+    g_mutex_lock(&project->mutex);
 
-        params->resolved = 0;
+    project->contents = (GLoadedContent **)realloc(project->contents,
+                                                   ++project->count * sizeof(GLoadedContent *));
 
-        params->xdoc = xdoc;
-        params->context = context;
+    project->contents[project->count - 1] = content;
+    g_object_ref(G_OBJECT(content));
 
-        explored = 0;
+    g_mutex_unlock(&project->mutex);
 
-        for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++)
-        {
-            asprintf(&access, "/ChrysalideProject/RootContents/Content[position()=%zu]", i + 1);
+    g_signal_emit_by_name(project, "content-added", content);
 
-            content = g_binary_content_new_from_xml(context, access, project->filename);
+}
 
-            free(access);
 
-            if (content == NULL)
-            {
-                log_variadic_message(LMT_ERROR, _("Unable to load the root content #%zu ; skipping..."), i);
-                continue;
-            }
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : project = project à manipuler.                               *
+*                content = contenu chargé à dissocier du projet actuel.       *
+*                                                                             *
+*  Description : Détache un contenu donné d'un projet donné.                  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-            params->exp_wids[explored++] = g_content_explorer_create_group(explorer, content);
+void g_study_project_detach_content(GStudyProject *project, GLoadedContent *content)
+{
+    size_t i;                               /* Boucle de parcours          */
 
-            g_object_unref(G_OBJECT(content));
+    g_mutex_lock(&project->mutex);
 
-        }
+    for (i = 0; i < project->count; i++)
+        if (project->contents[i] == content) break;
 
-        params->exp_count = explored;
+    if ((i + 1) < project->count)
+        memmove(&project->contents[i], &project->contents[i + 1],
+                (project->count - i - 1) * sizeof(GLoadedContent *));
 
-        g_mutex_unlock(&project->ld_mutex);
+    project->contents = (GLoadedContent **)realloc(project->contents,
+                                                   --project->count * sizeof(GLoadedContent *));
 
-        g_object_unref(G_OBJECT(explorer));
+    g_mutex_unlock(&project->mutex);
 
-    }
+    g_signal_emit_by_name(project, "content-removed", content);
 
-    if(xobject != NULL)
-        xmlXPathFreeObject(xobject);
+    g_object_unref(G_OBJECT(content));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project = projet dont le contenu est à compléter.            *
-*                content = contenu binaire à mémoriser pour le projet.        *
+*  Paramètres  : project = projet dont le contenu est à afficher.             *
 *                                                                             *
-*  Description : Assure l'intégration de contenus binaires dans un projet.    *
+*  Description : Met en place un projet à l'écran.                            *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -735,41 +679,30 @@ static void g_study_project_recover_binary_contents(GStudyProject *project, xmlD
 *                                                                             *
 ******************************************************************************/
 
-void g_study_project_discover_binary_content(GStudyProject *project, GBinContent *content)
+void g_study_project_display(const GStudyProject *project)
 {
-    loading_params *params;                 /* Informations de chargement  */
-    GContentExplorer *explorer;             /* Explorateur de contenus     */
-
-    explorer = get_current_content_explorer();
-
-    g_mutex_lock(&project->ld_mutex);
-
-    params = g_study_project_prepare_content_loading(project);
-
-    params->exp_wids = (const wgroup_id_t **)malloc(sizeof(wgroup_id_t *));
-    params->exp_count = 1;
-
-    params->resolved = 0;
-
-    params->xdoc = NULL;
-    params->context = NULL;
-
-    params->exp_wids[0] = g_content_explorer_create_group(explorer, content);
+#if 0
+    size_t i;                               /* Boucle de parcours #1       */
+    loaded_binary *handled;                 /* Binaire prise en compte     */
+    size_t j;                               /* Boucle de parcours #2       */
 
-    g_mutex_unlock(&project->ld_mutex);
+    for (i = 0; i < project->binaries_count; i++)
+    {
+        handled = project->binaries[i];
 
-    g_object_unref(G_OBJECT(explorer));
+        for (j = 0; j < handled->count; j++)
+            g_panel_item_dock(handled->items[j]);
 
+    }
+#endif
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : explorer = gestionnaire d'explorations à consulter.          *
-*                wid      = groupe d'exploration concerné.                    *
-*                project  = projet avide des résultats des opérations.        *
+*  Paramètres  : project = projet dont le contenu est à cacher.               *
 *                                                                             *
-*  Description : Note la fin d'une phase d'exploration de contenu.            *
+*  Description : Supprime de l'écran un projet en place.                      *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -777,182 +710,187 @@ void g_study_project_discover_binary_content(GStudyProject *project, GBinContent
 *                                                                             *
 ******************************************************************************/
 
-static void on_new_content_explored(GContentExplorer *explorer, wgroup_id_t wid, GStudyProject *project)
+void g_study_project_hide(const GStudyProject *project)
 {
-    const wgroup_id_t *wid_ptr;             /* Référence vers l'origine    */
-    loading_params *params;                 /* Informations de chargement  */
-    GBinContent **available;                /* Contenus binaires présents  */
-    size_t count;                           /* Quantité de ces contenus    */
-    GContentResolver *resolver;             /* Resolveur de contenus       */
-    size_t i;                               /* Boucle de parcours          */
+#if 0
+    size_t i;                               /* Boucle de parcours #1       */
+    loaded_binary *handled;                 /* Binaire prise en compte     */
+    size_t j;                               /* Boucle de parcours #2       */
 
-    g_mutex_lock(&project->ld_mutex);
-
-    params = g_study_project_find_exploration(project, wid, &wid_ptr);
-
-    /* S'il s'agit bien d'une exploration nouvelle */
-    if (params != NULL)
+    for (i = 0; i < project->binaries_count; i++)
     {
-        available = g_content_explorer_get_all(explorer, wid, &count);
-        assert(count > 0);
-
-        resolver = get_current_content_resolver();
-
-        g_content_resolver_create_group(resolver, wid_ptr, available, count);
-
-        g_object_unref(G_OBJECT(resolver));
-
-        for (i = 0; i < count; i++)
-           g_object_unref(G_OBJECT(available[i]));
+        handled = project->binaries[i];
 
-        free(available);
+        for (j = 0; j < handled->count; j++)
+            g_panel_item_undock(handled->items[j]);
 
     }
-
-    g_mutex_unlock(&project->ld_mutex);
-
+#endif
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : resolver = gestionnaire de résolutions à consulter.          *
-*                wid      = groupe d'exploration concerné.                    *
-*                project  = projet avide des résultats des opérations.        *
+*  Paramètres  : project = projet dont le contenu est à afficher.             *
+*                count = nombre de contenus pris en compte. [OUT]             *
 *                                                                             *
-*  Description : Note la fin d'une phase de resolution de contenu.            *
+*  Description : Fournit l'ensemble des contenus associés à un projet.        *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Liste à libérer de la mémoire.                               *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, GStudyProject *project)
+GLoadedContent **g_study_project_get_contents(GStudyProject *project, size_t *count)
 {
-    loading_params *params;                 /* Informations de chargement  */
-    GLoadedContent **available;             /* Contenus chargés valables   */
-    size_t count;                           /* Quantité de ces contenus    */
+    GLoadedContent **result;                /* Tableau à retourner         */
     size_t i;                               /* Boucle de parcours          */
-    GBinContent *content;                   /* Contenu brut à manipuler    */
-    const gchar *hash;                      /* Empreinte d'un contenu      */
-    const char *format;                     /* Format associé à un élément */
-    char *access;                           /* Chemin pour une sous-config.*/
-    xmlXPathObjectPtr xobject;              /* Cible d'une recherche       */
-    bool status;                            /* Bilan d'une restauration    */
 
-    g_mutex_lock(&project->ld_mutex);
+    g_mutex_lock(&project->mutex);
 
-    params = g_study_project_find_exploration(project, wid, NULL);
+    *count = project->count;
+    result = (GLoadedContent **)calloc(*count, sizeof(GLoadedContent *));
 
-    /* S'il s'agit bien d'une exploration nouvelle */
-    if (params != NULL)
+    for (i = 0; i < *count; i++)
     {
-        available = g_content_resolver_get_all(resolver, wid, &count);
+        result[i] = project->contents[i];
+        g_object_ref(G_OBJECT(result[i]));
+    }
 
-        /* Rechargement à partir d'XML ? */
-        if (params->xdoc != NULL)
-        {
-            assert(params->context != NULL);
+    g_mutex_unlock(&project->mutex);
 
-            for (i = 0; i < count; i++)
-            {
-                content = g_loaded_content_get_content(available[i]);
-                hash = g_binary_content_get_checksum(content);
-                g_object_unref(G_OBJECT(content));
+    return result;
 
-                format = g_loaded_content_get_format_name(available[i]);
+}
 
-                asprintf(&access, "/ChrysalideProject/LoadedContents/Content[@hash='%s' and @format='%s']",
-                         hash, format);
 
-                xobject = get_node_xpath_object(params->context, access);
 
-                if (XPATH_OBJ_NODES_COUNT(xobject) > 0)
-                {
+/* ---------------------------------------------------------------------------------- */
+/*                          CHARGEMENTS DE CONTENUS BINAIRES                          */
+/* ---------------------------------------------------------------------------------- */
 
-                    status = g_loaded_content_restore(available[i], params->xdoc, params->context, access);
 
-                    if (!status)
-                        log_variadic_message(LMT_ERROR,
-                                             _("Unable to reload binary from XML (hash=%s) ; skipping..."), hash);
+/* Indique le type défini pour les tâches de chargement de contenus binaires. */
+G_DEFINE_TYPE(GLoadingHandler, g_loading_handler, G_TYPE_DELAYED_WORK);
 
-                    else
-                    {
-                        /**
-                         * S'il s'agit des résultats de la dernière exploration,
-                         * alors les groupes contenant les éléments chargés vont
-                         * être libéré, potentiellement pendant l'analyse.
-                         *
-                         * On temporise en incrémentant les références.
-                         */
-                        g_object_ref(G_OBJECT(available[i]));
 
-                        g_signal_connect(available[i], "analyzed", G_CALLBACK(on_loaded_content_analyzed), project);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des tâches de chargement de contenus.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-                        g_loaded_content_analyze(available[i]);
+static void g_loading_handler_class_init(GLoadingHandlerClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GDelayedWorkClass *work;                /* Version en classe parente   */
 
-                    }
+    object = G_OBJECT_CLASS(klass);
 
-                }
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_loading_handler_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_loading_handler_finalize;
 
-                free(access);
+    work = G_DELAYED_WORK_CLASS(klass);
 
-                if(xobject != NULL)
-                    xmlXPathFreeObject(xobject);
+    work->run = (run_task_fc)g_loading_handler_process;
 
-                g_object_unref(G_OBJECT(available[i]));
+}
 
-            }
 
-        }
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : handler = instance à initialiser.                            *
+*                                                                             *
+*  Description : Initialise une tâche de chargement de contenus binaires.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-        /* Découverte(s) initiale(s) ? */
-        else
-        {
-            for (i = 0; i < count; i++)
-            {
-                /**
-                 * S'il s'agit des résultats de la dernière exploration,
-                 * alors les groupes contenant les éléments chargés vont
-                 * être libéré, potentiellement pendant l'analyse.
-                 *
-                 * On temporise en incrémentant les références.
-                 */
-                g_object_ref(G_OBJECT(available[i]));
+static void g_loading_handler_init(GLoadingHandler *handler)
+{
+    GContentExplorer *explorer;             /* Explorateur de contenus     */
+    GContentResolver *resolver;             /* Resolveur de contenus       */
 
-                g_signal_connect(available[i], "analyzed", G_CALLBACK(on_loaded_content_analyzed), project);
+    g_cond_init(&handler->wait_cond);
+    g_mutex_init(&handler->mutex);
 
-                g_loaded_content_analyze(available[i]);
+    explorer = get_current_content_explorer();
+    g_signal_connect(explorer, "explored", G_CALLBACK(on_new_content_explored), handler);
+    g_object_unref(G_OBJECT(explorer));
 
-                g_object_unref(G_OBJECT(available[i]));
+    resolver = get_current_content_resolver();
+    g_signal_connect(resolver, "resolved", G_CALLBACK(on_new_content_resolved), handler);
+    g_object_unref(G_OBJECT(resolver));
 
-            }
+}
 
-        }
 
-        /* Dans tous les cas... */
-        if (available != NULL)
-            free(available);
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : handler = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-        /* Si c'était la dernière résolution... */
-        if (++params->resolved == params->exp_count)
-            g_study_project_destroy_content_loading(project, params);
+static void g_loading_handler_dispose(GLoadingHandler *handler)
+{
+    GContentExplorer *explorer;             /* Explorateur de contenus     */
+    GContentResolver *resolver;             /* Resolveur de contenus       */
+    size_t i;                               /* Boucle de parcours          */
+
+    /* Supression des groupes de travail */
 
+    explorer = get_current_content_explorer();
+    resolver = get_current_content_resolver();
+
+    g_signal_handlers_disconnect_by_func(explorer, G_CALLBACK(on_new_content_explored), handler);
+    g_signal_handlers_disconnect_by_func(resolver, G_CALLBACK(on_new_content_resolved), handler);
+
+    g_mutex_lock(&handler->mutex);
+
+    for (i = 0; i < handler->exp_count; i++)
+    {
+        g_content_resolver_delete_group(resolver, *handler->exp_wids[i]);
+        g_content_explorer_delete_group(explorer, *handler->exp_wids[i]);
     }
 
-    g_mutex_unlock(&project->ld_mutex);
+    g_mutex_unlock(&handler->mutex);
+
+    g_object_unref(G_OBJECT(explorer));
+    g_object_unref(G_OBJECT(resolver));
+
+    /* Nettoyage plus général */
+
+    g_mutex_clear(&handler->mutex);
+    g_cond_clear(&handler->wait_cond);
+
+    g_object_unref(G_OBJECT(handler->project));
+
+    G_OBJECT_CLASS(g_loading_handler_parent_class)->dispose(G_OBJECT(handler));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : content = contenu chargé et analysé.                         *
-*                success = bilan d'une analyse menée.                         *
-*                project = projet avide des résultats des opérations.         *
+*  Paramètres  : handler = instance d'objet GLib à traiter.                   *
 *                                                                             *
-*  Description : Réceptionne la recette d'une analyse de contenu.             *
+*  Description : Procède à la libération totale de la mémoire.                *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -960,99 +898,160 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
 *                                                                             *
 ******************************************************************************/
 
-static void on_loaded_content_analyzed(GLoadedContent *content, gboolean success, GStudyProject *project)
+static void g_loading_handler_finalize(GLoadingHandler *handler)
 {
-    const char *desc;                       /* Description du contenu      */
-
-    desc = g_loaded_content_describe(content, true);
+    free(handler->exp_wids);
 
-    if (success)
-    {
-        g_study_project_attach_content(project, content);
-        log_variadic_message(LMT_INFO, _("Content from '%s' has been analyzed successfully!"), desc);
-    }
+    /* Fermture de l'éventuel fichier XML de chargement */
 
-    else
-        log_variadic_message(LMT_ERROR, _("Failed to load '%s'"), desc);
+    if (handler->xdoc != NULL)
+        close_xml_file(handler->xdoc, handler->context);
 
-    g_object_ref(G_OBJECT(content));
+    G_OBJECT_CLASS(g_loading_handler_parent_class)->finalize(G_OBJECT(handler));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project = project à manipuler.                               *
-*                content = contenu chargé à associer au projet actuel.        *
+*  Paramètres  : project = projet dont le contenu est à compléter.            *
+*                content = contenu binaire à mémoriser pour le projet.        *
 *                                                                             *
-*  Description : Attache un contenu donné à un projet donné.                  *
+*  Description : Crée une tâche de chargement de contenu bianire.             *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Tâche créée.                                                 *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_study_project_attach_content(GStudyProject *project, GLoadedContent *content)
+static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project, GBinContent *content)
 {
-    g_mutex_lock(&project->mutex);
+    GLoadingHandler *result;                /* Tâche à retourner           */
+    GContentExplorer *explorer;             /* Explorateur de contenus     */
 
-    project->contents = (GLoadedContent **)realloc(project->contents,
-                                                   ++project->count * sizeof(GLoadedContent *));
+    result = g_object_new(G_TYPE_LOADING_HANDLER, NULL);
 
-    project->contents[project->count - 1] = content;
-    g_object_ref(G_OBJECT(content));
+    result->project = project;
+    g_object_ref(G_OBJECT(result->project));
 
-    g_mutex_unlock(&project->mutex);
+    result->xdoc = NULL;
+    result->context = NULL;
 
-    g_signal_emit_by_name(project, "content-added", content);
+    result->exp_wids = (const wgroup_id_t **)malloc(sizeof(wgroup_id_t *));
+    result->exp_count = 1;
+
+    result->resolved = 0;
+
+    explorer = get_current_content_explorer();
+
+    g_mutex_lock(&result->mutex);
+
+    result->exp_wids[0] = g_content_explorer_create_group(explorer, content);
+
+    g_mutex_unlock(&result->mutex);
+
+    g_object_unref(G_OBJECT(explorer));
+
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project = project à manipuler.                               *
-*                content = contenu chargé à dissocier du projet actuel.       *
+*  Paramètres  : project = projet dont le contenu est à compléter.            *
+*                xdoc    = structure XML en cours d'édition.                  *
+*                context = contexte à utiliser pour les recherches.           *
 *                                                                             *
-*  Description : Détache un contenu donné d'un projet donné.                  *
+*  Description : Crée une tâche de chargement de contenu bianire.             *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Tâche créée.                                                 *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_study_project_detach_content(GStudyProject *project, GLoadedContent *content)
+static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context)
 {
+    GLoadingHandler *result;                /* Tâche à retourner           */
+    xmlXPathObjectPtr xobject;              /* Cible d'une recherche       */
+    size_t count;                           /* Nombre de contenus premiers */
+    GContentExplorer *explorer;             /* Explorateur de contenus     */
+    size_t explored;                        /* Qté. d'explorations lancées */
     size_t i;                               /* Boucle de parcours          */
+    char *access;                           /* Chemin pour un contenu      */
+    GBinContent *content;                   /* Contenu binaire retrouvé    */
 
-    g_mutex_lock(&project->mutex);
+    xobject = get_node_xpath_object(context, "/ChrysalideProject/RootContents/Content");
 
-    for (i = 0; i < project->count; i++)
-        if (project->contents[i] == content) break;
+    count = XPATH_OBJ_NODES_COUNT(xobject);
 
-    if ((i + 1) < project->count)
-        memmove(&project->contents[i], &project->contents[i + 1],
-                (project->count - i - 1) * sizeof(GLoadedContent *));
+    if (count > 0)
+    {
+        result = g_object_new(G_TYPE_LOADING_HANDLER, NULL);
 
-    project->contents = (GLoadedContent **)realloc(project->contents,
-                                                   --project->count * sizeof(GLoadedContent *));
+        result->project = project;
+        g_object_ref(G_OBJECT(result->project));
 
-    g_mutex_unlock(&project->mutex);
+        result->xdoc = xdoc;
+        result->context = context;
 
-    g_signal_emit_by_name(project, "content-removed", content);
+        result->exp_wids = (const wgroup_id_t **)malloc(count * sizeof(wgroup_id_t *));
 
-    g_object_unref(G_OBJECT(content));
+        result->resolved = 0;
+
+        explorer = get_current_content_explorer();
+
+        explored = 0;
+
+        g_mutex_lock(&result->mutex);
+
+        for (i = 0; i < XPATH_OBJ_NODES_COUNT(xobject); i++)
+        {
+            asprintf(&access, "/ChrysalideProject/RootContents/Content[position()=%zu]", i + 1);
+
+            content = g_binary_content_new_from_xml(context, access, project->filename);
+
+            free(access);
+
+            if (content == NULL)
+            {
+                log_variadic_message(LMT_ERROR, _("Unable to load the root content #%zu ; skipping..."), i);
+                continue;
+            }
+
+            result->exp_wids[explored++] = g_content_explorer_create_group(explorer, content);
+
+            g_object_unref(G_OBJECT(content));
+
+        }
+
+        result->exp_count = explored;
+
+        g_mutex_unlock(&result->mutex);
+
+        g_object_unref(G_OBJECT(explorer));
+
+    }
+
+    else
+        result = NULL;
+
+    if(xobject != NULL)
+        xmlXPathFreeObject(xobject);
+
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project = projet dont le contenu est à afficher.             *
+*  Paramètres  : handler = opération de chargement à menuer.                  *
+*                status  = barre de statut à tenir informée.                  *
 *                                                                             *
-*  Description : Met en place un projet à l'écran.                            *
+*  Description : Assure le chargement de contenus binaires en différé.        *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -1060,30 +1059,70 @@ void g_study_project_detach_content(GStudyProject *project, GLoadedContent *cont
 *                                                                             *
 ******************************************************************************/
 
-void g_study_project_display(const GStudyProject *project)
+static void g_loading_handler_process(GLoadingHandler *handler, GtkStatusStack *status)
 {
-#if 0
-    size_t i;                               /* Boucle de parcours #1       */
-    loaded_binary *handled;                 /* Binaire prise en compte     */
-    size_t j;                               /* Boucle de parcours #2       */
+    g_mutex_lock(&handler->mutex);
 
-    for (i = 0; i < project->binaries_count; i++)
+    while (handler->resolved < handler->exp_count)
+        g_cond_wait(&handler->wait_cond, &handler->mutex);
+
+    g_mutex_unlock(&handler->mutex);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : handler = gestionnaire dont contenu est à consulter.         *
+*                wid     = identifiant du groupe d'exploration recherché.     *
+*                ptr     = pointeur vers la valeur d'origine externe.         *
+*                                                                             *
+*  Description : Détermine si un encadrement est adapté pour un identifiant.  *
+*                                                                             *
+*  Retour      : Bilan d'adéquation.                                          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_loading_handler_check(GLoadingHandler *handler, wgroup_id_t wid, const wgroup_id_t **ptr)
+{
+    bool result;                        /* Bilan à retourner           */
+    const wgroup_id_t *value;           /* Raccourci de confort        */
+    size_t i;                           /* Boucle de parcours          */
+
+    assert(!g_mutex_trylock(&handler->mutex));
+
+    result = false;
+
+    value = NULL;
+
+    for (i = 0; i < handler->exp_count && !result; i++)
     {
-        handled = project->binaries[i];
+        value = handler->exp_wids[i];
 
-        for (j = 0; j < handled->count; j++)
-            g_panel_item_dock(handled->items[j]);
+        result = (*value == wid);
 
     }
-#endif
+
+    if (ptr != NULL)
+    {
+        assert(!result || value != NULL);
+        *ptr = (result ? value : NULL);
+    }
+
+    return result;
+
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project = projet dont le contenu est à cacher.               *
+*  Paramètres  : explorer = gestionnaire d'explorations à consulter.          *
+*                wid      = groupe d'exploration concerné.                    *
+*                handler  = gestionnaire avide des résultats des opérations.  *
 *                                                                             *
-*  Description : Supprime de l'écran un projet en place.                      *
+*  Description : Note la fin d'une phase d'exploration de contenu.            *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -1091,57 +1130,167 @@ void g_study_project_display(const GStudyProject *project)
 *                                                                             *
 ******************************************************************************/
 
-void g_study_project_hide(const GStudyProject *project)
+static void on_new_content_explored(GContentExplorer *explorer, wgroup_id_t wid, GLoadingHandler *handler)
 {
-#if 0
-    size_t i;                               /* Boucle de parcours #1       */
-    loaded_binary *handled;                 /* Binaire prise en compte     */
-    size_t j;                               /* Boucle de parcours #2       */
+    const wgroup_id_t *wid_ptr;             /* Référence vers l'origine    */
+    GBinContent **available;                /* Contenus binaires présents  */
+    size_t count;                           /* Quantité de ces contenus    */
+    GContentResolver *resolver;             /* Resolveur de contenus       */
+    size_t i;                               /* Boucle de parcours          */
 
-    for (i = 0; i < project->binaries_count; i++)
+    g_mutex_lock(&handler->mutex);
+
+    if (g_loading_handler_check(handler, wid, &wid_ptr))
     {
-        handled = project->binaries[i];
+        available = g_content_explorer_get_all(explorer, wid, &count);
+        assert(count > 0);
 
-        for (j = 0; j < handled->count; j++)
-            g_panel_item_undock(handled->items[j]);
+        resolver = get_current_content_resolver();
+
+        g_content_resolver_create_group(resolver, wid_ptr, available, count);
+
+        g_object_unref(G_OBJECT(resolver));
+
+        for (i = 0; i < count; i++)
+           g_object_unref(G_OBJECT(available[i]));
+
+        free(available);
 
     }
-#endif
+
+    g_mutex_unlock(&handler->mutex);
+
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : project = projet dont le contenu est à afficher.             *
-*                count = nombre de contenus pris en compte. [OUT]             *
+*  Paramètres  : resolver = gestionnaire de résolutions à consulter.          *
+*                wid      = groupe d'exploration concerné.                    *
+*                handler  = gestionnaire avide des résultats des opérations.  *
 *                                                                             *
-*  Description : Fournit l'ensemble des contenus associés à un projet.        *
+*  Description : Note la fin d'une phase de resolution de contenu.            *
 *                                                                             *
-*  Retour      : Liste à libérer de la mémoire.                               *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GLoadedContent **g_study_project_get_contents(GStudyProject *project, size_t *count)
+static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid, GLoadingHandler *handler)
 {
-    GLoadedContent **result;                /* Tableau à retourner         */
+    GLoadedContent **available;             /* Contenus chargés valables   */
+    size_t count;                           /* Quantité de ces contenus    */
     size_t i;                               /* Boucle de parcours          */
+    GBinContent *content;                   /* Contenu brut à manipuler    */
+    const gchar *hash;                      /* Empreinte d'un contenu      */
+    const char *format;                     /* Format associé à un élément */
+    char *access;                           /* Chemin pour une sous-config.*/
+    xmlXPathObjectPtr xobject;              /* Cible d'une recherche       */
+    bool status;                            /* Bilan d'une restauration    */
 
-    g_mutex_lock(&project->mutex);
-
-    *count = project->count;
-    result = (GLoadedContent **)calloc(*count, sizeof(GLoadedContent *));
+    g_mutex_lock(&handler->mutex);
 
-    for (i = 0; i < *count; i++)
+    if (g_loading_handler_check(handler, wid, NULL))
     {
-        result[i] = project->contents[i];
-        g_object_ref(G_OBJECT(result[i]));
-    }
+        available = g_content_resolver_get_all(resolver, wid, &count);
 
-    g_mutex_unlock(&project->mutex);
+        /* Rechargement à partir d'XML ? */
+        if (handler->xdoc != NULL)
+        {
+            assert(handler->context != NULL);
 
-    return result;
+            for (i = 0; i < count; i++)
+            {
+                content = g_loaded_content_get_content(available[i]);
+                hash = g_binary_content_get_checksum(content);
+                g_object_unref(G_OBJECT(content));
+
+                format = g_loaded_content_get_format_name(available[i]);
+
+                asprintf(&access, "/ChrysalideProject/LoadedContents/Content[@hash='%s' and @format='%s']",
+                         hash, format);
+
+                xobject = get_node_xpath_object(handler->context, access);
+
+                if (XPATH_OBJ_NODES_COUNT(xobject) > 0)
+                {
+
+                    status = g_loaded_content_restore(available[i], handler->xdoc, handler->context, access);
+
+                    if (!status)
+                        log_variadic_message(LMT_ERROR,
+                                             _("Unable to reload binary from XML (hash=%s) ; skipping..."), hash);
+
+                    else
+                    {
+                        /**
+                         * S'il s'agit des résultats de la dernière exploration,
+                         * alors les groupes contenant les éléments chargés vont
+                         * être libéré, potentiellement pendant l'analyse.
+                         *
+                         * On temporise en incrémentant les références.
+                         */
+                        g_object_ref(G_OBJECT(available[i]));
+
+                        g_signal_connect(available[i], "analyzed",
+                                         G_CALLBACK(on_loaded_content_analyzed), handler->project);
+
+                        g_loaded_content_analyze(available[i]);
+
+                    }
+
+                }
+
+                free(access);
+
+                if(xobject != NULL)
+                    xmlXPathFreeObject(xobject);
+
+                g_object_unref(G_OBJECT(available[i]));
+
+            }
+
+        }
+
+        /* Découverte(s) initiale(s) ? */
+        else
+        {
+            for (i = 0; i < count; i++)
+            {
+                /**
+                 * S'il s'agit des résultats de la dernière exploration,
+                 * alors les groupes contenant les éléments chargés vont
+                 * être libéré, potentiellement pendant l'analyse.
+                 *
+                 * On temporise en incrémentant les références.
+                 */
+                g_object_ref(G_OBJECT(available[i]));
+
+                g_signal_connect(available[i], "analyzed",
+                                 G_CALLBACK(on_loaded_content_analyzed), handler->project);
+
+                g_loaded_content_analyze(available[i]);
+
+                g_object_unref(G_OBJECT(available[i]));
+
+            }
+
+        }
+
+        /* Dans tous les cas... */
+        if (available != NULL)
+            free(available);
+
+        /* Si c'était la dernière résolution... */
+
+        handler->resolved++;
+
+        g_cond_broadcast(&handler->wait_cond);
+
+    }
+
+    g_mutex_unlock(&handler->mutex);
 
 }
 
diff --git a/src/core/queue.c b/src/core/queue.c
index 615e351..79a87b2 100644
--- a/src/core/queue.c
+++ b/src/core/queue.c
@@ -60,6 +60,13 @@ bool init_global_works(void)
     g_work_queue_define_work_group(queue);
 #endif
 
+#ifndef NDEBUG
+    expected = g_work_queue_define_work_group(queue);
+    assert(expected == LOADING_WORK_GROUP);
+#else
+    g_work_queue_define_work_group(queue);
+#endif
+
     return true;
 
 }
@@ -105,7 +112,8 @@ void wait_for_all_global_works(void)
     GWorkQueue *queue;                      /* Singleton pour tâches       */
 
     static const wgroup_id_t group_ids[] = {
-        DEFAULT_WORK_GROUP
+        DEFAULT_WORK_GROUP,
+        LOADING_WORK_GROUP
     };
 
     queue = get_work_queue();
diff --git a/src/core/queue.h b/src/core/queue.h
index 1984fff..bee16a4 100644
--- a/src/core/queue.h
+++ b/src/core/queue.h
@@ -34,8 +34,9 @@
  */
 
 #define DEFAULT_WORK_GROUP 0
+#define LOADING_WORK_GROUP 1
 
-#define GLOBAL_WORK_GROUPS_COUNT 1
+#define GLOBAL_WORK_GROUPS_COUNT 2
 
 
 /* Met en place les mécanismes de traitements parallèles. */
-- 
cgit v0.11.2-87-g4458