summaryrefslogtreecommitdiff
path: root/src/glibext/gbufferview.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2016-05-01 01:35:26 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2016-05-01 01:35:26 (GMT)
commitef68a3dd8ff259200ca7f088eecc9ce35e7ffe8f (patch)
treef89cccbe3d0ac421b41cc49a28bee32e8903e45a /src/glibext/gbufferview.c
parent89ceb1e27afed0bac789e33c2f10eade01747d88 (diff)
Handled all width measures per view in a dedicated manager.
Diffstat (limited to 'src/glibext/gbufferview.c')
-rw-r--r--src/glibext/gbufferview.c1330
1 files changed, 1330 insertions, 0 deletions
diff --git a/src/glibext/gbufferview.c b/src/glibext/gbufferview.c
new file mode 100644
index 0000000..214b212
--- /dev/null
+++ b/src/glibext/gbufferview.c
@@ -0,0 +1,1330 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * gbufferview.c - affichage d'une vue particulière d'un tampon de lignes
+ *
+ * Copyright (C) 2016 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * 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 "gbufferview.h"
+
+
+
+/* Vue d'un tampon pour code désassemblé (instance) */
+struct _GBufferView
+{
+ GObject parent; /* A laisser en premier */
+
+ GCodeBuffer *buffer; /* Tampon de code visualisé */
+
+ vmpa2t start; /* Première ligne intégrée */
+ vmpa2t end; /* Dernière ligne intégrée */
+
+ size_t first; /* Indice de la première ligne */
+ size_t last; /* Indice de la dernière ligne */
+
+ union
+ {
+ const GWidthTracker *ext_tracker; /* Suivi externe des largeurs */
+ GWidthTracker *int_tracker; /* Suivi interne des largeurs */
+ GWidthTracker *tracker; /* Suivi pour usage interne */
+ };
+
+ bool unrestricted; /* Validité des informations */
+
+ segcnt_list *highlighted; /* Segments mis en évidence */
+ bool external; /* Note l'origine de la liste */
+
+};
+
+/* Vue d'un tampon pour code désassemblé (classe) */
+struct _GBufferViewClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+ gint line_height; /* Hauteur maximale des lignes */
+ gint left_margin; /* Marge gauche + espace */
+ gint left_text; /* Début d'impression du code */
+
+ /* Signaux */
+
+ void (* need_redraw) (GBufferView *);
+
+};
+
+
+/* Procède à l'initialisation d'une classe de vue de tampon. */
+static void g_buffer_view_class_init(GBufferViewClass *);
+
+/* Procède à l'initialisation d'une vue d'un tampon pour code. */
+static void g_buffer_view_init(GBufferView *);
+
+/* Supprime toutes les références externes. */
+static void g_buffer_view_dispose(GBufferView *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_buffer_view_finalize(GBufferView *);
+
+/* Accompagne une variation de la quantité de lignes du tampon. */
+static void on_buffer_size_changed(const GCodeBuffer *, bool, size_t, size_t, GBufferView *);
+
+/* Réagit à un changement de contenu d'une ligne donnée. */
+static void on_buffer_line_changed(GCodeBuffer *, GBufferLine *, GBufferSegment *, GBufferView *);
+
+
+
+/* Détermine le type de la vue d'un tampon pour code désassemblé. */
+G_DEFINE_TYPE(GBufferView, g_buffer_view, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : class = classe de composant GTK à initialiser. *
+* *
+* Description : Procède à l'initialisation d'une classe de vue de tampon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_buffer_view_class_init(GBufferViewClass *class)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(class);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_buffer_view_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_buffer_view_finalize;
+
+ class->line_height = 17;
+ class->left_margin = 2 * class->line_height;
+ class->left_text = 2.5 * class->line_height;
+
+
+ g_signal_new("need-redraw",
+ G_TYPE_BUFFER_VIEW,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(GBufferViewClass, need_redraw),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 0);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = composant GLib à initialiser. *
+* *
+* Description : Procède à l'initialisation d'une vue d'un tampon pour code. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_buffer_view_init(GBufferView *view)
+{
+ view->unrestricted = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_buffer_view_dispose(GBufferView *view)
+{
+ g_object_unref(G_OBJECT(view->buffer));
+
+ G_OBJECT_CLASS(g_buffer_view_parent_class)->dispose(G_OBJECT(view));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_buffer_view_finalize(GBufferView *view)
+{
+ if (!view->external)
+ exit_segment_content_list(view->highlighted);
+
+ G_OBJECT_CLASS(g_buffer_view_parent_class)->finalize(G_OBJECT(view));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : buffer = tampon à représenter à l'écran. *
+* widget = composant GTK de destination pour le rendu. *
+* *
+* Description : Crée une nouvelle vue d'un tampon pour code désassemblé. *
+* *
+* Retour : Composant GTK créé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBufferView *g_buffer_view_new(GCodeBuffer *buffer, segcnt_list *highlighted)
+{
+ GBufferView *result; /* Composant à retourner */
+
+ result = g_object_new(G_TYPE_BUFFER_VIEW, NULL);
+
+ g_object_ref(G_OBJECT(buffer));
+ result->buffer = buffer;
+
+ g_buffer_view_restrict(result, NULL, NULL);
+
+ g_code_buffer_register_view_callback(buffer,
+ (buffer_size_changed_cb)on_buffer_size_changed,
+ G_OBJECT(result));
+
+ g_signal_connect(buffer, "line-changed", G_CALLBACK(on_buffer_line_changed), result);
+
+ if (highlighted != NULL)
+ result->highlighted = highlighted;
+ else
+ result->highlighted = init_segment_content_list();
+
+ result->external = (highlighted != NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : buffer = tampon de lignes cohérentes à manipuler. *
+* added = indication sur la variation de la taille du tampon. *
+* index = indice de la première ligne à traiter. *
+* count = nombre de lignes à traiter. *
+* view = vue active du tampon de lignes concerné. *
+* *
+* Description : Accompagne une variation de la quantité de lignes du tampon. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_buffer_size_changed(const GCodeBuffer *buffer, bool added, size_t index, size_t count, GBufferView *view)
+{
+ size_t i; /* Boucle de parcours */
+ GBufferLine *line; /* Ligne à manipuler */
+ const vmpa2t *addr; /* Localisation de ligne */
+
+ /**
+ * Il n'y a pas besoin de verrou ici car la fonction est appelée directement par le tampon.
+ * D'autre part, on considère qu'il y a toujours une ligne aux adresses de borne, si la vue est bornée.
+ */
+
+ if (added)
+ {
+ if (view->unrestricted)
+ view->last += count;
+
+ else
+ {
+ /* Avant la zone représentée ? */
+ if (index < view->first)
+ {
+ view->first += count;
+ view->last += count;
+ }
+
+ /* Juste avant la zone représentée ? */
+ else if (view->first == index)
+ for (i = 0; i < count; i++)
+ {
+ line = g_code_buffer_find_line_by_index(buffer, index + i);
+ addr = get_mrange_addr(g_buffer_line_get_range(line));
+
+ if (cmp_vmpa(&view->start, addr) == 0)
+ {
+ view->first++;
+ view->last++;
+ }
+ else
+ break;
+
+ }
+
+ /* Dans la zone représentée ? */
+ else if (view->first < index && index <= view->last)
+ view->last += count;
+
+ /* Juste après la vue représentée ? */
+ else if ((view->last + 1) == index)
+ for (i = 0; i < count; i++)
+ {
+ line = g_code_buffer_find_line_by_index(buffer, index + i);
+ addr = get_mrange_addr(g_buffer_line_get_range(line));
+
+ if (cmp_vmpa(&view->end, addr) == 0)
+ view->last++;
+ else
+ break;
+
+ }
+
+ g_width_tracker_update_added(view->int_tracker, index, count);
+
+ }
+
+ }
+
+ else
+ {
+ if (view->unrestricted)
+ view->last -= count;
+
+ else
+ {
+ /* Avant la zone représentée ? */
+ if (index <= view->first)
+ {
+ view->first -= count;
+ view->last -= count;
+ }
+
+ /* Dans la zone représentée ? */
+ else if (view->first < index && index <= view->last)
+ view->last -= count;
+
+ }
+
+ g_width_tracker_update_deleted(view->int_tracker, index, index + count - 1);
+
+ }
+
+ g_signal_emit_by_name(view, "need-redraw");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : buffer = tampon de lignes cohérentes à manipuler. *
+* line = ligne dont la définition vient d'évoluer. *
+* segment = éventuel segment qui vient d'évoluer ou NULL. *
+* view = vue active du tampon de lignes concerné. *
+* *
+* Description : Réagit à un changement de contenu d'une ligne donnée. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void on_buffer_line_changed(GCodeBuffer *buffer, GBufferLine *line, GBufferSegment *segment, GBufferView *view)
+{
+ const vmpa2t *addr; /* Localisation de ligne */
+
+ addr = get_mrange_addr(g_buffer_line_get_range(line));
+
+ if (cmp_vmpa(&view->start, addr) <= 0 && cmp_vmpa(addr, &view->end) <= 0)
+ g_signal_emit_by_name(view, "need-redraw");
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisateur à mettre à jour. *
+* first = première ligne à imprimer. *
+* last = première ligne hors cadre. *
+* *
+* Description : Restreint le champ d'application de l'affichage. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_buffer_view_restrict(GBufferView *view, const vmpa2t *start, const vmpa2t *end)
+{
+ const GWidthTracker *template; /* Suivi déjà en place */
+
+ if (!view->unrestricted)
+ g_object_unref(G_OBJECT(view->int_tracker));
+
+ view->unrestricted = (start == NULL || end == NULL);
+
+ template = g_code_buffer_get_width_tracker(view->buffer);
+
+ if (view->unrestricted)
+ {
+ view->first = 0;
+ view->last = g_code_buffer_count_lines(view->buffer) - 1;
+
+ view->ext_tracker = template;
+
+ }
+
+ else
+ {
+ copy_vmpa(&view->start, start);
+ copy_vmpa(&view->end, end);
+
+ view->first = g_code_buffer_get_index_from_address(view->buffer, start, true);
+ view->last = g_code_buffer_get_index_from_address(view->buffer, end, false);
+
+ view->ext_tracker = g_width_tracker_new_restricted(template, view->first, view->last);
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisateur à mettre à jour. *
+* first = première ligne à imprimer ou NULL. [OUT] *
+* last = première ligne hors cadre ou NULL. [OUT] *
+* *
+* Description : Indique le champ d'application de l'affichage. *
+* *
+* Retour : true si des restrictions particulières sont en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_buffer_view_get_restrictions(GBufferView *view, vmpa2t *start, vmpa2t *end)
+{
+ if (!view->unrestricted)
+ {
+ if (start != NULL) copy_vmpa(start, &view->start);
+ if (end != NULL) copy_vmpa(end, &view->end);
+ }
+
+ return !view->unrestricted;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisateur à consulter. *
+* *
+* Description : Fournit le tampon de code lié à un visualisateur donné. *
+* *
+* Retour : Tampon de code associé au gestionnaire d'affichage. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GCodeBuffer *g_buffer_view_get_buffer(const GBufferView *view)
+{
+ g_object_ref(G_OBJECT(view->buffer));
+
+ return view->buffer;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à consulter. *
+* *
+* Description : Fournit la hauteur d'impression d'une ligne visualisée. *
+* *
+* Retour : Hauteur de ligne en pixel. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gint g_buffer_view_get_line_height(GBufferView *view)
+{
+ return G_BUFFER_VIEW_GET_CLASS(view)->line_height;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à consulter. *
+* display = règles d'affichage des colonnes modulables. *
+* *
+* Description : Fournit la largeur requise par une visualisation. *
+* *
+* Retour : Dimension calculée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gint g_buffer_view_get_width(GBufferView *view, const bool *display)
+{
+ gint result; /* Taille à retourner */
+
+ result = G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+
+ result += g_width_tracker_get_width(view->tracker, display);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à consulter. *
+* display = règles d'affichage des colonnes modulables. *
+* *
+* Description : Fournit la largeur requise pour dépasser les marges gauches. *
+* *
+* Retour : Dimension calculée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gint g_buffer_view_get_margin(GBufferView *view, const bool *display)
+{
+ gint result; /* Taille à retourner */
+
+ result = G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+
+ result += g_width_tracker_get_margin(view->tracker, display);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à consulter. *
+* *
+* Description : Fournit la hauteur requise par une visualisation. *
+* *
+* Retour : Dimension calculée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+gint g_buffer_view_get_height(const GBufferView *view)
+{
+ gint result; /* Taille à retourner */
+
+ result = G_BUFFER_VIEW_GET_CLASS(view)->line_height;
+
+ result *= (view->last - view->first + 1);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = vue de tampon à mettre à jour. *
+* x = abscisse de la zone principale à traiter. *
+* y = ordonnée de la zone principale à traiter. *
+* display = règles d'affichage des colonnes modulables. *
+* caret = position du curseur à construire. [OUT] *
+* *
+* Description : Calcule la position idéale de curseur pour un point donné. *
+* *
+* Retour : Adresse si une a pu être déterminée, NULL sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const vmpa2t *g_buffer_view_compute_caret(GBufferView *view, gint x, gint y, const bool *display, GdkRectangle *caret)
+{
+ gint remaining; /* Copie de travail modifiable */
+ size_t index; /* Indice de ligne de tampon */
+ GBufferLine *line; /* Ligne à la position courante*/
+ GBufferSegment *segment; /* Segment présent sur la place*/
+ GBufferViewClass *class; /* Classe pour les vues */
+
+ remaining = x;
+
+ line = g_buffer_view_find_line_and_segment_at(view, &remaining, y, &index, display, &segment);
+
+ if (line == NULL) return NULL;
+ if (segment == NULL) printf(" -- no segment\n");
+ if (segment == NULL) return NULL;
+
+
+
+
+
+ printf("\n[BASE] orig = %d tronc = %d reste = %d dernier = %d largeur = %d\n",
+ x, x - remaining, remaining, g_buffer_segment_get_caret_position(segment, remaining),
+ g_buffer_segment_get_width(segment));
+
+ printf(" '%s'\n", g_buffer_segment_get_text(segment, false));
+
+
+ class = G_BUFFER_VIEW_GET_CLASS(view);
+
+ caret->x = /*view->left_text +*/ (x - remaining) + g_buffer_segment_get_caret_position(segment, remaining);
+
+ caret->y = (index - view->first) * class->line_height;
+
+ caret->width = 2;
+ caret->height = class->line_height;
+
+ return get_mrange_addr(g_buffer_line_get_range(line));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = vue de tampon à mettre à jour. *
+* line = ligne correspondant à la position. *
+* index = indice de cette même ligne dans le tampon. *
+* x = abscisse de la zone principale à traiter. *
+* display = règles d'affichage des colonnes modulables. *
+* caret = position du curseur à construire. [OUT] *
+* *
+* Description : Calcule la position idéale de curseur pour un point donné. *
+* *
+* Retour : Adresse si une a pu être déterminée, NULL sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const vmpa2t *g_buffer_view_compute_caret_full(GBufferView *view, GBufferLine *line, size_t index, gint x, const bool *display, GdkRectangle *caret)
+{
+ GBufferViewClass *class; /* Classe pour les vues */
+ gint offset; /* Point de travail modifiable */
+ const line_width_summary *summary; /* Résumé concis des largeurs */
+ gint base; /* Position absolue de segment */
+ GBufferSegment *segment; /* Segment visé par le pointeur*/
+
+ class = G_BUFFER_VIEW_GET_CLASS(view);
+
+ offset = x;
+
+ offset -= class->left_text;
+ if (offset < 0) return NULL;
+
+ summary = g_width_tracker_get_width_summary(view->tracker);
+
+ segment = g_buffer_line_get_segment_at(line, summary, display, &base, &offset, GDK_SCROLL_LEFT, true);
+ if (segment == NULL) return NULL;
+
+ caret->x = class->left_text + base + offset;
+
+ printf("caret Y : %zu -> %zu\n", view->first, index);
+
+ caret->y = (index - view->first) * class->line_height;
+
+ caret->width = 2;
+ caret->height = class->line_height;
+
+ return get_mrange_addr(g_buffer_line_get_range(line));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : line = ligne à venir consulter. *
+* caret = position du curseur à faire évoluer. *
+* ctrl = indique la demande d'un parcours rapide. *
+* dir = direction du parcours. *
+* display = règles d'affichage des colonnes modulables. *
+* *
+* Description : Déplace le curseur au sein d'une vue de tampon. *
+* *
+* Retour : true si un déplacement a été effectué, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool _g_buffer_view_move_caret(GBufferView *view, const GBufferLine *line, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display)
+{
+ bool result; /* Bilan à retourner */
+ gint offset; /* Point de travail modifiable */
+ const line_width_summary *summary; /* Résumé concis des largeurs */
+ gint base; /* Position absolue de segment */
+ GBufferSegment *segment; /* Segment visé par le pointeur*/
+
+
+
+ offset = caret->x;
+
+ offset -= G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+ if (offset < 0) return false;
+
+ summary = g_width_tracker_get_width_summary(view->tracker);
+
+ segment = g_buffer_line_get_segment_at(line, summary, display, &base, &offset, dir, false);
+
+ if (segment == NULL) printf(" ===== NO SEG...\n");
+
+ if (segment == NULL) return false;
+
+
+ printf(" ====== FIRST SEG :: %p ('%s')\n", segment, g_buffer_segment_get_text(segment, false));
+
+
+
+
+
+
+ //if (dir == GDK_SCROLL_LEFT || dir == GDK_SCROLL_RIGHT)
+ result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir);
+ //else
+ //result = true;
+
+ printf(" ====== MOVE 1 ? %d\n", result);
+
+ ///////////////////
+
+ if (!result)
+ {
+ base = 0;
+
+ segment = g_buffer_line_find_near_segment(line, segment, summary, display, dir, &offset);
+
+
+ printf(" ====== NEAR SEG :: %p ('%s')\n", segment, segment ? g_buffer_segment_get_text(segment, false) : NULL);
+
+ if (segment != NULL)
+ {
+
+ result = true;
+ //result = g_buffer_segment_move_caret(segment, &offset, ctrl, dir);
+
+ /*
+ if (result)
+ caret->x -= COL_MARGIN;
+ */
+
+ printf(" ====== MOVE 2 ? %d (offset=%d)\n", result, offset);
+
+
+ }
+
+
+ }
+
+
+ if (result)
+ printf(" ====== NEW CARET: %d -> %d\n", caret->x, G_BUFFER_VIEW_GET_CLASS(view)->left_text + base + offset);
+ else
+ printf(" ====== NO NEW CARET!\n");
+
+
+
+ if (result)
+ caret->x = G_BUFFER_VIEW_GET_CLASS(view)->left_text + base + offset;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = vue de tampon à mettre à jour. *
+* caret = position du curseur à faire évoluer. *
+* ctrl = indique la demande d'un parcours rapide. *
+* dir = direction du parcours. *
+* display = règles d'affichage des colonnes modulables. *
+* *
+* Description : Déplace le curseur au sein d'une vue de tampon. *
+* *
+* Retour : Adresse si une a pu être déterminée, VMPA_INVALID sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const vmpa2t *g_buffer_view_move_caret(GBufferView *view, GdkRectangle *caret, bool ctrl, GdkScrollDirection dir, const bool *display)
+{
+ const vmpa2t *result; /* Actualisation à renvoyer */
+ size_t index; /* Indice de ligne de tampon */
+ GBufferLine *line; /* Ligne sous le pointeur */
+
+
+ const line_width_summary *summary; /* Résumé concis des largeurs */
+ bool computed; /* Récursivité pris en compte */
+ gint left_pos; /* Retour à la ligne */
+ gint right_pos; /* Position d'extrème droite */
+ BufferLineColumn i; /* Boucle de parcours */
+ size_t first; /* Première ligne intégrée */
+ size_t last; /* Dernière ligne intégrée */
+
+
+
+
+ bool moved; /* Mémorisation d'une évolut° */
+
+
+
+
+
+
+
+
+
+ result = NULL;
+
+
+
+ line = g_buffer_view_find_line_at(view, caret->y, &index);
+ if (line == NULL) return NULL;
+
+ summary = g_width_tracker_get_width_summary(view->tracker);
+
+ computed = false;
+
+ switch (dir)
+ {
+ case GDK_SCROLL_UP:
+ case GDK_SCROLL_DOWN:
+ break;
+ case GDK_SCROLL_LEFT:
+ case GDK_SCROLL_RIGHT:
+ left_pos = G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+ if (display[BLC_PHYSICAL]) left_pos += summary->max_widths[BLC_PHYSICAL] + COL_MARGIN;
+ if (display[BLC_VIRTUAL]) left_pos += summary->max_widths[BLC_VIRTUAL] + COL_MARGIN;
+ if (display[BLC_BINARY]) left_pos += summary->max_widths[BLC_BINARY] + COL_MARGIN;
+ right_pos = left_pos;
+ for (i = BLC_ASSEMBLY_HEAD; i < BLC_COUNT; i++)
+ right_pos += summary->max_widths[i] + COL_MARGIN;
+
+ /*
+gint g_buffer_line_compute_max_width(const GBufferLine *line, BufferLineColumn index, const gint *max_widths)
+
+BufferLineColumn g_buffer_line_get_merge_start(const GBufferLine *line)
+ */
+
+ left_pos = G_BUFFER_VIEW_GET_CLASS(view)->left_text;
+
+ break;
+ default: /* GDK_SCROLL_SMOOTH */
+ break;
+ }
+
+ first = view->first;
+ last = view->last;
+
+ switch (dir)
+ {
+ case GDK_SCROLL_UP:
+
+ if (index > first)
+ {
+ line = g_code_buffer_find_line_by_index(view->buffer, index - 1);
+ result = g_buffer_view_compute_caret_full(view, line, index - 1, caret->x, display, caret);
+ }
+
+ break;
+
+ case GDK_SCROLL_DOWN:
+
+ if (index < last)
+ {
+ line = g_code_buffer_find_line_by_index(view->buffer, index + 1);
+ result = g_buffer_view_compute_caret_full(view, line, index + 1, caret->x, display, caret);
+ }
+
+ break;
+
+ case GDK_SCROLL_LEFT:
+
+ /*
+ line = g_buffer_view_find_line_at(view, caret->y, &index);
+ if (line == NULL) break;
+ */
+
+ moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_LEFT, display);
+
+ if (moved)
+ result = get_mrange_addr(g_buffer_line_get_range(line));
+
+ else if (index > first)
+ {
+ line = g_code_buffer_find_line_by_index(view->buffer, index - 1);
+ result = g_buffer_view_compute_caret_full(view, line, index - 1, INT_MAX, display, caret);
+ }
+
+ break;
+
+ case GDK_SCROLL_RIGHT:
+
+ /*
+ line = g_buffer_view_find_line_at(view, caret->y, &index);
+ if (line == NULL) break;
+ */
+
+ moved = _g_buffer_view_move_caret(view, line, caret, ctrl, GDK_SCROLL_RIGHT, display);
+
+ if (moved)
+ result = get_mrange_addr(g_buffer_line_get_range(line));
+
+ else if (index < last)
+ {
+ line = g_code_buffer_find_line_by_index(view->buffer, index + 1);
+ result = g_buffer_view_compute_caret_full(view, line, index + 1, left_pos, display, caret);
+ }
+
+ break;
+
+ default: /* GDK_SCROLL_SMOOTH */
+ break;
+
+ }
+
+ /*
+ printf(" --- CARET --- moved = %d index = %d result = %p\n",
+ moved, index, result);
+ */
+
+
+ /*
+ if (result && !computed)
+ result = g_buffer_view_compute_caret_full(view, caret->x, caret->y, caret, display, NULL);
+ */
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = vue de tampon à mettre à jour. *
+* *
+* Description : Supprime toute mise en évidence de segments. *
+* *
+* Retour : true si un besoin d'actualisation d'affichage se fait sentir.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_buffer_view_unhighlight_segments(GBufferView *view)
+{
+ bool result; /* Bilan d'action à renvoyer */
+
+ result = reset_segment_content_list(view->highlighted);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = vue de tampon à mettre à jour. *
+* x = abscisse de la zone principale à traiter. *
+* y = ordonnée de la zone principale à traiter. *
+* display = règles d'affichage des colonnes modulables. *
+* *
+* Description : Surligne tous les segments similaires à celui sous la souris.*
+* *
+* Retour : true si un besoin d'actualisation d'affichage se fait sentir.*
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_buffer_view_highlight_segments(GBufferView *view, gint x, gint y, const bool *display)
+{
+ bool need_redraw; /* Besoin d'actualisation ? */
+ GBufferSegment *segment; /* Segment sélectionnable */
+
+ if (view->highlighted != NULL)
+ need_redraw = g_buffer_view_unhighlight_segments(view);
+ else
+ need_redraw = false;
+
+ g_buffer_view_find_line_and_segment_at(view, &x, y, NULL, display, &segment);
+
+ if (segment)
+ need_redraw |= add_segment_content_to_selection_list(view->highlighted, segment);
+
+ if (need_redraw)
+ g_signal_emit_by_name(view, "need-redraw");
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à représenter. *
+* cr = contexte graphique dédié à la procédure. *
+* fake_x = abscisse réelle du point 0 à l'écran. *
+* fake_y = ordonnée réelle du point 0 à l'écran. *
+* area = position et surface à traiter. *
+* display = règles d'affichage des colonnes modulables. *
+* selected = ordonnée d'une ligne sélectionnée ou NULL. *
+* *
+* Description : Imprime la visualisation du tampon de code désassemblé. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_buffer_view_draw(const GBufferView *view, cairo_t *cr, gint fake_x, gint fake_y, const cairo_rectangle_int_t *area, const bool *display, const gint *selected)
+{
+ GBufferViewClass *class; /* Classe pour les vues */
+ gint real_x; /* Abscisse réelle pour tampon */
+ gint real_y; /* Ordonnée réelle pour tampon */
+ size_t first; /* Première ligne visée */
+ size_t last; /* Dernière ligne visée + 1 */
+ gint y; /* Point de départ + décallage */
+ bool wait_selection; /* Sélection déjà passée ? */
+ gint rel_selected; /* Position relative de sélect°*/
+ size_t i; /* Boucle de parcours */
+ GBufferLine *line; /* Ligne à dessiner à l'écran */
+ line_width_summary summary; /* Résumé concis des largeurs */
+
+ class = G_BUFFER_VIEW_GET_CLASS(view);
+
+ real_x = fake_x + class->left_text;
+ real_y = fake_y + area->y;
+
+ first = view->first;
+ first += (real_y / class->line_height);
+
+ last = first + (area->height / class->line_height);
+ if (area->height % class->line_height > 0) last++;
+
+ last = MIN(last, view->last);
+
+ y = area->y - (real_y % class->line_height);
+
+ wait_selection = true;
+
+ if (selected != NULL)
+ rel_selected = *selected - fake_y;
+
+ if (g_code_buffer_count_lines(view->buffer) > 0)
+ for (i = first; i <= last; i++)
+ {
+ /* Si sélection, on sousligne la ligne concernée */
+ if (wait_selection && selected != NULL && rel_selected == y)
+ {
+ cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.05);
+
+ cairo_rectangle(cr, area->x, y, area->width, class->line_height);
+ cairo_fill(cr);
+
+ wait_selection = false;
+
+ }
+
+ line = g_code_buffer_find_line_by_index(view->buffer, i);
+
+ if (i == first || (g_buffer_line_get_flags(line) & BLF_WIDTH_MANAGER))
+ g_width_tracker_get_local_width_summary(view->tracker, i, &summary);
+
+ g_buffer_line_draw(line, cr, &summary, real_x, y, display, view->highlighted);
+
+ y += class->line_height;
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à consulter. *
+* addr = adresse où retrouver la ligne recherchée. *
+* flags = propriétés à vérifier en tout ou partie. *
+* idx = indice de la ligne trouvée ou NULL. [OUT] *
+* *
+* Description : Retrouve une ligne au sein d'un tampon avec une adresse. *
+* *
+* Retour : Line retrouvée ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBufferLine *g_buffer_view_find_line_by_addr(const GBufferView *view, const vmpa2t *addr, BufferLineFlags flags, size_t *idx)
+{
+ GBufferLine *result; /* Ligne trouvée à retourner */
+ phys_t length; /* Taille de la vue */
+ mrange_t vrange; /* Couverture de la vue */
+ bool allowed; /* Rechercher validée ? */
+
+ /* Vérification des bornes */
+
+ if (!view->unrestricted)
+ {
+ length = compute_vmpa_diff(&view->start, &view->end);
+
+ init_mrange(&vrange, &view->start, length);
+
+ allowed = mrange_contains_addr_inclusive(&vrange, addr);
+
+ }
+ else allowed = true;
+
+ /* Lancement des recherches ? */
+
+ if (allowed)
+ result = g_code_buffer_find_line_by_addr(view->buffer, addr, flags, idx);
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à consulter. *
+* index = indice de la ligne recherchée. *
+* *
+* Description : Retrouve une ligne au sein d'un tampon avec un indice. *
+* *
+* Retour : Line retrouvée ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBufferLine *g_buffer_view_find_line_by_index(const GBufferView *view, size_t index)
+{
+ GBufferLine *result; /* Ligne trouvée à retourner */
+ bool allowed; /* Rechercher validée ? */
+
+ /* Vérification des bornes */
+
+ allowed = (view->first <= index && index <= view->last);
+
+ /* Lancement des recherches ? */
+
+ if (allowed)
+ result = g_code_buffer_find_line_by_index(view->buffer, index);
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à consulter. *
+* y = ordonnée comprise dans la ligne recherchée. *
+* idx = indice de la ligne trouvée ou NULL. [OUT] *
+* *
+* Description : Fournit la ligne présente à une ordonnée donnée. *
+* *
+* Retour : Ligne retrouvée ou NULL si aucune. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBufferLine *g_buffer_view_find_line_at(GBufferView *view, gint y, size_t *idx)
+{
+ GBufferLine *result; /* Ligne trouvée à retourner */
+ gint lheight; /* Hauteur d'une ligne */
+ size_t index; /* Indice attendu */
+
+ lheight = g_buffer_view_get_line_height(view);
+ index = y / lheight;
+
+ index += view->first;
+
+ if (index <= view->last)
+ result = g_code_buffer_find_line_by_index(view->buffer, index);
+
+ if (result != NULL && idx != NULL)
+ *idx = index;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = visualisation à consulter. *
+* x = abscisse comprise dans le segment recherché. [OUT] *
+* y = ordonnée comprise dans la ligne recherchée. *
+* idx = indice de la ligne trouvée ou NULL. [OUT] *
+* display = règles d'affichage des colonnes modulables. *
+* segment = portion de texte recherchée ou NULL. [OUT] *
+* *
+* Description : Fournit la ligne et son segment présents à une position. *
+* *
+* Retour : Ligne retrouvée ou NULL si aucune. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GBufferLine *g_buffer_view_find_line_and_segment_at(GBufferView *view, gint *x, gint y, size_t *idx, const bool *display, GBufferSegment **segment)
+{
+ GBufferLine *result; /* Ligne trouvée à retourner */
+ GBufferViewClass *class; /* Classe pour les vues */
+ const line_width_summary *summary; /* Résumé concis des largeurs */
+
+ /* Recherche d'une ligne correspondante */
+
+ result = g_buffer_view_find_line_at(view, y, idx);
+
+ /* Recherche du segment visé éventuel */
+
+ if (result != NULL && segment != NULL)
+ {
+ class = G_BUFFER_VIEW_GET_CLASS(view);
+
+ if (*x < class->left_text)
+ *segment = NULL;
+
+ else
+ {
+ summary = g_width_tracker_get_width_summary(view->tracker);
+
+ *x -= class->left_text;
+ *segment = g_buffer_line_get_segment_at(result, summary, display,
+ (gint []) { 0 }, x, GDK_SCROLL_LEFT, true);
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : view = composant GTK à consulter. *
+* addr = adresse à présenter à l'écran. *
+* x = position horizontale au sein du composant. [OUT] *
+* y = position verticale au sein du composant. [OUT] *
+* code = s'arrête si possible à une ligne avec code. *
+* *
+* Description : Indique la position d'affichage d'une adresse donnée. *
+* *
+* Retour : true si l'adresse fait partie du composant, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_buffer_view_get_address_coordinates(GBufferView *view, const vmpa2t *addr, gint *x, gint *y, bool code)
+{
+ bool result; /* Bilan à retourner */
+ gint lheight; /* Hauteur d'une ligne */
+ size_t i; /* Boucle de parcours */
+ GBufferLine *line; /* Ligne à consulter */
+ const mrange_t *range; /* Emplacement parcouru */
+
+ result = false;
+
+ *x = 0;
+ *y = 0;
+
+ lheight = g_buffer_view_get_line_height(view);
+
+ for (i = view->first; i <= view->last; i++)
+ {
+ /**
+ * Si l'adresse recherchée est plus petite que l'adresse de départ,
+ * on va effectuer un parcours complet pour rien.
+ *
+ * On considère cependant que le seul cas où celà peut arriver
+ * est lorsque que des découpages en blocs sont impliqués.
+ *
+ * Les découpages conduisent alors à la formation de petites zones,
+ * rapides à parcourir.
+ */
+
+ line = g_code_buffer_find_line_by_index(view->buffer, i);
+ range = g_buffer_line_get_range(line);
+
+ result = mrange_contains_addr(range, addr);
+ if (result) break;
+
+ *y += lheight;
+
+ }
+
+ if (result && code)
+ for (; i <= view->last; i++)
+ {
+ line = g_code_buffer_find_line_by_index(view->buffer, i);
+
+ if (g_buffer_line_get_flags(line) & BLF_HAS_CODE) break;
+
+ if (i == view->last) break;
+
+ line = g_code_buffer_find_line_by_index(view->buffer, i + 1);
+
+ range = g_buffer_line_get_range(line);
+ if (!mrange_contains_addr(range, addr)) break;
+
+ *y += lheight;
+
+ }
+
+ return result;
+
+}