diff options
Diffstat (limited to 'src/glibext/gbufferview.c')
-rw-r--r-- | src/glibext/gbufferview.c | 1330 |
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; + +} |