/* 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; }