From ecb9ecc486049fe3bec6ecaeeb27f08f67bf0ef0 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 13 Jun 2009 14:05:50 +0000
Subject: Made the GUI offer to change the view of the current analyzed binary.

git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@73 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
---
 ChangeLog                   |  40 +++
 src/editor.c                | 133 +++++---
 src/gtkext/Makefile.am      |   4 +-
 src/gtkext/easygtk.c        |  34 ++
 src/gtkext/easygtk.h        |   3 +
 src/gtkext/gtkbinview-int.h |  49 +++
 src/gtkext/gtkbinview.c     |  30 +-
 src/gtkext/gtkbinview.h     |   3 +
 src/gtkext/gtkblockview.c   | 785 ++++++++++++++++++++++++++++++++++++++++++++
 src/gtkext/gtkblockview.h   |  99 ++++++
 src/gtkext/gtkdockpanel.c   |  51 ++-
 src/gtkext/gtkdockpanel.h   |   6 +
 src/gtkext/gtkgraphview.c   | 110 +++++++
 src/gtkext/gtkgraphview.h   |  56 ++++
 src/gtkext/gtksnippet.c     | 755 ------------------------------------------
 src/gtkext/gtksnippet.h     | 117 -------
 src/project.c               | 156 ++++++++-
 src/project.h               |  18 +
 18 files changed, 1493 insertions(+), 956 deletions(-)
 create mode 100644 src/gtkext/gtkbinview-int.h
 create mode 100644 src/gtkext/gtkblockview.c
 create mode 100644 src/gtkext/gtkblockview.h
 create mode 100644 src/gtkext/gtkgraphview.c
 create mode 100644 src/gtkext/gtkgraphview.h
 delete mode 100644 src/gtkext/gtksnippet.c
 delete mode 100644 src/gtkext/gtksnippet.h

diff --git a/ChangeLog b/ChangeLog
index d13bebf..e978740 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,43 @@
+09-06-13  Cyrille Bagard <nocbos@gmail.com>
+
+	* src/editor.c:
+	Make the GUI offer to change the view of the current analyzed binary.
+
+	* src/gtkext/easygtk.c:
+	* src/gtkext/easygtk.h:
+	Add a function to create a scrolled window.
+
+	* src/gtkext/gtkbinview.c:
+	* src/gtkext/gtkbinview.h:
+	Reorganize the way the binary content is displayed.
+
+	* src/gtkext/gtkbinview-int.h:
+	New entrie: reorganize the way the binary content is displayed.
+
+	* src/gtkext/gtkblockview.c:
+	* src/gtkext/gtkblockview.h:
+	Renamed entries: reorganize the way the binary content is displayed.
+
+	* src/gtkext/gtkdockpanel.c:
+	* src/gtkext/gtkdockpanel.h:
+	Allow to look for a dock item with its name and to replace its content.
+
+	* src/gtkext/gtkgraphview.c:
+	* src/gtkext/gtkgraphview.h:
+	New entries: reorganize the way the binary content is displayed.
+
+	* src/gtkext/gtksnippet.c:
+	* src/gtkext/gtksnippet.h:
+	Deleted entries ; see gtkblockview.[ch].
+
+	* src/gtkext/Makefile.am:
+	Add gtkbinview-int.h, gtkgraphview.[ch] and replace gtksnippet.[ch] by
+	gtkblockview.[ch] in libgtkext_la_SOURCES.
+
+	* src/project.c:
+	* src/project.h:
+	Keep track of all displaying supports for loaded binaries.
+
 09-06-08  Cyrille Bagard <nocbos@gmail.com>
 
 	* src/analysis/binary.c:
diff --git a/src/editor.c b/src/editor.c
index 7185e3f..8c28e68 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -47,7 +47,6 @@
 #include "gtkext/easygtk.h"
 #include "gtkext/gtkbinview.h"
 #include "gtkext/gtkdockpanel.h"
-#include "gtkext/gtksnippet.h"
 #include "format/exe_format.h"
 #include "format/mangling/demangler.h"
 #include "plugins/pglist.h"
@@ -87,12 +86,8 @@ void mcb_file_save_project_as(GtkMenuItem *, gpointer);
 /* Charge un projet récent et met à jour la liste. */
 void mcb_open_recent_project(GtkMenuItem *, gpointer);
 
-
-/* Réagit avec le menu "Affichage -> Vue textuelle". */
-void mcb_view_as_text(GtkCheckMenuItem *, gpointer);
-
-/* Réagit avec le menu "Affichage -> Vue graphique". */
-void mcb_view_as_graph(GtkCheckMenuItem *, gpointer);
+/* Réagit avec le menu "Affichage -> Vue xxx". */
+void mcb_view_change_support(GtkRadioMenuItem *, GObject *);
 
 /* Réagit avec le menu "Affichage -> Adresse virtuelle". */
 void mcb_view_vaddress(GtkCheckMenuItem *, gpointer);
@@ -136,6 +131,10 @@ void update_debug_menu_items(GObject *, gboolean);
 
 
 
+
+
+
+
 void open_last_file(GObject *ref);
 
 
@@ -248,7 +247,7 @@ GtkWidget *create_editor(void)
   GtkWidget *snippet;
   GtkWidget *statusbar1;
 
-  GtkWidget *binview;
+  GtkWidget *view;
 
   GtkWidget *panel;
 
@@ -324,12 +323,14 @@ GtkWidget *create_editor(void)
     menubar = gtk_menu_new();
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menubar);
 
-    submenuitem = qck_create_radio_menu_item(NULL, NULL, NULL, _("Text view"), G_CALLBACK(mcb_view_as_text), result);
+    submenuitem = qck_create_radio_menu_item(NULL, NULL, NULL, _("Text view"), G_CALLBACK(mcb_view_change_support), result);
+    g_object_set_data(G_OBJECT(submenuitem), "kind_of_view", GUINT_TO_POINTER(BVW_BLOCK));
     gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
 
     rgroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(submenuitem));
 
-    submenuitem = qck_create_radio_menu_item(NULL, NULL, rgroup, _("Graph view"), G_CALLBACK(mcb_view_as_graph), result);
+    submenuitem = qck_create_radio_menu_item(NULL, NULL, rgroup, _("Graph view"), G_CALLBACK(mcb_view_change_support), result);
+    g_object_set_data(G_OBJECT(submenuitem), "kind_of_view", GUINT_TO_POINTER(BVW_GRAPH));
     gtk_container_add(GTK_CONTAINER(menubar), submenuitem);
 
     submenuitem = qck_create_menu_separator();
@@ -443,10 +444,12 @@ GtkWidget *create_editor(void)
 
 
     dpanel = gtk_dock_panel_new();
+    g_object_set_data(G_OBJECT(result), "binpanel", dpanel);
     gtk_widget_show(dpanel);
 
     gtk_paned_pack1(GTK_PANED(hpaned1), dpanel, TRUE, TRUE);
 
+#if 0
 
   scrolledwindow2 = gtk_scrolled_window_new (NULL, NULL);
   gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow2), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
@@ -458,16 +461,18 @@ GtkWidget *create_editor(void)
     gtk_dock_panel_add_item(dpanel, ditem);
 
 
-    binview = gtk_binview_new();
-    g_object_set_data(G_OBJECT(result), "binview", binview);
+    view = gtk_graph_view_new();
+    g_object_set_data(G_OBJECT(result), "grahview", view);
     //gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwindow2), binview);
     //gtk_container_add(GTK_CONTAINER(scrolledwindow2), binview);
 
 
+    view = gtk_binview_new();
+    g_object_set_data(G_OBJECT(result), "binview", view);
 
   snippet = gtk_snippet_new();
     g_object_set_data(G_OBJECT(result), "snippet", snippet);
-  gtk_widget_show(binview);
+  gtk_widget_show(view);
   /*
   snippet = gtk_text_view_new ();
   */
@@ -475,20 +480,20 @@ GtkWidget *create_editor(void)
   /*gtk_container_add (GTK_CONTAINER (scrolledwindow2), snippet);*/
   //gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwindow2), snippet);
 
-  gtk_container_add(GTK_CONTAINER(binview), snippet);
+  gtk_container_add(GTK_CONTAINER(view), snippet);
 
 
 
 
 
   //binview = gtk_fixed_new();
-    gtk_widget_show(binview);
+    gtk_widget_show(view);
     //g_object_set_data(G_OBJECT(result), "binview", binview);
-    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwindow2), binview);
+    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwindow2), view);
     //gtk_container_add(GTK_CONTAINER(scrolledwindow2), binview);
 
 
-
+#endif
 
 
 
@@ -712,14 +717,12 @@ void mcb_open_recent_project(GtkMenuItem *menuitem, gpointer data)
 }
 
 
-
-
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : menuitem = élément de menu ayant basculé.                    *
-*                data     = adresse de l'espace de référencement global.      *
+*                ref      = adresse de l'espace de référencement global.      *
 *                                                                             *
-*  Description : Réagit avec le menu "Affichage -> Vue textuelle".            *
+*  Description : Réagit avec le menu "Affichage -> Vue xxx".                  *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -727,39 +730,36 @@ void mcb_open_recent_project(GtkMenuItem *menuitem, gpointer data)
 *                                                                             *
 ******************************************************************************/
 
-void mcb_view_as_text(GtkCheckMenuItem *menuitem, gpointer data)
+void mcb_view_change_support(GtkRadioMenuItem *menuitem, GObject *ref)
 {
-    gboolean active;                        /* Etat de sélection du menu   */
-
-    active = gtk_check_menu_item_get_active(menuitem);
-
-    printf("View as text ? %d\n", active);
+    GSList *group;                          /* Liste de menus radio        */
+    GSList *iter;                           /* Boucle de parcours          */
+    BinaryView view;                        /* Nouvelle vue à présenter    */
+    openida_binary *binary;                 /* Edition courante            */
+    GtkWidget *panel;                       /* Nouveau support à utiliser  */
+    GtkDockPanel *dpanel;                   /* Support de panneaux         */
+    GtkDockItem *ditem;                     /* Panneau avec ses infos.     */
 
+    /* On ne traite qu'une seule fois ! */
+    if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) return;
 
-}
+    group = gtk_radio_menu_item_get_group(menuitem);
 
+    for (iter = group; iter != NULL; iter = g_slist_next(iter))
+    {
+        if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(iter->data))) continue;
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : menuitem = élément de menu ayant basculé.                    *
-*                data     = adresse de l'espace de référencement global.      *
-*                                                                             *
-*  Description : Réagit avec le menu "Affichage -> Vue graphique".            *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+        view = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(iter->data), "kind_of_view"));
 
-void mcb_view_as_graph(GtkCheckMenuItem *menuitem, gpointer data)
-{
-    gboolean active;                        /* Etat de sélection du menu   */
+        binary = (openida_binary *)g_object_get_data(ref, "current_binary");
+        panel = get_view_for_openida_project_binary(get_current_openida_project(), binary, view);
 
-    active = gtk_check_menu_item_get_active(menuitem);
+        dpanel = GTK_DOCK_PANEL(g_object_get_data(ref, "binpanel"));
+        ditem = gtk_dock_panel_item_from_name(dpanel, openida_binary_to_string(binary));
 
-    printf("View as graph ? %d\n", active);
+        gtk_dock_panel_replace_item_content(dpanel, ditem, panel);
 
+    }
 
 }
 
@@ -936,6 +936,7 @@ void mcb_select_sections(GtkMenuItem *menuitem, gpointer data)
 
 void reload_menu_project(GObject *ref)
 {
+#if 0
     GtkWidget *menuitem;                    /* Menu principal à compléter  */
     GtkWidget *menubar;                     /* Support pour éléments       */
     GList *list;                            /* Liste des éléments en place */
@@ -973,7 +974,7 @@ void reload_menu_project(GObject *ref)
     }
 
     gtk_widget_set_sensitive(menuitem, count > 0);
-
+#endif
 }
 
 
@@ -1206,12 +1207,50 @@ void update_debug_menu_items(GObject *ref, gboolean stopped)
 void open_last_file(GObject *ref)
 {
 
+
+    GtkWidget *scrolledwindow;
+
+
+    GtkWidget *snippet;
+
+
+
+    GtkDockPanel *dpanel;                   /* Support de panneaux         */
+    GtkDockItem *ditem;                     /* Panneau avec ses infos.     */
+
     openida_binary *binary;
 
 
+    openida_project *project;
+
+    GtkWidget *view;                        /* Affichage du code binaire   */
+
+
 
     binary = load_binary_file("/tmp/hello");
-    gtk_snippet_set_rendering_lines(GTK_SNIPPET(g_object_get_data(ref, "snippet")), get_openida_binary_lines(binary));
+
+    if (binary == NULL)
+    {
+        /* TODO : log ... */
+        return;
+    }
+
+
+    project = get_current_openida_project();
+
+    attach_binary_to_openida_project(project, binary);
+
+    view = get_view_for_openida_project_binary(project, binary, BVW_BLOCK);
+
+
+
+
+    dpanel = GTK_DOCK_PANEL(g_object_get_data(ref, "binpanel"));
+
+    ditem = gtk_dock_item_new(openida_binary_to_string(binary), view);
+    gtk_dock_panel_add_item(dpanel, ditem);
+
+
 
 
     g_object_set_data(ref, "current_binary", binary);
diff --git a/src/gtkext/Makefile.am b/src/gtkext/Makefile.am
index 021a061..421a1c4 100644
--- a/src/gtkext/Makefile.am
+++ b/src/gtkext/Makefile.am
@@ -5,11 +5,13 @@ noinst_LTLIBRARIES = libgtkext.la
 
 libgtkext_la_SOURCES =					\
 	easygtk.h easygtk.c					\
+	gtkbinview-int.h					\
 	gtkbinview.h gtkbinview.c			\
+	gtkblockview.h gtkblockview.c		\
 	gtkdockitem.h gtkdockitem.c			\
 	gtkdockpanel.h gtkdockpanel.c		\
 	gtkdropwindow.h gtkdropwindow.c		\
-	gtksnippet.h gtksnippet.c			\
+	gtkgraphview.h gtkgraphview.c		\
 	iodamarshal.h iodamarshal.c			\
 	support.h support.c
 
diff --git a/src/gtkext/easygtk.c b/src/gtkext/easygtk.c
index f596404..253b4bc 100644
--- a/src/gtkext/easygtk.c
+++ b/src/gtkext/easygtk.c
@@ -127,6 +127,40 @@ GtkWidget *qck_create_notebook(GObject *object, const char *name)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : object = espace dédié à l'inscription de références.         *
+*                name   = nom à donner au nouveau composant.                  *
+*                                                                             *
+*  Description : Met en place un support avec défilement automatique.         *
+*                                                                             *
+*  Retour      : Composant 'GtkWidget' ici créé.                              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *qck_create_scrolled_window(GObject *object, const char *name)
+{
+    GtkWidget *result;                      /* Instance à renvoyer         */
+
+    result = gtk_scrolled_window_new(NULL, NULL);
+    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(result),
+                                   GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+    if (G_IS_OBJECT(object) && name != NULL)
+    {
+        gtk_widget_ref(result);
+        g_object_set_data_full(object, name, result, (GtkDestroyNotify)g_object_unref);
+    }
+
+    gtk_widget_show(result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : object   = espace dédié à l'inscription de références.       *
 *                name     = nom à donner au nouveau composant.                *
 *                filename = chemin d'accès complet au fichier à afficher.     *
diff --git a/src/gtkext/easygtk.h b/src/gtkext/easygtk.h
index 41b24e0..d1d7fbf 100644
--- a/src/gtkext/easygtk.h
+++ b/src/gtkext/easygtk.h
@@ -38,6 +38,9 @@ GtkWidget *qck_create_frame(const char *, GtkWidget **, guint, guint, guint, gui
 /* Met en place un support à onglets. */
 GtkWidget *qck_create_notebook(GObject *, const char *);
 
+/* Met en place un support avec défilement automatique. */
+GtkWidget *qck_create_scrolled_window(GObject *, const char *);
+
 /* Crée un composant 'GtkImage'. */
 GtkWidget *qck_create_image(GObject *, const char *, gchar *);
 
diff --git a/src/gtkext/gtkbinview-int.h b/src/gtkext/gtkbinview-int.h
new file mode 100644
index 0000000..33ba33c
--- /dev/null
+++ b/src/gtkext/gtkbinview-int.h
@@ -0,0 +1,49 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * gtkbinview-int.h - définitions internes propre à l'affichage d'un ou plusieurs morceaux de code
+ *
+ * Copyright (C) 2009 Cyrille Bagard
+ *
+ *  This file is part of OpenIDA.
+ *
+ *  OpenIDA 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.
+ *
+ *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GTKBINVIEW_INT_H
+#define _GTKEXT_GTKBINVIEW_INT_H
+
+
+#include "gtkbinview.h"
+
+
+#include <gtk/gtkfixed.h>
+
+
+
+struct _GtkBinview
+{
+    GtkFixed parent;                        /* A laisser en premier        */
+
+};
+
+struct _GtkBinviewClass
+{
+    GtkFixedClass parent;                   /* A laisser en premier        */
+
+};
+
+
+
+#endif  /* _GTKEXT_GTKBINVIEW_INT_H */
diff --git a/src/gtkext/gtkbinview.c b/src/gtkext/gtkbinview.c
index 5ed6388..9ffb5f6 100644
--- a/src/gtkext/gtkbinview.c
+++ b/src/gtkext/gtkbinview.c
@@ -24,29 +24,19 @@
 #include "gtkbinview.h"
 
 
-#include "gtksnippet.h"
+#include "gtkbinview-int.h"
 
 
 
 
 
-struct _GtkBinview
-{
-    GtkViewport viewport;
-
-};
-
-struct _GtkBinviewClass
-{
-    GtkViewportClass parent_class;
 
-};
 
 
 
 
 /* Détermine le type du composant d'affichage des morceaux. */
-G_DEFINE_TYPE(GtkBinview, gtk_binview, GTK_TYPE_VIEWPORT)
+G_DEFINE_TYPE(GtkBinview, gtk_binview, GTK_TYPE_FIXED)
 
 
 
@@ -68,17 +58,15 @@ G_DEFINE_TYPE(GtkBinview, gtk_binview, GTK_TYPE_VIEWPORT)
 static void gtk_binview_class_init(GtkBinviewClass *class)
 {
     GtkWidgetClass *widget_class;           /* Classe de haut niveau       */
-    GtkViewportClass *viewport_class;             /* Classe du niveau supérieur  */
 
     widget_class = GTK_WIDGET_CLASS(class);
-    viewport_class = GTK_VIEWPORT_CLASS(class);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : binview = composant GTK à initialiser.                       *
+*  Paramètres  : view = composant GTK à initialiser.                          *
 *                                                                             *
 *  Description : Procède à l'initialisation de l'afficheur de morceaux.       *
 *                                                                             *
@@ -88,10 +76,9 @@ static void gtk_binview_class_init(GtkBinviewClass *class)
 *                                                                             *
 ******************************************************************************/
 
-static void gtk_binview_init(GtkBinview *binview)
+static void gtk_binview_init(GtkBinview *view)
 {
-
-
+    gtk_fixed_set_has_window(GTK_FIXED(view), TRUE);
 
 }
 
@@ -140,7 +127,7 @@ void gtk_binview_show_vaddress(GtkBinview *binview, gboolean show)
     list = gtk_container_get_children(GTK_CONTAINER(binview));
 
     for (iter = g_list_first(list); iter != NULL; iter = g_list_next(iter))
-        gtk_snippet_show_vaddress(GTK_SNIPPET(iter->data), show);
+        /*gtk_snippet_show_vaddress(GTK_SNIPPET(iter->data), show)*/;
 
     g_list_free(list);
 
@@ -168,7 +155,7 @@ void gtk_binview_show_code(GtkBinview *binview, gboolean show)
     list = gtk_container_get_children(GTK_CONTAINER(binview));
 
     for (iter = g_list_first(list); iter != NULL; iter = g_list_next(iter))
-        gtk_snippet_show_code(GTK_SNIPPET(iter->data), show);
+        /*gtk_snippet_show_code(GTK_SNIPPET(iter->data), show)*/;
 
     g_list_free(list);
 
@@ -195,6 +182,7 @@ void gtk_binview_show_code(GtkBinview *binview, gboolean show)
 
 void gtk_binview_scroll_to_address(GtkBinview *binview, uint64_t address)
 {
+#if 0
     GList *list;                            /* Ensemble des enfants        */
     GList *iter;                            /* Boucle de parcours          */
     GtkSnippet *snippet;                    /* Morceau de code présent     */
@@ -220,7 +208,7 @@ void gtk_binview_scroll_to_address(GtkBinview *binview, uint64_t address)
     }
 
     g_list_free(list);
-
+#endif
 }
 
 
diff --git a/src/gtkext/gtkbinview.h b/src/gtkext/gtkbinview.h
index 4fafad1..722d10d 100644
--- a/src/gtkext/gtkbinview.h
+++ b/src/gtkext/gtkbinview.h
@@ -43,6 +43,9 @@
 typedef struct _GtkBinview        GtkBinview;
 typedef struct _GtkBinviewClass   GtkBinviewClass;
 
+typedef struct _GtkBinview        GtkBinView;
+typedef struct _GtkBinviewClass   GtkBinViewClass;
+
 
 
 /* Détermine le type du composant d'affichage des morceaux. */
diff --git a/src/gtkext/gtkblockview.c b/src/gtkext/gtkblockview.c
new file mode 100644
index 0000000..b125c7b
--- /dev/null
+++ b/src/gtkext/gtkblockview.c
@@ -0,0 +1,785 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * gtkblockview.c - affichage d'un fragment de code d'assemblage
+ *
+ * Copyright (C) 2008 Cyrille Bagard
+ *
+ *  This file is part of OpenIDA.
+ *
+ *  OpenIDA 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.
+ *
+ *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "gtkblockview.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include "gtkbinview-int.h"
+#include "../common/dllist.h"
+
+
+
+#define CONTENT_BUFFER_LEN 64
+
+#define MARGIN_SPACE 4
+
+
+
+struct _GtkBlockView
+{
+    GtkBinView parent;                      /* A laisser en premier        */
+
+    bool show_vaddress;                     /* Affichage des adresses ?    */
+    bool show_code;                         /* Affichage du code brut ?    */
+
+    PangoLayout *layout;                    /* Moteur de rendu du code ASM */
+    GdkGC *gc;                              /* Contexte graphique du rendu */
+    int line_height;                        /* Hauteur maximale des lignes */
+
+    const exe_format *format;               /* Format du contenu bianire   */
+
+    GRenderingLine *lines;                  /* Contenu à représenter       */
+
+};
+
+struct _GtkBlockViewClass
+{
+    GtkBinViewClass parent;                 /* A laisser en premier        */
+
+};
+
+
+
+
+
+
+
+
+/* Redessine l'affichage suite une mise à jour dans la marge. */
+void gtk_block_view_update_margin(GRenderingLine *, GtkBlockView *);
+
+
+
+
+
+/* Réclame une nouvelle taille adaptée au contenu présent. */
+void gtk_block_view_recompute_size_request(GtkBlockView *);
+
+
+
+
+
+
+
+
+static void gtk_block_view_class_init(GtkBlockViewClass *klass);
+static void gtk_block_view_init(GtkBlockView *cpu);
+static void gtk_block_view_size_request(GtkWidget *widget,
+    GtkRequisition *requisition);
+static void gtk_block_view_size_allocate(GtkWidget *widget,
+    GtkAllocation *allocation);
+static void gtk_block_view_realize(GtkWidget *widget);
+
+
+static gboolean gtk_block_view_button_press(GtkWidget *, GdkEventButton *event);
+
+static gboolean gtk_block_view_expose(GtkWidget *widget,
+    GdkEventExpose *event);
+static void gtk_block_view_paint(GtkBlockView *view);
+static void gtk_block_view_destroy(GtkObject *object);
+
+
+
+G_DEFINE_TYPE(GtkBlockView, gtk_block_view, GTK_TYPE_BIN_VIEW)
+
+
+
+
+GtkWidget * gtk_block_view_new(void)
+{
+    GtkBlockView *result;
+
+    result = gtk_type_new(gtk_block_view_get_type());
+
+    return GTK_WIDGET(result);
+
+}
+
+
+static void
+gtk_block_view_class_init(GtkBlockViewClass *klass)
+{
+  GtkWidgetClass *widget_class;
+  GtkObjectClass *object_class;
+
+
+  widget_class = (GtkWidgetClass *) klass;
+  object_class = (GtkObjectClass *) klass;
+
+
+  widget_class->button_press_event = gtk_block_view_button_press;
+  widget_class->realize = gtk_block_view_realize;
+  widget_class->size_request = gtk_block_view_size_request;
+  widget_class->size_allocate = gtk_block_view_size_allocate;
+  widget_class->expose_event = gtk_block_view_expose;
+
+  object_class->destroy = gtk_block_view_destroy;
+}
+
+
+static void
+gtk_block_view_init(GtkBlockView *view)
+{
+
+}
+
+
+static void
+gtk_block_view_size_request(GtkWidget *widget,
+    GtkRequisition *requisition)
+{
+  g_return_if_fail(widget != NULL);
+  g_return_if_fail(GTK_IS_BLOCK_VIEW(widget));
+  g_return_if_fail(requisition != NULL);
+
+  requisition->width = 80;
+  requisition->height = 100;
+}
+
+
+static void
+gtk_block_view_size_allocate(GtkWidget *widget,
+    GtkAllocation *allocation)
+{
+  g_return_if_fail(widget != NULL);
+  g_return_if_fail(GTK_IS_BLOCK_VIEW(widget));
+  g_return_if_fail(allocation != NULL);
+
+  widget->allocation = *allocation;
+
+  if (GTK_WIDGET_REALIZED(widget)) {
+     gdk_window_move_resize(
+         widget->window,
+         allocation->x, allocation->y,
+         allocation->width, allocation->height
+     );
+   }
+}
+
+
+static void
+gtk_block_view_realize(GtkWidget *widget)
+{
+    GdkWindowAttr attributes;
+    guint attributes_mask;
+    GdkColor white;                         /* Couleur de fond normale     */
+
+  g_return_if_fail(widget != NULL);
+  g_return_if_fail(GTK_IS_BLOCK_VIEW(widget));
+
+  GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
+
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.event_mask = gtk_widget_get_events(widget) | GDK_BUTTON_PRESS_MASK | GDK_EXPOSURE_MASK;
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y;
+
+  widget->window = gdk_window_new(
+     gtk_widget_get_parent_window (widget),
+     & attributes, attributes_mask
+  );
+
+  gdk_window_set_user_data(widget->window, widget);
+
+    widget->style = gtk_style_attach(widget->style, widget->window);
+
+
+    gdk_color_white(gtk_widget_get_colormap(widget), &white);
+    gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &white);
+
+
+    GTK_BLOCK_VIEW(widget)->layout = gtk_widget_create_pango_layout(widget, NULL);
+    GTK_BLOCK_VIEW(widget)->gc = gdk_gc_new(GDK_DRAWABLE(widget->window));
+
+    gtk_block_view_build_content(GTK_BLOCK_VIEW(widget));
+
+}
+
+
+static gboolean gtk_block_view_button_press(GtkWidget *widget, GdkEventButton *event)
+{
+    gboolean result;                        /* Décision à retourner        */
+    GtkBlockView *view;                    /* Composant GTK réel          */
+    gdouble y;                              /* Position à manipuler        */
+    GRenderingLine *line;                   /* Ligne de rendu visée        */
+
+    result = FALSE;
+
+    view = GTK_BLOCK_VIEW(widget);
+
+    y = event->y;
+    line = g_rendering_line_find_by_y(view->lines, &y);
+
+    if (line != NULL)
+    {
+        /* Clic dans la marge */
+        if (event->type == GDK_BUTTON_PRESS && event->x < (2 * MARGIN_SPACE + view->line_height))
+        {
+            result = TRUE;
+            g_rendering_line_toggle_flag(line, RLF_BREAK_POINT);
+        }
+
+    }
+
+    if (result)
+    {
+        /* TODO: regions */
+        gtk_block_view_paint(view);
+    }
+
+    return result;
+
+}
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : line = ligne dont un drapeau a évolué.                       *
+*                view = composant GTK à mettre à jour.                        *
+*                                                                             *
+*  Description : Redessine l'affichage suite une mise à jour dans la marge.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_block_view_update_margin(GRenderingLine *line, GtkBlockView *view)
+{
+
+
+    gtk_block_view_paint(view);
+
+
+
+
+}
+
+
+
+
+
+static gboolean
+gtk_block_view_expose(GtkWidget *widget,
+    GdkEventExpose *event)
+{
+  g_return_val_if_fail(widget != NULL, FALSE);
+  g_return_val_if_fail(GTK_IS_BLOCK_VIEW(widget), FALSE);
+  g_return_val_if_fail(event != NULL, FALSE);
+
+  gtk_block_view_paint(GTK_BLOCK_VIEW(widget));
+
+
+
+  /*
+
+
+gdk_gc_set_clip_region              (GdkGC *gc,
+                                                         const GdkRegion *region);
+
+gdk_window_invalidate_region        (GdkWindow *window,
+                                                         const GdkRegion *region,
+                                                         gboolean invalidate_children);
+gdk_window_begin_paint_region       (GdkWindow *window,
+                                                         const GdkRegion *region);
+void                gdk_window_end_paint                (GdkWindow *window);
+   */
+
+
+
+
+
+
+    return TRUE;
+
+}
+
+
+static void
+gtk_block_view_paint(GtkBlockView *view)
+{
+    GtkWidget *widget;                      /* Version GTK du composant    */
+    GdkGCValues values;                     /* Propriétés du contexte      */
+    GdkColor white;                         /* Couleur du fond             */
+    int width;                              /* Largeur de l'élément        */
+    int height;                             /* Hauteur de l'élément        */
+    GdkColor red;                           /* Couleur des arrêts          */
+    PangoLayoutIter *iter;                  /* Boucle de parcours          */
+    unsigned int index;                     /* Indice de la ligne visée    */
+    int y0;                                 /* Ordonnée du haut d'une ligne*/
+    int y1;                                 /* Ordonnée du bas d'une ligne */
+
+    GRenderingLine *liter;
+
+
+    widget = GTK_WIDGET(view);
+    gdk_gc_get_values(view->gc, &values);
+
+    gdk_color_white(gtk_widget_get_colormap(widget), &white);
+    gdk_gc_set_foreground(view->gc, &white);
+
+    gtk_widget_get_size_request(widget, &width, &height);
+
+    gdk_draw_rectangle(GDK_DRAWABLE(widget->window), GTK_BLOCK_VIEW(widget)->gc,
+                       TRUE, 0, 0, width, height);
+
+    gdk_color_parse("#ff0000", &red);
+    gdk_color_alloc(gtk_widget_get_colormap(widget), &red);
+    gdk_gc_set_foreground(view->gc, &red);
+
+
+    index = 0;
+    iter = pango_layout_get_iter(view->layout);
+
+#if 0
+    for (; index < view->info_count; index++, pango_layout_iter_next_line(iter))
+    {
+        if (!view->info[index].bp_set) continue;
+
+        pango_layout_iter_get_line_yrange(iter, &y0, &y1);
+
+
+
+        gdk_draw_arc(GDK_DRAWABLE(widget->window), GTK_BLOCK_VIEW(widget)->gc,
+                     FALSE, MARGIN_SPACE, y0 / PANGO_SCALE,
+                     view->line_height - 2, view->line_height - 2,
+                     0, 360 * 64);
+
+    }
+#endif
+
+    pango_layout_iter_free(iter);
+
+    gdk_gc_set_foreground(view->gc, &values.foreground);
+
+    gdk_draw_layout(GDK_DRAWABLE(widget->window), view->gc,
+                    2 * MARGIN_SPACE + view->line_height, 0,
+                    view->layout);
+
+
+    y0 = 0;
+
+    for (/* l! */liter = view->lines; liter != NULL; liter = g_rendering_line_get_next_iter(view->lines, liter))
+    {
+        g_rendering_line_draw(liter, GDK_DRAWABLE(widget->window), view->gc,
+                              MARGIN_SPACE, 2 * MARGIN_SPACE + view->line_height,
+                              y0, view->line_height);
+
+        y0 += view->line_height;
+
+    }
+
+
+}
+
+
+static void
+gtk_block_view_destroy(GtkObject *object)
+{
+  GtkBlockView *cpu;
+  GtkBlockViewClass *klass;
+
+  g_return_if_fail(object != NULL);
+  g_return_if_fail(GTK_IS_BLOCK_VIEW(object));
+
+  cpu = GTK_BLOCK_VIEW(object);
+
+  klass = gtk_type_class(gtk_widget_get_type());
+
+  if (GTK_OBJECT_CLASS(klass)->destroy) {
+     (* GTK_OBJECT_CLASS(klass)->destroy) (object);
+  }
+}
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GTK à mettre à jour.                     *
+*                show    = état de l'affichage auquel parvenir.               *
+*                                                                             *
+*  Description : Choisit d'afficher les adresses virtuelles ou non.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_block_view_show_vaddress(GtkBlockView *view, gboolean show)
+{
+    view->show_vaddress = show;
+
+    gtk_block_view_build_content(view);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GTK à mettre à jour.                     *
+*                show    = état de l'affichage auquel parvenir.               *
+*                                                                             *
+*  Description : Choisit d'afficher le code brut ou non.                      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_block_view_show_code(GtkBlockView *view, gboolean show)
+{
+    view->show_code = show;
+
+    gtk_block_view_build_content(view);
+
+}
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GTK à mettre à jour.                     *
+*                format  = format du binaire affiché.                         *
+*                                                                             *
+*  Description : Définit le format auquel le contenu est lié.                 *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_block_view_set_format(GtkBlockView *view, const exe_format *format)
+{
+    view->format = format;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GTK à mettre à jour.                     *
+*                lines   = informations à intégrer.                           *
+*                                                                             *
+*  Description : Définit les lignes du bloc de représentation.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_block_view_set_rendering_lines(GtkBlockView *view, GRenderingLine *lines)
+{
+    GRenderingLine *iter;                   /* Boucle de parcours          */
+
+    view->lines = lines;
+
+    for (iter = lines; iter != NULL; iter = g_rendering_line_get_next_iter(lines, iter))
+        g_signal_connect(iter, "rendering-line-flags-changed",
+                         G_CALLBACK(gtk_block_view_update_margin), view);
+
+    g_rendering_line_update_bin_len(lines);
+
+    gtk_block_view_recompute_size_request(view);
+
+}
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GTK à mettre à jour.                     *
+*                                                                             *
+*  Description : Réclame une nouvelle taille adaptée au contenu présent.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_block_view_recompute_size_request(GtkBlockView *view)
+{
+    int width;                              /* Largeur de l'objet actuelle */
+    int height;                             /* Hauteur de l'objet actuelle */
+
+    g_rendering_line_get_size(view->lines, &width, &height, &view->line_height);
+
+    gtk_widget_set_size_request(GTK_WIDGET(view),
+                                width + 2 * MARGIN_SPACE + view->line_height,
+                                height);
+
+}
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = composant GTK à mettre à jour.                        *
+*                                                                             *
+*  Description : Définit le contenu visuel à partir des infos enregistrées.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_block_view_build_content(GtkBlockView *view)
+{
+#if 0
+    const uint8_t *exe_content;             /* Contenu binaire global      */
+    off_t max_bin_len;                      /* Taille max du code brut     */
+    unsigned int i;                         /* Boucle de traitement        */
+    off_t bin_len;                          /* Taille d'instruction        */
+    char *bin_code;                         /* Tampon du code binaire      */
+    char *content;                          /* Contenu à définir           */
+    size_t content_len;                     /* Taille du contenu           */
+    AdressMode mode;                        /* Affichage des adresses      */
+    char buffer[CONTENT_BUFFER_LEN];        /* Zone tampon à utiliser      */
+    off_t bin_offset;                       /* Début de l'instruction      */
+    off_t k;                                /* Boucle de parcours #2       */
+    off_t j;                                /* Boucle de parcours #1       */
+    int width;                              /* Largeur de l'objet actuelle */
+    int height;                             /* Hauteur de l'objet actuelle */
+    PangoLayoutIter *iter;                  /* Boucle de parcours          */
+    int y0;                                 /* Ordonnée du haut d'une ligne*/
+    int y1;                                 /* Ordonnée du bas d'une ligne */
+
+    /* Calcul de la largeur maximale brute si besoin est */
+    if (view->show_code)
+    {
+        exe_content = get_exe_content(view->format, NULL);
+
+        max_bin_len = 1;
+
+        for (i = 0; i < view->info_count; i++)
+        {
+            /* Commentaire uniquement */
+            if (view->info[i].instr == NULL) continue;
+
+            get_asm_instr_offset_and_length(view->info[i].instr, NULL, &bin_len);
+            if (bin_len > max_bin_len) max_bin_len = bin_len;
+
+        }
+
+        max_bin_len = max_bin_len * 2 + (max_bin_len - 1);
+        bin_code = (char *)calloc(max_bin_len + 1, sizeof(char));
+
+    }
+
+    content_len = strlen("<tt>") + 1;
+    content = (char *)calloc(content_len, sizeof(char));
+    strcpy(content, "<tt>");
+
+    mode = ADM_32BITS;  /* FIXME */
+
+    for (i = 0; i < view->info_count; i++)
+    {
+        if (i > 0)
+        {
+            content = (char *)realloc(content, ++content_len * sizeof(char));
+            strcat(content, "\n");
+        }
+
+        /* Eventuelle adresse virtuelle */
+
+        if (view->show_vaddress)
+        {
+            switch (mode)
+            {
+                case ADM_32BITS:
+                    snprintf(buffer, CONTENT_BUFFER_LEN,
+                             "<span foreground='#333333'>0x%08llx</span>", 
+                             view->info[i].offset);
+                    break;
+
+                case ADM_64BITS:
+                    snprintf(buffer, CONTENT_BUFFER_LEN,
+                             "<span foreground='#333333'>0x%16llx</span>", 
+                             view->info[i].offset);
+                    break;
+
+            }
+
+            content_len += strlen(buffer);
+            content = (char *)realloc(content, content_len * sizeof(char));
+            strcat(content, buffer);
+
+        }
+
+        /* Eventuel code brut */
+
+        if (view->show_code)
+        {
+            k = 0;
+
+            if (view->info[i].instr != NULL)
+            {
+                get_asm_instr_offset_and_length(view->info[i].instr, &bin_offset, &bin_len);
+
+                for (j = 0; j < bin_len; j++)
+                {
+                    if ((j + 1) < bin_len)
+                        k += snprintf(&bin_code[j * (2 + 1)], 4, "%02hhx ", exe_content[bin_offset + j]);
+                    else
+                        k += snprintf(&bin_code[j * (2 + 1)], 3, "%02hhx", exe_content[bin_offset + j]);
+                }
+
+            }
+ 
+            for (; k < max_bin_len; k++)
+                snprintf(&bin_code[k], 2, " ");
+
+            if (view->show_vaddress) content_len += strlen("\t");
+            content_len += strlen(bin_code);
+            content = (char *)realloc(content, content_len * sizeof(char));
+            if (view->show_vaddress) strcat(content, "\t");
+            strcat(content, bin_code);
+
+        }
+
+        /* Eventuelle instruction */
+
+        if (view->info[i].instr != NULL)
+        {
+            print_hinstruction(view->proc, view->format, view->info[i].instr, buffer, CONTENT_BUFFER_LEN, ASX_INTEL);
+
+            if (view->show_vaddress || view->show_code) content_len += strlen("\t");
+            content_len += strlen(buffer);
+
+            content = (char *)realloc(content, content_len * sizeof(char));
+            if (view->show_vaddress || view->show_code) strcat(content, "\t");
+            strcat(content, buffer);
+
+        }
+
+        /* Eventuel commantaire */
+
+        if (view->info[i].comment != NULL)
+        {
+            if (view->show_vaddress || view->show_code) content_len += strlen("\t");
+            content_len += strlen("<b><span foreground='#003300'>; ") + strlen(view->info[i].comment) + strlen("</span></b>");
+
+            content = (char *)realloc(content, content_len * sizeof(char));
+            if (view->show_vaddress || view->show_code) strcat(content, "\t");
+            strcat(content, "<b><span foreground='#003300'>; ");
+            strcat(content, view->info[i].comment);
+            strcat(content, "</span></b>");
+
+        }
+
+    }
+
+    content_len += strlen("</tt>");
+    content = (char *)realloc(content, content_len * sizeof(char));
+    strcat(content, "</tt>");
+
+    if (view->show_code) free(bin_code);
+
+    pango_layout_set_markup(view->layout, content, content_len - 1);
+
+    pango_layout_get_pixel_size(view->layout, &width, &height);
+
+    view->line_height = 0;
+    iter = pango_layout_get_iter(view->layout);
+
+    do
+    {
+        pango_layout_iter_get_line_yrange(iter, &y0, &y1);
+        view->line_height = MAX(view->line_height, (y1 - y0) / PANGO_SCALE);
+    }
+    while (pango_layout_iter_next_line(iter));
+
+    pango_layout_iter_free(iter);
+
+    //gtk_widget_set_size_request(GTK_WIDGET(block_view), width + 2 * MARGIN_SPACE + view->line_height, height);
+#endif
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view     = composant GTK à consulter.                        *
+*                address  = adresse à présenter à l'écran.                    *
+*                position = position verticale au sein du composant. [OUT]    *
+*                                                                             *
+*  Description : Indique la position verticale d'une adresse donnée.          *
+*                                                                             *
+*  Retour      : TRUE si l'adresse fait partie du composant, FALSE sinon.     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+gboolean gtk_block_view_get_address_vposition(GtkBlockView *view, uint64_t address, gint *position)
+{
+    unsigned int i;                         /* Boucle de parcours          */
+
+    *position = 0;
+#if 0
+    for (i = 0; i < view->info_count; i++)
+    {
+        if (view->info[i].offset == address) break;
+        else *position += view->line_height;
+    }
+#endif
+    return false;//(i < view->info_count);
+
+}
+
diff --git a/src/gtkext/gtkblockview.h b/src/gtkext/gtkblockview.h
new file mode 100644
index 0000000..66117fa
--- /dev/null
+++ b/src/gtkext/gtkblockview.h
@@ -0,0 +1,99 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * gtkblockview.h - prototypes pour l'affichage d'un fragment de code d'assemblage
+ *
+ * Copyright (C) 2008 Cyrille Bagard
+ *
+ *  This file is part of OpenIDA.
+ *
+ *  OpenIDA 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.
+ *
+ *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GTKBLOCKVIEW_H
+#define _GTKEXT_GTKBLOCKVIEW_H
+
+
+#include <stdint.h>
+#include <gtk/gtk.h>
+#include <cairo.h>
+
+
+#include "../analysis/line.h"
+#include "../format/exe_format.h"
+
+
+
+#define GTK_TYPE_BLOCK_VIEW                  (gtk_block_view_get_type())
+#define GTK_BLOCK_VIEW(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_BLOCK_VIEW, GtkBlockView))
+#define GTK_BLOCK_VIEW_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_BLOCK_VIEW, GtkBlockViewClass))
+#define GTK_IS_BLOCK_VIEW(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_BLOCK_VIEW))
+#define GTK_IS_BLOCK_VIEW_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_BLOCK_VIEW))
+#define GTK_BLOCK_VIEW_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_BLOCK_VIEW, GtkBlockViewClass))
+
+
+
+typedef struct _GtkBlockView GtkBlockView;
+
+
+typedef struct _GtkBlockViewClass GtkBlockViewClass;
+
+
+
+/* Détermine le type du composant d'affichage en blockique. */
+GType gtk_block_view_get_type(void);
+
+/* Crée un nouveau composant pour l'affichage en blockique. */
+GtkWidget* gtk_block_view_new(void);
+
+
+
+
+
+
+
+
+
+
+
+
+/* Choisit d'afficher les adresses virtuelles ou non. */
+void gtk_block_view_show_vaddress(GtkBlockView *, gboolean);
+
+/* Choisit d'afficher le code brut ou non. */
+void gtk_block_view_show_code(GtkBlockView *, gboolean);
+
+
+
+
+/* Définit le format auquel le contenu est lié. */
+void gtk_block_view_set_format(GtkBlockView *, const exe_format *);
+
+/* Définit les lignes du bloc de représentation. */
+void gtk_block_view_set_rendering_lines(GtkBlockView *, GRenderingLine *);
+
+/* Définit le contenu visuel à partir des infos enregistrées. */
+void gtk_block_view_build_content(GtkBlockView *);
+
+
+
+/* Indique la position verticale d'une adresse donnée. */
+gboolean gtk_block_view_get_address_vposition(GtkBlockView *, uint64_t, gint *);
+
+
+
+
+
+
+#endif  /* _GTKEXT_GTKBLOCKVIEW_H */
diff --git a/src/gtkext/gtkdockpanel.c b/src/gtkext/gtkdockpanel.c
index e7bd14b..41b71aa 100644
--- a/src/gtkext/gtkdockpanel.c
+++ b/src/gtkext/gtkdockpanel.c
@@ -514,23 +514,35 @@ static void gtk_dock_panel_drag_end_cb(GtkDockPanel *dpanel, GdkDragContext *con
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : dpanel  = composant à l'origine de la manoeuvre.             *
-*                context = contexte de l'opération de "Drag and drop".        *
-*                data    = adresse non utilisée ici.                          *
+*  Paramètres  : dpanel = composant dont le contenu est à parcourir.          *
+*                name   = désignation humaine du membre à retrouver.          *
 *                                                                             *
-*  Description : Nettoie les traces d'un "Drag and drop".                     *
+*  Description : Retrouve un membre du panneau d'après son nom.               *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Membre trouvé ou NULL si aucun.                              *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-static void gtk_dock_panel_drag_data_delete_cb(GtkDockPanel *dpanel, GdkDragContext *context, gpointer data)
+GtkDockItem *gtk_dock_panel_item_from_name(GtkDockPanel *dpanel, const char *name)
 {
+    GtkDockItem *result;                    /* Trouvaille à remonter       */
+    GList *iter;                            /* Boucle de parcours          */
+    const char *tmp;                        /* Autre nom à consulter       */
 
+    result = NULL;
 
+    for (iter = dpanel->ditems; iter != NULL && result == NULL; iter = g_list_next(iter))
+    {
+        tmp = gtk_dock_item_get_name(GTK_DOCK_ITEM(iter->data));
+
+        if (strcmp(name, tmp) == 0)
+            result = GTK_DOCK_ITEM(iter->data);
 
+    }
+
+    return result;
 
 }
 
@@ -574,6 +586,32 @@ void gtk_dock_panel_add_item(GtkDockPanel *dpanel, GtkDockItem *ditem)
 *                                                                             *
 *  Paramètres  : dpanel = composant GTK à mettre à jour.                      *
 *                ditem  = nouvel élément à sortir.                            *
+*                panel  = nouveau panneau à présenter.                        *
+*                                                                             *
+*  Description : Remplace le panneau d'un membre actuellement affiché.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void gtk_dock_panel_replace_item_content(GtkDockPanel *dpanel, GtkDockItem *ditem, GtkWidget *panel)
+{
+    gtk_widget_ref(gtk_dock_item_get_panel(ditem));
+    gtk_container_remove(GTK_CONTAINER(dpanel->notebook), gtk_dock_item_get_panel(ditem));
+
+    gtk_dock_item_set_panel(ditem, panel);
+
+    gtk_container_add(GTK_CONTAINER(dpanel->notebook), gtk_dock_item_get_panel(ditem));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : dpanel = composant GTK à mettre à jour.                      *
+*                ditem  = nouvel élément à sortir.                            *
 *                                                                             *
 *  Description : Supprime un paquet d'informations à la station dockable.     *
 *                                                                             *
@@ -593,6 +631,7 @@ void gtk_dock_panel_remove_item(GtkDockPanel *dpanel, GtkDockItem *ditem)
 
     printf("[rem %p from %p] list len :: %u\n", ditem, dpanel, g_list_length(dpanel->ditems));
 
+    gtk_widget_ref(gtk_dock_item_get_panel(ditem));
     gtk_container_remove(GTK_CONTAINER(dpanel->notebook), gtk_dock_item_get_panel(ditem));
 
     //gtk_notebook_remove_page(dpanel->notebook, pos);
diff --git a/src/gtkext/gtkdockpanel.h b/src/gtkext/gtkdockpanel.h
index 140f812..037ee26 100644
--- a/src/gtkext/gtkdockpanel.h
+++ b/src/gtkext/gtkdockpanel.h
@@ -73,9 +73,15 @@ GtkType gtk_dock_panel_get_type(void);
 /* Crée un nouveau composant pour station dockable. */
 GtkWidget *gtk_dock_panel_new(void);
 
+/* Retrouve un membre du panneau d'après son nom. */
+GtkDockItem *gtk_dock_panel_item_from_name(GtkDockPanel *, const char *);
+
 /* Ajoute un paquet d'informations à la station dockable. */
 void gtk_dock_panel_add_item(GtkDockPanel *, GtkDockItem *);
 
+/* Remplace le panneau d'un membre actuellement affiché. */
+void gtk_dock_panel_replace_item_content(GtkDockPanel *, GtkDockItem *, GtkWidget *);
+
 /* Supprime un paquet d'informations à la station dockable. */
 void gtk_dock_panel_remove_item(GtkDockPanel *, GtkDockItem *);
 
diff --git a/src/gtkext/gtkgraphview.c b/src/gtkext/gtkgraphview.c
new file mode 100644
index 0000000..d843311
--- /dev/null
+++ b/src/gtkext/gtkgraphview.c
@@ -0,0 +1,110 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * gtkgraphview.c - affichage de morceaux de code sous forme graphique
+ *
+ * Copyright (C) 2009 Cyrille Bagard
+ *
+ *  This file is part of OpenIDA.
+ *
+ *  OpenIDA 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.
+ *
+ *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "gtkgraphview.h"
+
+
+#include "gtkbinview-int.h"
+
+
+
+/* Représentation de code binaire sous forme graphique (instace) */
+struct _GtkGraphView
+{
+    GtkBinView parent;                      /* A laisser en premier        */
+
+};
+
+/* Représentation de code binaire sous forme graphique (classe) */
+struct _GtkGraphViewClass
+{
+    GtkBinViewClass parent;                 /* A laisser en premier        */
+
+};
+
+
+/* Initialise la classe générique des graphiques de code. */
+static void gtk_graph_view_class_init(GtkGraphViewClass *);
+
+/* Initialise une instance d'afficheur de code en graphique. */
+static void gtk_graph_view_init(GtkGraphView *);
+
+
+
+/* Détermine le type du composant d'affichage en graphique. */
+G_DEFINE_TYPE(GtkGraphView, gtk_graph_view, GTK_TYPE_BIN_VIEW)
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : class = classe GTK à initialiser.                            *
+*                                                                             *
+*  Description : Initialise la classe générique des graphiques de code.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void gtk_graph_view_class_init(GtkGraphViewClass *class)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : view = instance GTK à initialiser.                           *
+*                                                                             *
+*  Description : Initialise une instance d'afficheur de code en graphique.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void gtk_graph_view_init(GtkGraphView *view)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Crée un nouveau composant pour l'affichage en graphique.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget* gtk_graph_view_new(void)
+{
+    return g_object_new(GTK_TYPE_GRAPH_VIEW, NULL);
+
+}
diff --git a/src/gtkext/gtkgraphview.h b/src/gtkext/gtkgraphview.h
new file mode 100644
index 0000000..12dd606
--- /dev/null
+++ b/src/gtkext/gtkgraphview.h
@@ -0,0 +1,56 @@
+
+/* OpenIDA - Outil d'analyse de fichiers binaires
+ * gtkgraphview.h - prototypes pour l'affichage de morceaux de code sous forme graphique
+ *
+ * Copyright (C) 2009 Cyrille Bagard
+ *
+ *  This file is part of OpenIDA.
+ *
+ *  OpenIDA 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.
+ *
+ *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GTKEXT_GTKGRAPHVIEW_H
+#define _GTKEXT_GTKGRAPHVIEW_H
+
+
+#include <gtk/gtkwidget.h>
+
+
+
+#define GTK_TYPE_GRAPH_VIEW                  (gtk_graph_view_get_type())
+#define GTK_GRAPH_VIEW(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_GRAPH_VIEW, GtkGraphView))
+#define GTK_GRAPH_VIEW_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_GRAPH_VIEW, GtkGraphViewClass))
+#define GTK_IS_GRAPH_VIEW(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_GRAPH_VIEW))
+#define GTK_IS_GRAPH_VIEW_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_GRAPH_VIEW))
+#define GTK_GRAPH_VIEW_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_GRAPH_VIEW, GtkGraphViewClass))
+
+
+
+typedef struct _GtkGraphView GtkGraphView;
+
+
+typedef struct _GtkGraphViewClass GtkGraphViewClass;
+
+
+
+/* Détermine le type du composant d'affichage en graphique. */
+GType gtk_graph_view_get_type(void);
+
+/* Crée un nouveau composant pour l'affichage en graphique. */
+GtkWidget* gtk_graph_view_new(void);
+
+
+
+#endif  /* _GTKEXT_GTKGRAPHVIEW_H */
diff --git a/src/gtkext/gtksnippet.c b/src/gtkext/gtksnippet.c
deleted file mode 100644
index 3d1ed7e..0000000
--- a/src/gtkext/gtksnippet.c
+++ /dev/null
@@ -1,755 +0,0 @@
-
-/* OpenIDA - Outil d'analyse de fichiers binaires
- * gtksnippet.c - affichage d'un fragment de code d'assemblage
- *
- * Copyright (C) 2008 Cyrille Bagard
- *
- *  This file is part of OpenIDA.
- *
- *  OpenIDA 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.
- *
- *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#include "gtksnippet.h"
-
-
-#include <malloc.h>
-#include <string.h>
-
-
-#include "../common/dllist.h"
-
-
-
-#define CONTENT_BUFFER_LEN 64
-
-#define MARGIN_SPACE 4
-
-
-
-
-/* Redessine l'affichage suite une mise à jour dans la marge. */
-void gtk_snippet_update_margin(GRenderingLine *, GtkSnippet *);
-
-
-
-
-
-/* Réclame une nouvelle taille adaptée au contenu présent. */
-void gtk_snippet_recompute_size_request(GtkSnippet *);
-
-
-
-
-
-
-
-
-static void gtk_snippet_class_init(GtkSnippetClass *klass);
-static void gtk_snippet_init(GtkSnippet *cpu);
-static void gtk_snippet_size_request(GtkWidget *widget,
-    GtkRequisition *requisition);
-static void gtk_snippet_size_allocate(GtkWidget *widget,
-    GtkAllocation *allocation);
-static void gtk_snippet_realize(GtkWidget *widget);
-
-
-static gboolean gtk_snippet_button_press(GtkWidget *, GdkEventButton *event);
-
-static gboolean gtk_snippet_expose(GtkWidget *widget,
-    GdkEventExpose *event);
-static void gtk_snippet_paint(GtkSnippet *snippet);
-static void gtk_snippet_destroy(GtkObject *object);
-
-
-
-G_DEFINE_TYPE(GtkSnippet, gtk_snippet, GTK_TYPE_WIDGET)
-
-
-
-
-GtkWidget * gtk_snippet_new(void)
-{
-    GtkSnippet *result;
-
-    result = gtk_type_new(gtk_snippet_get_type());
-
-    return GTK_WIDGET(result);
-
-}
-
-
-static void
-gtk_snippet_class_init(GtkSnippetClass *klass)
-{
-  GtkWidgetClass *widget_class;
-  GtkObjectClass *object_class;
-
-
-  widget_class = (GtkWidgetClass *) klass;
-  object_class = (GtkObjectClass *) klass;
-
-
-  widget_class->button_press_event = gtk_snippet_button_press;
-  widget_class->realize = gtk_snippet_realize;
-  widget_class->size_request = gtk_snippet_size_request;
-  widget_class->size_allocate = gtk_snippet_size_allocate;
-  widget_class->expose_event = gtk_snippet_expose;
-
-  object_class->destroy = gtk_snippet_destroy;
-}
-
-
-static void
-gtk_snippet_init(GtkSnippet *snippet)
-{
-   snippet->sel = 0;
-}
-
-
-static void
-gtk_snippet_size_request(GtkWidget *widget,
-    GtkRequisition *requisition)
-{
-  g_return_if_fail(widget != NULL);
-  g_return_if_fail(GTK_IS_SNIPPET(widget));
-  g_return_if_fail(requisition != NULL);
-
-  requisition->width = 80;
-  requisition->height = 100;
-}
-
-
-static void
-gtk_snippet_size_allocate(GtkWidget *widget,
-    GtkAllocation *allocation)
-{
-  g_return_if_fail(widget != NULL);
-  g_return_if_fail(GTK_IS_SNIPPET(widget));
-  g_return_if_fail(allocation != NULL);
-
-  widget->allocation = *allocation;
-
-  if (GTK_WIDGET_REALIZED(widget)) {
-     gdk_window_move_resize(
-         widget->window,
-         allocation->x, allocation->y,
-         allocation->width, allocation->height
-     );
-   }
-}
-
-
-static void
-gtk_snippet_realize(GtkWidget *widget)
-{
-    GdkWindowAttr attributes;
-    guint attributes_mask;
-    GdkColor white;                         /* Couleur de fond normale     */
-
-  g_return_if_fail(widget != NULL);
-  g_return_if_fail(GTK_IS_SNIPPET(widget));
-
-  GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
-
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.x = widget->allocation.x;
-  attributes.y = widget->allocation.y;
-  attributes.width = widget->allocation.width;
-  attributes.height = widget->allocation.height;
-
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.event_mask = gtk_widget_get_events(widget) | GDK_BUTTON_PRESS_MASK | GDK_EXPOSURE_MASK;
-
-  attributes_mask = GDK_WA_X | GDK_WA_Y;
-
-  widget->window = gdk_window_new(
-     gtk_widget_get_parent_window (widget),
-     & attributes, attributes_mask
-  );
-
-  gdk_window_set_user_data(widget->window, widget);
-
-    widget->style = gtk_style_attach(widget->style, widget->window);
-
-
-    gdk_color_white(gtk_widget_get_colormap(widget), &white);
-    gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &white);
-
-
-    GTK_SNIPPET(widget)->layout = gtk_widget_create_pango_layout(widget, NULL);
-    GTK_SNIPPET(widget)->gc = gdk_gc_new(GDK_DRAWABLE(widget->window));
-
-    gtk_snippet_build_content(GTK_SNIPPET(widget));
-
-}
-
-
-static gboolean gtk_snippet_button_press(GtkWidget *widget, GdkEventButton *event)
-{
-    gboolean result;                        /* Décision à retourner        */
-    GtkSnippet *snippet;                    /* Composant GTK réel          */
-    gdouble y;                              /* Position à manipuler        */
-    GRenderingLine *line;                   /* Ligne de rendu visée        */
-
-    result = FALSE;
-
-    snippet = GTK_SNIPPET(widget);
-
-    y = event->y;
-    line = g_rendering_line_find_by_y(snippet->lines, &y);
-
-    if (line != NULL)
-    {
-        /* Clic dans la marge */
-        if (event->type == GDK_BUTTON_PRESS && event->x < (2 * MARGIN_SPACE + snippet->line_height))
-        {
-            result = TRUE;
-            g_rendering_line_toggle_flag(line, RLF_BREAK_POINT);
-        }
-
-    }
-
-    if (result)
-    {
-        /* TODO: regions */
-        gtk_snippet_paint(snippet);
-    }
-
-    return result;
-
-}
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : line    = ligne dont un drapeau a évolué.                    *
-*                snippet = composant GTK à mettre à jour.                     *
-*                                                                             *
-*  Description : Redessine l'affichage suite une mise à jour dans la marge.   *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void gtk_snippet_update_margin(GRenderingLine *line, GtkSnippet *snippet)
-{
-
-
-    gtk_snippet_paint(snippet);
-
-
-
-
-}
-
-
-
-
-
-static gboolean
-gtk_snippet_expose(GtkWidget *widget,
-    GdkEventExpose *event)
-{
-  g_return_val_if_fail(widget != NULL, FALSE);
-  g_return_val_if_fail(GTK_IS_SNIPPET(widget), FALSE);
-  g_return_val_if_fail(event != NULL, FALSE);
-
-  gtk_snippet_paint(GTK_SNIPPET(widget));
-
-
-
-  /*
-
-
-gdk_gc_set_clip_region              (GdkGC *gc,
-                                                         const GdkRegion *region);
-
-gdk_window_invalidate_region        (GdkWindow *window,
-                                                         const GdkRegion *region,
-                                                         gboolean invalidate_children);
-gdk_window_begin_paint_region       (GdkWindow *window,
-                                                         const GdkRegion *region);
-void                gdk_window_end_paint                (GdkWindow *window);
-   */
-
-
-
-
-
-
-    return TRUE;
-
-}
-
-
-static void
-gtk_snippet_paint(GtkSnippet *snippet)
-{
-    GtkWidget *widget;                      /* Version GTK du composant    */
-    GdkGCValues values;                     /* Propriétés du contexte      */
-    GdkColor white;                         /* Couleur du fond             */
-    int width;                              /* Largeur de l'élément        */
-    int height;                             /* Hauteur de l'élément        */
-    GdkColor red;                           /* Couleur des arrêts          */
-    PangoLayoutIter *iter;                  /* Boucle de parcours          */
-    unsigned int index;                     /* Indice de la ligne visée    */
-    int y0;                                 /* Ordonnée du haut d'une ligne*/
-    int y1;                                 /* Ordonnée du bas d'une ligne */
-
-    GRenderingLine *liter;
-
-
-    widget = GTK_WIDGET(snippet);
-    gdk_gc_get_values(snippet->gc, &values);
-
-    gdk_color_white(gtk_widget_get_colormap(widget), &white);
-    gdk_gc_set_foreground(snippet->gc, &white);
-
-    gtk_widget_get_size_request(widget, &width, &height);
-
-    gdk_draw_rectangle(GDK_DRAWABLE(widget->window), GTK_SNIPPET(widget)->gc,
-                       TRUE, 0, 0, width, height);
-
-    gdk_color_parse("#ff0000", &red);
-    gdk_color_alloc(gtk_widget_get_colormap(widget), &red);
-    gdk_gc_set_foreground(snippet->gc, &red);
-
-
-    index = 0;
-    iter = pango_layout_get_iter(snippet->layout);
-
-#if 0
-    for (; index < snippet->info_count; index++, pango_layout_iter_next_line(iter))
-    {
-        if (!snippet->info[index].bp_set) continue;
-
-        pango_layout_iter_get_line_yrange(iter, &y0, &y1);
-
-
-
-        gdk_draw_arc(GDK_DRAWABLE(widget->window), GTK_SNIPPET(widget)->gc,
-                     FALSE, MARGIN_SPACE, y0 / PANGO_SCALE,
-                     snippet->line_height - 2, snippet->line_height - 2,
-                     0, 360 * 64);
-
-    }
-#endif
-
-    pango_layout_iter_free(iter);
-
-    gdk_gc_set_foreground(snippet->gc, &values.foreground);
-
-    gdk_draw_layout(GDK_DRAWABLE(widget->window), snippet->gc,
-                    2 * MARGIN_SPACE + snippet->line_height, 0,
-                    snippet->layout);
-
-
-    y0 = 0;
-
-    for (/* l! */liter = snippet->lines; liter != NULL; liter = g_rendering_line_get_next_iter(snippet->lines, liter))
-    {
-        g_rendering_line_draw(liter, GDK_DRAWABLE(widget->window), snippet->gc,
-                              MARGIN_SPACE, 2 * MARGIN_SPACE + snippet->line_height,
-                              y0, snippet->line_height);
-
-        y0 += snippet->line_height;
-
-    }
-
-
-}
-
-
-static void
-gtk_snippet_destroy(GtkObject *object)
-{
-  GtkSnippet *cpu;
-  GtkSnippetClass *klass;
-
-  g_return_if_fail(object != NULL);
-  g_return_if_fail(GTK_IS_SNIPPET(object));
-
-  cpu = GTK_SNIPPET(object);
-
-  klass = gtk_type_class(gtk_widget_get_type());
-
-  if (GTK_OBJECT_CLASS(klass)->destroy) {
-     (* GTK_OBJECT_CLASS(klass)->destroy) (object);
-  }
-}
-
-
-
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : snippet = composant GTK à mettre à jour.                     *
-*                show    = état de l'affichage auquel parvenir.               *
-*                                                                             *
-*  Description : Choisit d'afficher les adresses virtuelles ou non.           *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void gtk_snippet_show_vaddress(GtkSnippet *snippet, gboolean show)
-{
-    snippet->show_vaddress = show;
-
-    gtk_snippet_build_content(snippet);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : snippet = composant GTK à mettre à jour.                     *
-*                show    = état de l'affichage auquel parvenir.               *
-*                                                                             *
-*  Description : Choisit d'afficher le code brut ou non.                      *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void gtk_snippet_show_code(GtkSnippet *snippet, gboolean show)
-{
-    snippet->show_code = show;
-
-    gtk_snippet_build_content(snippet);
-
-}
-
-
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : snippet = composant GTK à mettre à jour.                     *
-*                format  = format du binaire affiché.                         *
-*                                                                             *
-*  Description : Définit le format auquel le contenu est lié.                 *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void gtk_snippet_set_format(GtkSnippet *snippet, const exe_format *format)
-{
-    snippet->format = format;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : snippet = composant GTK à mettre à jour.                     *
-*                lines   = informations à intégrer.                           *
-*                                                                             *
-*  Description : Définit les lignes du bloc de représentation.                *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void gtk_snippet_set_rendering_lines(GtkSnippet *snippet, GRenderingLine *lines)
-{
-    GRenderingLine *iter;                   /* Boucle de parcours          */
-
-    snippet->lines = lines;
-
-    for (iter = lines; iter != NULL; iter = g_rendering_line_get_next_iter(lines, iter))
-        g_signal_connect(iter, "rendering-line-flags-changed",
-                         G_CALLBACK(gtk_snippet_update_margin), snippet);
-
-    g_rendering_line_update_bin_len(lines);
-
-    gtk_snippet_recompute_size_request(snippet);
-
-}
-
-
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : snippet = composant GTK à mettre à jour.                     *
-*                                                                             *
-*  Description : Réclame une nouvelle taille adaptée au contenu présent.      *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void gtk_snippet_recompute_size_request(GtkSnippet *snippet)
-{
-    int width;                              /* Largeur de l'objet actuelle */
-    int height;                             /* Hauteur de l'objet actuelle */
-
-    g_rendering_line_get_size(snippet->lines, &width, &height, &snippet->line_height);
-
-    gtk_widget_set_size_request(GTK_WIDGET(snippet),
-                                width + 2 * MARGIN_SPACE + snippet->line_height,
-                                height);
-
-}
-
-
-
-
-
-
-
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : snippet = composant GTK à mettre à jour.                     *
-*                                                                             *
-*  Description : Définit le contenu visuel à partir des infos enregistrées.   *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void gtk_snippet_build_content(GtkSnippet *snippet)
-{
-#if 0
-    const uint8_t *exe_content;             /* Contenu binaire global      */
-    off_t max_bin_len;                      /* Taille max du code brut     */
-    unsigned int i;                         /* Boucle de traitement        */
-    off_t bin_len;                          /* Taille d'instruction        */
-    char *bin_code;                         /* Tampon du code binaire      */
-    char *content;                          /* Contenu à définir           */
-    size_t content_len;                     /* Taille du contenu           */
-    AdressMode mode;                        /* Affichage des adresses      */
-    char buffer[CONTENT_BUFFER_LEN];        /* Zone tampon à utiliser      */
-    off_t bin_offset;                       /* Début de l'instruction      */
-    off_t k;                                /* Boucle de parcours #2       */
-    off_t j;                                /* Boucle de parcours #1       */
-    int width;                              /* Largeur de l'objet actuelle */
-    int height;                             /* Hauteur de l'objet actuelle */
-    PangoLayoutIter *iter;                  /* Boucle de parcours          */
-    int y0;                                 /* Ordonnée du haut d'une ligne*/
-    int y1;                                 /* Ordonnée du bas d'une ligne */
-
-    /* Calcul de la largeur maximale brute si besoin est */
-    if (snippet->show_code)
-    {
-        exe_content = get_exe_content(snippet->format, NULL);
-
-        max_bin_len = 1;
-
-        for (i = 0; i < snippet->info_count; i++)
-        {
-            /* Commentaire uniquement */
-            if (snippet->info[i].instr == NULL) continue;
-
-            get_asm_instr_offset_and_length(snippet->info[i].instr, NULL, &bin_len);
-            if (bin_len > max_bin_len) max_bin_len = bin_len;
-
-        }
-
-        max_bin_len = max_bin_len * 2 + (max_bin_len - 1);
-        bin_code = (char *)calloc(max_bin_len + 1, sizeof(char));
-
-    }
-
-    content_len = strlen("<tt>") + 1;
-    content = (char *)calloc(content_len, sizeof(char));
-    strcpy(content, "<tt>");
-
-    mode = ADM_32BITS;  /* FIXME */
-
-    for (i = 0; i < snippet->info_count; i++)
-    {
-        if (i > 0)
-        {
-            content = (char *)realloc(content, ++content_len * sizeof(char));
-            strcat(content, "\n");
-        }
-
-        /* Eventuelle adresse virtuelle */
-
-        if (snippet->show_vaddress)
-        {
-            switch (mode)
-            {
-                case ADM_32BITS:
-                    snprintf(buffer, CONTENT_BUFFER_LEN,
-                             "<span foreground='#333333'>0x%08llx</span>", 
-                             snippet->info[i].offset);
-                    break;
-
-                case ADM_64BITS:
-                    snprintf(buffer, CONTENT_BUFFER_LEN,
-                             "<span foreground='#333333'>0x%16llx</span>", 
-                             snippet->info[i].offset);
-                    break;
-
-            }
-
-            content_len += strlen(buffer);
-            content = (char *)realloc(content, content_len * sizeof(char));
-            strcat(content, buffer);
-
-        }
-
-        /* Eventuel code brut */
-
-        if (snippet->show_code)
-        {
-            k = 0;
-
-            if (snippet->info[i].instr != NULL)
-            {
-                get_asm_instr_offset_and_length(snippet->info[i].instr, &bin_offset, &bin_len);
-
-                for (j = 0; j < bin_len; j++)
-                {
-                    if ((j + 1) < bin_len)
-                        k += snprintf(&bin_code[j * (2 + 1)], 4, "%02hhx ", exe_content[bin_offset + j]);
-                    else
-                        k += snprintf(&bin_code[j * (2 + 1)], 3, "%02hhx", exe_content[bin_offset + j]);
-                }
-
-            }
- 
-            for (; k < max_bin_len; k++)
-                snprintf(&bin_code[k], 2, " ");
-
-            if (snippet->show_vaddress) content_len += strlen("\t");
-            content_len += strlen(bin_code);
-            content = (char *)realloc(content, content_len * sizeof(char));
-            if (snippet->show_vaddress) strcat(content, "\t");
-            strcat(content, bin_code);
-
-        }
-
-        /* Eventuelle instruction */
-
-        if (snippet->info[i].instr != NULL)
-        {
-            print_hinstruction(snippet->proc, snippet->format, snippet->info[i].instr, buffer, CONTENT_BUFFER_LEN, ASX_INTEL);
-
-            if (snippet->show_vaddress || snippet->show_code) content_len += strlen("\t");
-            content_len += strlen(buffer);
-
-            content = (char *)realloc(content, content_len * sizeof(char));
-            if (snippet->show_vaddress || snippet->show_code) strcat(content, "\t");
-            strcat(content, buffer);
-
-        }
-
-        /* Eventuel commantaire */
-
-        if (snippet->info[i].comment != NULL)
-        {
-            if (snippet->show_vaddress || snippet->show_code) content_len += strlen("\t");
-            content_len += strlen("<b><span foreground='#003300'>; ") + strlen(snippet->info[i].comment) + strlen("</span></b>");
-
-            content = (char *)realloc(content, content_len * sizeof(char));
-            if (snippet->show_vaddress || snippet->show_code) strcat(content, "\t");
-            strcat(content, "<b><span foreground='#003300'>; ");
-            strcat(content, snippet->info[i].comment);
-            strcat(content, "</span></b>");
-
-        }
-
-    }
-
-    content_len += strlen("</tt>");
-    content = (char *)realloc(content, content_len * sizeof(char));
-    strcat(content, "</tt>");
-
-    if (snippet->show_code) free(bin_code);
-
-    pango_layout_set_markup(snippet->layout, content, content_len - 1);
-
-    pango_layout_get_pixel_size(snippet->layout, &width, &height);
-
-    snippet->line_height = 0;
-    iter = pango_layout_get_iter(snippet->layout);
-
-    do
-    {
-        pango_layout_iter_get_line_yrange(iter, &y0, &y1);
-        snippet->line_height = MAX(snippet->line_height, (y1 - y0) / PANGO_SCALE);
-    }
-    while (pango_layout_iter_next_line(iter));
-
-    pango_layout_iter_free(iter);
-
-    //gtk_widget_set_size_request(GTK_WIDGET(snippet), width + 2 * MARGIN_SPACE + snippet->line_height, height);
-#endif
-}
-
-
-
-
-
-
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : snippet  = composant GTK à consulter.                        *
-*                address  = adresse à présenter à l'écran.                    *
-*                position = position verticale au sein du composant. [OUT]    *
-*                                                                             *
-*  Description : Indique la position verticale d'une adresse donnée.          *
-*                                                                             *
-*  Retour      : TRUE si l'adresse fait partie du composant, FALSE sinon.     *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-gboolean gtk_snippet_get_address_vposition(GtkSnippet *snippet, uint64_t address, gint *position)
-{
-    unsigned int i;                         /* Boucle de parcours          */
-
-    *position = 0;
-#if 0
-    for (i = 0; i < snippet->info_count; i++)
-    {
-        if (snippet->info[i].offset == address) break;
-        else *position += snippet->line_height;
-    }
-#endif
-    return false;//(i < snippet->info_count);
-
-}
-
diff --git a/src/gtkext/gtksnippet.h b/src/gtkext/gtksnippet.h
deleted file mode 100644
index aa388a2..0000000
--- a/src/gtkext/gtksnippet.h
+++ /dev/null
@@ -1,117 +0,0 @@
-
-/* OpenIDA - Outil d'analyse de fichiers binaires
- * gtksnippet.h - prototypes pour l'affichage d'un fragment de code d'assemblage
- *
- * Copyright (C) 2008 Cyrille Bagard
- *
- *  This file is part of OpenIDA.
- *
- *  OpenIDA 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.
- *
- *  OpenIDA 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef _GTK_SNIPPET_H
-#define _GTK_SNIPPET_H
-
-
-#include <stdint.h>
-#include <gtk/gtk.h>
-#include <cairo.h>
-
-
-#include "../analysis/line.h"
-#include "../format/exe_format.h"
-
-
-
-G_BEGIN_DECLS
-
-
-#define GTK_SNIPPET(obj) GTK_CHECK_CAST(obj, gtk_snippet_get_type (), GtkSnippet)
-#define GTK_SNIPPET_CLASS(klass) GTK_CHECK_CLASS_CAST(klass, gtk_snippet_get_type(), GtkSnippetClass)
-#define GTK_IS_SNIPPET(obj) GTK_CHECK_TYPE(obj, gtk_snippet_get_type())
-
-
-typedef struct _GtkSnippet GtkSnippet;
-typedef struct _GtkSnippetClass GtkSnippetClass;
-
-
-
-
-
-struct _GtkSnippet {
-
-    GtkWidget widget;                       /* Présence obligatoire en 1er */
-
-    bool show_vaddress;                     /* Affichage des adresses ?    */
-    bool show_code;                         /* Affichage du code brut ?    */
-
-    PangoLayout *layout;                    /* Moteur de rendu du code ASM */
-    GdkGC *gc;                              /* Contexte graphique du rendu */
-    int line_height;                        /* Hauteur maximale des lignes */
-
-    const exe_format *format;               /* Format du contenu bianire   */
-
-    GRenderingLine *lines;                  /* Contenu à représenter       */
-
-
-  gint sel;
-};
-
-struct _GtkSnippetClass {
-  GtkWidgetClass parent_class;
-};
-
-
-GtkType gtk_snippet_get_type(void);
-void gtk_snippet_set_sel(GtkSnippet *cpu, gint sel);
-
-GtkWidget * gtk_snippet_new(void);
-
-
-
-
-/* Choisit d'afficher les adresses virtuelles ou non. */
-void gtk_snippet_show_vaddress(GtkSnippet *, gboolean);
-
-/* Choisit d'afficher le code brut ou non. */
-void gtk_snippet_show_code(GtkSnippet *, gboolean);
-
-
-
-
-/* Définit le format auquel le contenu est lié. */
-void gtk_snippet_set_format(GtkSnippet *, const exe_format *);
-
-/* Définit les lignes du bloc de représentation. */
-void gtk_snippet_set_rendering_lines(GtkSnippet *, GRenderingLine *);
-
-/* Définit le contenu visuel à partir des infos enregistrées. */
-void gtk_snippet_build_content(GtkSnippet *);
-
-
-
-/* Indique la position verticale d'une adresse donnée. */
-gboolean gtk_snippet_get_address_vposition(GtkSnippet *, uint64_t, gint *);
-
-
-
-G_END_DECLS
-
-
-
-
-
-
-#endif  /* _GTK_SNIPPET_H */
diff --git a/src/project.c b/src/project.c
index 20ec7c3..dc1efd1 100644
--- a/src/project.c
+++ b/src/project.c
@@ -33,6 +33,28 @@
 #include "xdg.h"
 #include "xml.h"
 #include "gtkext/easygtk.h"
+#include "gtkext/gtkblockview.h"
+#include "gtkext/gtkgraphview.h"
+
+
+
+
+/* Conservation d'un binaire chargé */
+typedef struct _loaded_binary
+{
+    openida_binary *binary;                 /* Binaire en question         */
+
+    GtkWidget *views[BVW_COUNT];            /* Composants pour l'affichage */
+
+} loaded_binary;
+
+
+/* Met en place un nouveau binaire pour un projet. */
+loaded_binary *load_openida_binary(openida_binary *);
+
+/* Fournit un support d'affichage donné pour un binaire chargé. */
+GtkWidget *get_loaded_binary_view(const loaded_binary *, BinaryView);
+
 
 
 
@@ -42,7 +64,7 @@ struct openida_project
 {
     char *filename;                         /* Lieu d'enregistrement       */
 
-    openida_binary **binaries;              /* Fichiers binaires associés  */
+    loaded_binary **binaries;               /* Fichiers binaires associés  */
     size_t binaries_count;                  /* Nombre de ces fichiers      */
 
 
@@ -55,6 +77,93 @@ struct openida_project
 
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary = binaire chargé à encadrer.                          *
+*                                                                             *
+*  Description : Met en place un nouveau binaire pour un projet.              *
+*                                                                             *
+*  Retour      : Adresse de la structure intermédiaire ou NULL si aucune (!). *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+loaded_binary *load_openida_binary(openida_binary *binary)
+{
+    loaded_binary *result;                  /* Structure à renvoyer        */
+    BinaryView i;                           /* Boucle de parcours          */
+    GtkWidget *scrolledwindow;              /* Surface d'exposition        */
+    GtkWidget *view;                        /* Affichage du binaire        */
+
+    result = (loaded_binary *)calloc(1, sizeof(loaded_binary));
+
+    result->binary = binary;
+
+    for (i = 0; i < BVW_COUNT; i++)
+    {
+        scrolledwindow = qck_create_scrolled_window(NULL, NULL);
+
+        switch (i)
+        {
+            default: /* GCC ! */
+            case BVW_BLOCK:
+                view = gtk_block_view_new();
+                break;
+            case BVW_GRAPH:
+                view = gtk_graph_view_new();
+                break;
+        }
+
+        if (i == 0)
+        gtk_block_view_set_rendering_lines(GTK_BLOCK_VIEW(view), get_openida_binary_lines(binary));
+
+        gtk_widget_show(view);
+
+        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolledwindow), view);
+
+        result->views[i] = scrolledwindow;
+
+    }
+
+    return result;
+
+}
+
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : binary = binaire chargé et encadré.                          *
+*                view   = type d'affichage requis.                            *
+*                                                                             *
+*  Description : Fournit un support d'affichage donné pour un binaire chargé. *
+*                                                                             *
+*  Retour      : Composant GTK dédié à un affichage particulier.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *get_loaded_binary_view(const loaded_binary *binary, BinaryView view)
+{
+    return binary->views[view];
+
+}
+
+
+
+
+
+
+
+
+
 
 /******************************************************************************
 *                                                                             *
@@ -277,15 +386,10 @@ bool write_openida_project_to_xml(openida_project *project, const char *filename
 
 void attach_binary_to_openida_project(openida_project *project, openida_binary *binary)
 {
-    project->binaries = (openida_binary **)realloc(project->binaries,
-                                                   ++project->binaries_count * sizeof(openida_binary *));
-
-
-
-
-
-    project->binaries[project->binaries_count - 1] = binary;
+    project->binaries = (loaded_binary **)realloc(project->binaries,
+                                                   ++project->binaries_count * sizeof(loaded_binary *));
 
+    project->binaries[project->binaries_count - 1] = load_openida_binary(binary);
 
 }
 
@@ -305,6 +409,7 @@ void attach_binary_to_openida_project(openida_project *project, openida_binary *
 
 void detach_binary_to_openida_project(openida_project *project, openida_binary *binary)
 {
+#if 0
     size_t i;                               /* Boucle de parcours          */
 
     for (i = 0; i < project->binaries_count; i++)
@@ -315,6 +420,39 @@ void detach_binary_to_openida_project(openida_project *project, openida_binary *
 
     project->binaries = (openida_binary **)realloc(project->binaries,
                                                    --project->binaries_count * sizeof(openida_binary *));
+#endif
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : project = projet à consulter.                                *
+*                binary  = binaire chargé, encadré et concerné.               *
+*                view    = type d'affichage requis.                           *
+*                                                                             *
+*  Description : Fournit un support d'affichage donné pour un binaire chargé. *
+*                                                                             *
+*  Retour      : Composant GTK dédié à un affichage particulier.              *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GtkWidget *get_view_for_openida_project_binary(const openida_project *project, const openida_binary *binary, BinaryView view)
+{
+    GtkWidget *result;                      /* Composant GTK à retourner   */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = NULL;
+
+    for (i = 0; i < project->binaries_count; i++)
+        if (project->binaries[i]->binary == binary)
+        {
+            result = get_loaded_binary_view(project->binaries[i], view);
+            break;
+        }
+
+    return result;
 
 }
 
diff --git a/src/project.h b/src/project.h
index 64c32bd..cf5613d 100644
--- a/src/project.h
+++ b/src/project.h
@@ -25,10 +25,25 @@
 #define _PROJECT_H
 
 
+#include <gtk/gtkwidget.h>
+
+
 #include "analysis/binary.h"
 
 
 
+/* Type de représentations */
+typedef enum _BinaryView
+{
+    BVW_BLOCK,                              /* Version basique             */
+    BVW_GRAPH,                              /* Affichage en graphqie       */
+
+    BVW_COUNT
+
+} BinaryView;
+
+
+
 /* Propriétés d'un ensemble de fichiers ouverts */
 typedef struct openida_project openida_project;
 
@@ -66,6 +81,9 @@ void attach_binary_to_openida_project(openida_project *, openida_binary *);
 /* Détache un fichier donné à un projet donné. */
 void detach_binary_to_openida_project(openida_project *, openida_binary *);
 
+/* Fournit un support d'affichage donné pour un binaire chargé. */
+GtkWidget *get_view_for_openida_project_binary(const openida_project *, const openida_binary *, BinaryView);
+
 /* Fournit l'ensemble des binaires associés à un projet. */
 const openida_binary **get_openida_project_binaries(const openida_project *, size_t *);
 
-- 
cgit v0.11.2-87-g4458