/* 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 .
*/
#include "gtkblockview.h"
#include
#include
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
#include
#include "gtkbinview-int.h"
#include "support.h"
#include "../analysis/exporter.h"
#include "../common/dllist.h"
#include "../glibext/delayed-int.h"
#include "../glibext/gcodebuffer.h"
#include "../glibext/gbuffersegment.h"
#ifndef _
# define _(str) str
#endif
/* -------------------------- INSERTION DIFFEREE DE LIGNES -------------------------- */
#define G_TYPE_DELAYED_INSERTION g_delayed_insertion_get_type()
#define G_DELAYED_INSERTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_delayed_insertion_get_type(), GDelayedInsertion))
#define G_IS_DELAYED_INSERTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_delayed_insertion_get_type()))
#define G_DELAYED_INSERTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DELAYED_INSERTION, GDelayedInsertionClass))
#define G_IS_DELAYED_INSERTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DELAYED_INSERTION))
#define G_DELAYED_INSERTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DELAYED_INSERTION, GDelayedInsertionClass))
/* Ensembles binaires à désassembler (instance) */
typedef struct _GDelayedInsertion
{
GDelayedWork parent; /* A laisser en premier */
GtkBlockView *view; /* Visualisation à constituer */
size_t lengths[SAR_COUNT]; /* Différentes tailles de zone */
} GDelayedInsertion;
/* Ensembles binaires à désassembler (classe) */
typedef struct _GDelayedInsertionClass
{
GDelayedWorkClass parent; /* A laisser en premier */
} GDelayedInsertionClass;
/* Indique le type défini pour les tâches d'insertions différées. */
static GType g_delayed_insertion_get_type(void);
/* Initialise la classe des tâches d'insertions différées. */
static void g_delayed_insertion_class_init(GDelayedInsertionClass *);
/* Initialise une tâche d'insertions différées. */
static void g_delayed_insertion_init(GDelayedInsertion *);
/* Crée une tâche d'insertions différées. */
static GDelayedInsertion *g_delayed_insertion_new(GtkBlockView *);
/* Assure des insertion de lignes en différé. */
static void g_delayed_insertion_process(GDelayedInsertion *, GtkExtStatusBar *);
struct _GtkBlockView
{
GtkBinView parent; /* A laisser en premier */
MainRendering rendering; /* Support final des lignes */
bool show_vaddress; /* Affichage des adresses ? */
bool show_code; /* Affichage du code brut ? */
GBufferView *buffer_view; /* Code sous forme de texte */
GtkTextBuffer *buffer; /* Code sous forme de texte */
GtkTextLayout *layout; /* Disposition du texte */
gint line_height; /* Hauteur maximale des lignes */
gint left_margin; /* Marge gauche + espace */
gint left_text; /* Début d'impression du code */
const exe_format *format; /* Format du contenu bianire */
GCodeBuffer *_buffer; /* Code sous forme de texte */
};
struct _GtkBlockViewClass
{
GtkBinViewClass parent; /* A laisser en premier */
GdkPixbuf *entry_pix; /* Image du point d'entrée */
GdkPixbuf *breakpoint_pix; /* Image de point d'arrêt */
GdkPixbuf *stopped_pix; /* Image de point actif */
};
static void
gtk_text_view2_set_attributes_from_style (GtkTextAttributes *values,
GtkStyle *style)
{
PangoFontDescription *font_desc;
values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
if (values->font)
pango_font_description_free (values->font);
font_desc = pango_font_description_from_string ("mono 10");
values->font = pango_font_description_copy (/*style->*/font_desc);
pango_font_description_free (font_desc);
}
/* Procède à l'initialisation de l'afficheur d'un bloc binaire. */
static void gtk_block_view_init(GtkBlockView *);
/* Encadre la construction graphique initiale de la visualisation. */
static void gtk_block_view_realize(GtkWidget *);
/* Fournit la taille de composant requise pour un plein rendu. */
static void gtk_block_view_size_request(GtkWidget *, GtkRequisition *);
/* S'adapte à la surface concédée par le composant parent. */
static void gtk_block_view_size_allocate(GtkWidget *, GtkAllocation *);
/* Réagit à un défilement quelconque. */
static void gtk_block_view_scroll(GtkBlockView *);
/* Définit les lignes du bloc de représentation. */
static void gtk_block_view_set_rendering_lines(GtkBlockView *, GRenderingLine *, GRenderingLine *);
/* Achève la construction de la visualisation des lignes. */
static void gtk_block_view_complete_building_content(GDelayedInsertion *, GtkBlockView *);
/* 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 *);
/* Indique la position d'affichage d'une adresse donnée. */
static bool gtk_block_view_get_address_coordinates(const GtkBlockView *, vmpa_t, gint *, gint *);
static void gtk_block_view_class_init(GtkBlockViewClass *klass);
static void gtk_block_view_size_allocate(GtkWidget *widget,
GtkAllocation *allocation);
static gboolean gtk_block_view_button_press(GtkWidget *, GdkEventButton *event);
/* Imprime d'éventuelles informations liées à une ligne. */
static void gtk_block_view_draw_line_extra(GBufferLine *, GdkDrawable *, GdkGC *, gint, gint, void *);
/* Met à jour l'affichage de la vue sous forme de bloc. */
static gboolean gtk_block_view_expose(GtkWidget *, GdkEventExpose *);
static void gtk_block_view_destroy(GtkObject *object);
/* ---------------------------------------------------------------------------------- */
/* INSERTION DIFFEREE DE LIGNES */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour les tâches d'insertions différées. */
G_DEFINE_TYPE(GDelayedInsertion, g_delayed_insertion, G_TYPE_DELAYED_WORK);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des tâches d'insertions différées. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_delayed_insertion_class_init(GDelayedInsertionClass *klass)
{
}
/******************************************************************************
* *
* Paramètres : insertion = instance à initialiser. *
* *
* Description : Initialise une tâche d'insertions différées. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_delayed_insertion_init(GDelayedInsertion *insertion)
{
G_DELAYED_WORK(insertion)->run = (run_task_fc)g_delayed_insertion_process;
}
/******************************************************************************
* *
* Paramètres : view = visualisation de lignes à constituer. *
* *
* Description : Crée une tâche d'insertions différées. *
* *
* Retour : Tâche créée. *
* *
* Remarques : - *
* *
******************************************************************************/
static GDelayedInsertion *g_delayed_insertion_new(GtkBlockView *view)
{
GDelayedInsertion *result; /* Tâche à retourner */
result = g_object_new(G_TYPE_DELAYED_INSERTION, NULL);
result->view = view;
return result;
}
/******************************************************************************
* *
* Paramètres : insertion = insertions de lignes à mener. *
* statusbar = barre de statut à tenir informée. *
* *
* Description : Assure des insertion de lignes en différé. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_delayed_insertion_process(GDelayedInsertion *insertion, GtkExtStatusBar *statusbar)
{
GtkBlockView *view; /* Visualisation à constituer */
GRenderingLine *lines; /* Liste de lignes à intégrer */
GRenderingLine *last; /* Dernière ligne ou NULL */
vmpa_t start; /* Adresse de début de parcours*/
vmpa_t end; /* Adresse de fin de parcours */
guint id; /* Identifiant de statut */
GRenderingOptions *options; /* Options de rendu */
GRenderingLine *iter; /* Boucle de parcours */
GtkTextIter pos; /* Point d'insertion */
GBufferLine *line; /* Ligne de destination */
//GtkTextMark *mark; /* Marquage de ligne associée */
vmpa_t done; /* Quantité déjà parcourue */
clock_t _start, _end;
double cpu_time_used;
view = insertion->view;
lines = GTK_BIN_VIEW(view)->lines;
last = GTK_BIN_VIEW(view)->last;
if (lines == NULL) return;
iter = g_rendering_line_loop_for_code(lines, last);
start = get_rendering_line_address(lines);
iter = g_rendering_line_get_last_iter(lines, last);
end = get_rendering_line_address(iter) + get_rendering_line_length(iter) - start;
insertion->lengths[SAR_ADDRESS] = 0;
insertion->lengths[SAR_CODE] = 0;
insertion->lengths[SAR_INSTRUCTION] = 0;
id = gtk_extended_status_bar_push(statusbar, _("Inserting lines..."), true);
options = g_openida_binary_get_options(GTK_BIN_VIEW(view)->binary);
_start = clock();
for (iter = lines;
iter != NULL;
iter = g_rendering_line_get_next_iter(lines, iter, last))
{
g_signal_connect(iter, "rendering-line-flags-changed",
G_CALLBACK(gtk_block_view_update_margin), view);
//gdk_threads_enter();
line = g_code_buffer_append_new_line(view->_buffer);
g_content_exporter_to_buffer(G_CONTENT_EXPORTER(iter), line, options);
g_object_set_data(G_OBJECT(line), "line", iter);
#if 0
if (iter != lines)
gtk_text_buffer_insert_with_tags(view->buffer, &pos, "\n", 1, NULL);
gtk_text_buffer_get_end_iter(view->buffer, &pos);
mark = gtk_text_buffer_create_mark(view->buffer, NULL, &pos, TRUE);
g_object_set_data(G_OBJECT(mark), "line", iter);
g_content_exporter_add_to_gtk_buffer(G_CONTENT_EXPORTER(iter), view->rendering,
view->buffer, &pos, insertion->lengths);
#endif
/*
gdk_flush ();
gdk_threads_leave();
*/
done = get_rendering_line_address(iter) + get_rendering_line_length(iter) - start;
gtk_extended_status_bar_update_activity(statusbar, id, done * 1.0 / end);
}
_end = clock();
cpu_time_used = ((double) (_end - _start)) / (CLOCKS_PER_SEC / 1000);
printf(" ### TEMPS passé ::: %g ms (pid = %d)\n", cpu_time_used, getpid());
gtk_extended_status_bar_remove(statusbar, id);
view->buffer_view = g_buffer_view_new(view->_buffer);
g_buffer_view_define_extra_drawing(view->buffer_view, gtk_block_view_draw_line_extra, view);
}
/* Détermine le type du composant d'affichage en block. */
G_DEFINE_TYPE(GtkBlockView, gtk_block_view, GTK_TYPE_BIN_VIEW)
/******************************************************************************
* *
* Paramètres : rendering = support effectif des lignes au final. *
* *
* Description : Crée un nouveau composant pour l'affichage en block. *
* *
* Retour : Composant GTK créé. *
* *
* Remarques : - *
* *
******************************************************************************/
GtkWidget * gtk_block_view_new(MainRendering rendering)
{
GtkBlockView *result;
result = gtk_type_new(gtk_block_view_get_type());
result->rendering = rendering;
return GTK_WIDGET(result);
}
static void gtk_block_view_class_init(GtkBlockViewClass *klass)
{
GtkWidgetClass *widget_class; /* Classe version Widget */
GtkObjectClass *object_class;
gchar *filename; /* Fichier d'image à charger */
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;
/* Image de la marge gauche */
filename = find_pixmap_file("entry.png");
if (filename == NULL) klass->entry_pix = NULL;
else
{
klass->entry_pix = gdk_pixbuf_new_from_file(filename, NULL);
g_free(filename);
}
filename = find_pixmap_file("breakpoint.png");
if (filename == NULL) klass->breakpoint_pix = NULL;
else
{
klass->breakpoint_pix = gdk_pixbuf_new_from_file(filename, NULL);
g_free(filename);
}
filename = find_pixmap_file("stopped.png");
if (filename == NULL) klass->stopped_pix = NULL;
else
{
klass->stopped_pix = gdk_pixbuf_new_from_file(filename, NULL);
g_free(filename);
}
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à initialiser. *
* *
* Description : Procède à l'initialisation de l'afficheur d'un bloc binaire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_init(GtkBlockView *view)
{
GtkBinView *binview; /* Instance parente */
PangoFontDescription *font_desc;
PangoContext *ltr_context, *rtl_context;
GtkTextAttributes *style;
static bool done = false;
binview = GTK_BIN_VIEW(view);
binview->scroll = (scroll_fc)gtk_block_view_scroll;
binview->set_lines = (set_rendering_lines_fc)gtk_block_view_set_rendering_lines;
binview->get_coordinates = (get_addr_coordinates_fc)gtk_block_view_get_address_coordinates;
view->buffer = gtk_text_buffer_new(get_gtk_tag_table());
view->layout = gtk_text_layout_new();
if (!done || 1)
{
done = true;
gtk_text_layout_set_overwrite_mode(GTK_BLOCK_VIEW(view)->layout, FALSE);
ltr_context = gtk_widget_create_pango_context(view);
pango_context_set_base_dir(ltr_context, PANGO_DIRECTION_LTR);
rtl_context = gtk_widget_create_pango_context(view);
pango_context_set_base_dir(rtl_context, PANGO_DIRECTION_RTL);
gtk_text_layout_set_contexts(GTK_BLOCK_VIEW(view)->layout, ltr_context, rtl_context);
style = gtk_text_attributes_new ();
gtk_widget_ensure_style(view);
font_desc = pango_font_description_from_string ("mono 10");
gtk_widget_modify_font (view, font_desc);
pango_font_description_free (font_desc);
gtk_text_view2_set_attributes_from_style(style, GTK_WIDGET(view)->style);
/*
style->pixels_above_lines = 5;
style->pixels_below_lines = 5;
style->pixels_inside_wrap = 10;
style->left_margin = 10;
style->right_margin = 10;
style->indent = 10;*/
style->left_margin = 10;
style->right_margin = 10;
style->wrap_mode = GTK_WRAP_NONE;
style->justification = GTK_JUSTIFY_LEFT;
style->direction = gtk_widget_get_direction(view);
gtk_text_layout_set_default_style(GTK_BLOCK_VIEW(view)->layout, style);
gtk_text_attributes_unref(style);
//gtk_text_layout_get_size (GTK_BLOCK_VIEW(view)->layout, &width, &height);
}
view->_buffer = g_code_buffer_new();
}
/******************************************************************************
* *
* Paramètres : widget = composant GTK à redessiner. *
* *
* Description : Encadre la construction graphique initiale de la visualisat°.*
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_realize(GtkWidget *widget)
{
GtkBinViewClass *parent_class; /* Version pure du parent */
parent_class = GTK_BIN_VIEW_CLASS(g_type_class_peek_parent(GTK_BLOCK_VIEW_GET_CLASS(widget)));
GTK_WIDGET_CLASS(parent_class)->realize(widget);
}
/******************************************************************************
* *
* Paramètres : widget = composant GTK à consulter. *
* requisition = dimensions souhaitées. [OUT] *
* *
* Description : Fournit la taille de composant requise pour un plein rendu. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_size_request(GtkWidget *widget, GtkRequisition *requisition)
{
g_buffer_view_get_size(GTK_BLOCK_VIEW(widget)->buffer_view,
&requisition->width, &requisition->height);
printf(" === size req :: (%d ; %d)\n",
requisition->width, requisition->height);
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à mettre à jour. *
* allocation = étendue accordée à la vue. *
* *
* Description : S'adapte à la surface concédée par le composant parent. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
GtkBinView *view; /* Autre version du composant */
gint width; /* Largeur de l'objet actuelle */
gint height; /* Hauteur de l'objet actuelle */
GtkAllocation valloc; /* Surface utilisable */
gboolean changed; /* Changement de valeur ? */
/* Mise à jour GTK */
widget->allocation = *allocation;
if (GTK_WIDGET_REALIZED(widget))
gdk_window_move_resize(widget->window,
allocation->x, allocation->y,
allocation->width, allocation->height);
view = GTK_BIN_VIEW(widget);
if (view->hadjustment == NULL || view->vadjustment == NULL)
return;
g_buffer_view_get_size(GTK_BLOCK_VIEW(view)->buffer_view, &width, &height);
gtk_bin_view_compute_allocation(view, &valloc);
/* Défilement horizontal */
view->hadjustment->page_size = valloc.width;
view->hadjustment->step_increment = valloc.width * 0.1;
view->hadjustment->page_increment = valloc.width * 0.9;
view->hadjustment->upper = MAX(width, valloc.width);
gtk_bin_view_reclamp_adjustment(view->hadjustment, &changed);
gtk_adjustment_changed(view->hadjustment);
if (changed)
gtk_adjustment_value_changed(view->hadjustment);
/* Défilement vertical */
view->vadjustment->page_size = valloc.height;
view->vadjustment->step_increment = GTK_BLOCK_VIEW(view)->line_height;
view->vadjustment->page_increment = view->vadjustment->step_increment * 10.0;
view->vadjustment->upper = MAX(height, valloc.height);
gtk_bin_view_reclamp_adjustment(view->vadjustment, &changed);
gtk_adjustment_changed(view->vadjustment);
if (changed)
gtk_adjustment_value_changed(view->vadjustment);
}
static gboolean gtk_block_view_button_press(GtkWidget *widget, GdkEventButton *event)
{
gboolean result; /* Décision à retourner */
GtkBlockView *view; /* Composant GTK réel */
GtkTextIter iter; /* Point d'insertion */
GtkTextMark *mark; /* Marquage de ligne associée */
GRenderingLine *line; /* Ligne de rendu */
result = FALSE;
view = GTK_BLOCK_VIEW(widget);
gtk_text_layout_get_line_at_y(view->layout, &iter, event->y, NULL);
mark = gtk_text_iter_get_marks(&iter)->data;
line = g_object_get_data(G_OBJECT(mark), "line");
/* Clic dans la marge */
if (event->type == GDK_BUTTON_PRESS && event->x < view->left_margin)
{
result = TRUE;
g_rendering_line_toggle_flag(line, RLF_BREAK_POINT);
}
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)
{
/* TODO : à améliorer ! */
gtk_widget_queue_draw(GTK_WIDGET(view));
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à redessiner. *
* event = informations liées à l'événement. *
* *
* Description : Met à jour l'affichage de la vue sous forme de bloc. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_compute_fake_coord(GtkBlockView *view, gint *x, gint *y)
{
if (GTK_BIN_VIEW(view)->hadjustment != NULL)
*x -= gtk_adjustment_get_value(GTK_BIN_VIEW(view)->hadjustment);
if (GTK_BIN_VIEW(view)->vadjustment != NULL)
*y += gtk_adjustment_get_value(GTK_BIN_VIEW(view)->vadjustment);
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à redessiner. *
* event = informations liées à l'événement. *
* *
* Description : Met à jour l'affichage de la vue sous forme de bloc. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_compute_real_coord(GtkBlockView *view, gint *x, gint *y)
{
if (GTK_BIN_VIEW(view)->hadjustment != NULL)
*x += gtk_adjustment_get_value(GTK_BIN_VIEW(view)->hadjustment);
if (GTK_BIN_VIEW(view)->vadjustment != NULL)
*y -= gtk_adjustment_get_value(GTK_BIN_VIEW(view)->vadjustment);
}
/******************************************************************************
* *
* Paramètres : line = ligne de texte à manipuler. *
* drawable = surface de rendu où travailler. *
* gc = contexte graphique à utiliser pour les pinceaux. *
* x = abscisse du point d'impression décallé. *
* y = ordonnée du point d'impression décallé. *
* data = pointeur vers le composant GTK de support. *
* *
* Description : Imprime d'éventuelles informations liées à une ligne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_draw_line_extra(GBufferLine *line, GdkDrawable *drawable, GdkGC *gc, gint x, gint y, void *data)
{
GRenderingLine *rline; /* Ligne de rendu représentée */
GtkBlockViewClass *class; /* Classe contenant les images */
gint line_height; /* Hauteur d'une ligne */
RenderingLineFlag flags; /* Propriétés de la ligne */
int height; /* Hauteur de l'image */
GdkPixbuf *pixbuf; /* Données utiles au dessin */
rline = G_RENDERING_LINE(g_object_get_data(G_OBJECT(line), "line"));
class = GTK_BLOCK_VIEW_GET_CLASS(data);
line_height = g_buffer_view_get_line_height(GTK_BLOCK_VIEW(data)->buffer_view);
flags = g_rendering_line_get_flags(rline);
if (flags & RLF_RUNNING_BP)
pixbuf = class->stopped_pix;
else if (flags & RLF_BREAK_POINT)
pixbuf = class->breakpoint_pix;
else pixbuf = NULL;
if (pixbuf != NULL)
{
height = gdk_pixbuf_get_height(pixbuf);
gdk_draw_pixbuf(drawable, gc, pixbuf, 0, 0, x + 10,
y + (line_height - height) / 2,
gdk_pixbuf_get_width(pixbuf), height,
GDK_RGB_DITHER_NORMAL, 0, 0);
}
/* Le point d'entrée prime */
if (flags & RLF_ENTRY_POINT)
{
pixbuf = class->entry_pix;
height = gdk_pixbuf_get_height(pixbuf);
gdk_draw_pixbuf(drawable, gc, pixbuf, 0, 0, x + 10,
y + (line_height - height) / 2,
gdk_pixbuf_get_width(pixbuf), height,
GDK_RGB_DITHER_NORMAL, 0, 0);
}
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à redessiner. *
* event = informations liées à l'événement. *
* *
* Description : Met à jour l'affichage de la vue sous forme de bloc. *
* *
* Retour : FALSE pour poursuivre la propagation de l'événement. *
* *
* Remarques : - *
* *
******************************************************************************/
static gboolean gtk_block_view_expose(GtkWidget *widget, GdkEventExpose *event)
{
GtkBlockView *view; /* Autre version du composant */
GtkBinView *bview; /* Autre version du composant */
GtkStyle *style; /* Style associé au composant */
GdkDrawable *drawable; /* Surface de dessin */
gint fake_x; /* Abscisse virtuelle */
gint fake_y; /* Ordonnée virtuelle */
GtkBinViewClass *parent_class; /* Version pure du parent */
view = GTK_BLOCK_VIEW(widget);
widget = GTK_WIDGET(view);
bview = GTK_BIN_VIEW(widget);
drawable = GDK_DRAWABLE(event->window);
gdk_window_begin_paint_region(drawable, event->region);
gdk_gc_set_clip_region(bview->gc, event->region);
style = gtk_widget_get_style(GTK_WIDGET(view));
fake_x = 0;
fake_y = 0;
gtk_block_view_compute_fake_coord(view, &fake_x, &fake_y);
/* Dessin de la marge gauche */
gdk_gc_set_foreground(bview->gc, &style->mid[GTK_WIDGET_STATE(widget)]);
gdk_draw_rectangle(drawable, bview->gc, TRUE,
fake_x, event->area.y, view->left_margin, event->area.y + event->area.height);
gdk_gc_set_foreground(bview->gc, &style->dark[GTK_WIDGET_STATE(widget)]);
gdk_draw_line(drawable, bview->gc,
fake_x + view->left_margin, event->area.y,
fake_x + view->left_margin, event->area.y + event->area.height);
/* Eventuelle bordure globale */
parent_class = GTK_BIN_VIEW_CLASS(g_type_class_peek_parent(GTK_BLOCK_VIEW_GET_CLASS(view)));
GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
/* Impression du désassemblage */
g_buffer_view_draw(view->buffer_view, event, bview->gc, fake_x, fake_y);
gdk_window_end_paint(drawable);
return TRUE;
}
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. *
* *
* Description : Réagit à un défilement quelconque. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_scroll(GtkBlockView *view)
{
gtk_widget_queue_draw(GTK_WIDGET(view));
}
/******************************************************************************
* *
* Paramètres : view = composant GTK à mettre à jour. *
* lines = informations à intégrer. *
* last = dernière ligne à intégrer ou NULL pour toutes. *
* *
* Description : Définit les lignes du bloc de représentation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_set_rendering_lines(GtkBlockView *view, GRenderingLine *lines, GRenderingLine *last)
{
GWorkQueue *queue; /* Gestionnaire de différés */
GDelayedInsertion *insertion; /* Insertions à mener */
queue = get_work_queue();
insertion = g_delayed_insertion_new(view);
g_signal_connect(insertion, "work-completed",
G_CALLBACK(gtk_block_view_complete_building_content), view);
g_work_queue_schedule_work(queue, G_DELAYED_WORK(insertion));
}
/******************************************************************************
* *
* Paramètres : insertion = travail d'insertion effectué. *
* view = composant GTK à mettre à jour. *
* *
* Description : Achève la construction de la visualisation des lignes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void gtk_block_view_complete_building_content(GDelayedInsertion *insertion, GtkBlockView *view)
{
size_t lengths[SAR_COUNT]; /* Différentes tailles de zone */
GtkTextIter pos; /* Point d'insertion */
PangoTabArray *tabs; /* Tailles de tabulation */
GdkRectangle rect; /* Zone d'un point */
lengths[SAR_ADDRESS] = insertion->lengths[SAR_ADDRESS];
lengths[SAR_CODE] = insertion->lengths[SAR_CODE];
lengths[SAR_INSTRUCTION] = insertion->lengths[SAR_INSTRUCTION];
gdk_threads_enter();
gtk_text_layout_set_buffer(view->layout, view->buffer);
gtk_text_layout_set_cursor_visible(GTK_BLOCK_VIEW(view)->layout, FALSE);
gtk_text_buffer_get_end_iter(view->buffer, &pos);
gtk_text_layout_move_iter_visually(view->layout, &pos, -1);
gtk_text_layout_get_iter_location(view->layout, &pos, &rect);
/* Taille des tabulations */
if (lengths[SAR_ADDRESS] > 0 && lengths[SAR_CODE] > 0)
tabs = pango_tab_array_new_with_positions(3, TRUE,
PANGO_TAB_LEFT, rect.width * (lengths[SAR_ADDRESS] + 3),
PANGO_TAB_LEFT, rect.width * (lengths[SAR_ADDRESS] + 3 + lengths[SAR_CODE] + 3),
PANGO_TAB_LEFT, rect.width * (lengths[SAR_ADDRESS] + 3 + lengths[SAR_CODE] + 3 + lengths[SAR_INSTRUCTION] + 4));
else if (lengths[SAR_ADDRESS] > 0 && lengths[SAR_CODE] == 0)
tabs = pango_tab_array_new_with_positions(2, TRUE,
PANGO_TAB_LEFT, rect.width * (lengths[SAR_ADDRESS] + 3),
PANGO_TAB_LEFT, rect.width * (lengths[SAR_ADDRESS] + 3 + lengths[SAR_INSTRUCTION] + 4));
else if (lengths[SAR_ADDRESS] == 0 && lengths[SAR_CODE] > 0)
tabs = pango_tab_array_new_with_positions(2, TRUE,
PANGO_TAB_LEFT, rect.width * (lengths[SAR_CODE] + 3),
PANGO_TAB_LEFT, rect.width * (lengths[SAR_CODE] + 3 + lengths[SAR_INSTRUCTION] + 4));
else
tabs = pango_tab_array_new_with_positions(1, TRUE,
PANGO_TAB_LEFT, rect.width * (lengths[SAR_INSTRUCTION] + 4));
if (view->layout->default_style->tabs)
pango_tab_array_free(view->layout->default_style->tabs);
view->layout->default_style->tabs = tabs;
gtk_text_layout_default_style_changed(view->layout);
/* Taille des marges */
view->line_height = rect.height;
view->left_margin = 2 * rect.height;
view->left_text = -2.5 * rect.height;
/* Validation finale */
gtk_text_layout_validate(GTK_BLOCK_VIEW(view)->layout, G_MAXINT);
gtk_block_view_recompute_size_request(view);
gdk_flush ();
gdk_threads_leave();
g_signal_emit_by_name(view, "lines-set");
}
/******************************************************************************
* *
* 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)
{
gint width; /* Largeur de l'objet actuelle */
gint height; /* Hauteur de l'objet actuelle */
g_buffer_view_get_size(view->buffer_view, &width, &height);
width += -view->left_text + 1;
height += 1;
gtk_widget_set_size_request(GTK_WIDGET(view), width, height);
}
/******************************************************************************
* *
* 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] *
* *
* Description : Indique la position d'affichage d'une adresse donnée. *
* *
* Retour : TRUE si l'adresse fait partie du composant, FALSE sinon. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool gtk_block_view_get_address_coordinates(const GtkBlockView *view, vmpa_t addr, gint *x, gint *y)
{
bool result; /* Bilan à retourner */
GRenderingLine *iter; /* Boucle de parcours */
result = false;
*x = 0;
*y = 0;
for (iter = GTK_BIN_VIEW(view)->lines;
iter != NULL && !result;
iter = g_rendering_line_get_next_iter(GTK_BIN_VIEW(view)->lines, iter, GTK_BIN_VIEW(view)->last))
{
if (get_rendering_line_address(iter) == addr) result = true;
else *y += view->line_height;
}
return result;
}