/* Chrysalide - Outil d'analyse de fichiers binaires * gtkbinarystrip.c - affichage d'un binaire sous forme de bande * * Copyright (C) 2013-2017 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide 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. * * Chrysalide 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 "gtkbinarystrip.h" #include "../glibext/chrysamarshal.h" /* Affichage d'un binaire en bande (instance) */ struct _GtkBinaryStrip { GtkDrawingArea parent; /* A laisser en premier */ GLoadedBinary *binary; /* Binaire à représenter */ gint display_pos; /* Position à l'écran */ vmpa2t cursor_addr; /* Adresse de la position */ gint cursor_pos; /* Position à l'écran */ }; /* Affichage d'un binaire en bande (classe) */ struct _GtkBinaryStripClass { GtkDrawingAreaClass parent; /* A laisser en premier */ void (* select_address) (GtkBinaryStrip *); }; /* Taille de l'encoche pour la position */ #define STRIP_MARKER_SIZE 7 /* Procède à l'initialisation de l'afficheur générique. */ static void gtk_binary_strip_class_init(GtkBinaryStripClass *); /* Procède à l'initialisation de l'afficheur générique. */ static void gtk_binary_strip_init(GtkBinaryStrip *); /* Encadre la préparation à l'affichage du composant. */ static void gtk_binary_strip_realize(GtkWidget *); /* Réagit à un changement de taille du composant. */ static void gtk_binary_strip_size_allocate(GtkWidget *, GtkAllocation *); /* Suit la progression de la souris sur le composant. */ static gboolean gtk_binary_strip_button_release(GtkWidget *, GdkEventButton *); /* Met à jour l'affichage du composant d'affichage. */ static gboolean gtk_binary_strip_draw(GtkWidget *, cairo_t *); /* Prépare l'affichage d'une astuce. */ static gboolean gtk_binary_strip_query_tooltip(GtkWidget *, gint, gint, gboolean, GtkTooltip *); /* Détermine le type du composant d'affichage générique. */ G_DEFINE_TYPE(GtkBinaryStrip, gtk_binary_strip, GTK_TYPE_DRAWING_AREA) /****************************************************************************** * * * Paramètres : class = classe GTK à initialiser. * * * * Description : Procède à l'initialisation de l'afficheur générique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_binary_strip_class_init(GtkBinaryStripClass *class) { GtkWidgetClass *widget_class; /* Classe de haut niveau */ widget_class = GTK_WIDGET_CLASS(class); widget_class->realize = gtk_binary_strip_realize; widget_class->size_allocate = gtk_binary_strip_size_allocate; widget_class->button_release_event = gtk_binary_strip_button_release; widget_class->draw = gtk_binary_strip_draw; widget_class->query_tooltip = gtk_binary_strip_query_tooltip; g_signal_new("select-address", GTK_TYPE_BINARY_STRIP, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GtkBinaryStripClass, select_address), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } /****************************************************************************** * * * Paramètres : strip = composant GTK à initialiser. * * * * Description : Procède à l'initialisation de l'afficheur générique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_binary_strip_init(GtkBinaryStrip *strip) { GObject *object; /* Autre version de l'instance */ GtkWidget *widget; /* Autre version de l'instance */ object = G_OBJECT(strip); widget = GTK_WIDGET(strip); g_object_set(object, "has-tooltip", TRUE, NULL); gtk_widget_set_size_request(widget, 400, 30); } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un nouveau composant pour l'affichage d'une bande. * * * * Retour : Composant GTK créé. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *gtk_binary_strip_new(void) { GtkBinaryStrip *result; /* Composant à retourner */ result = g_object_new(GTK_TYPE_BINARY_STRIP, NULL); return GTK_WIDGET(result); } /****************************************************************************** * * * Paramètres : widget = composant GTK à préparer. * * * * Description : Encadre la préparation à l'affichage du composant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_binary_strip_realize(GtkWidget *widget) { GdkCursor *cursor; /* Pointeur pour la surface */ GTK_WIDGET_CLASS(gtk_binary_strip_parent_class)->realize(widget); cursor = gdk_cursor_new(GDK_HAND1); gdk_window_set_cursor(gtk_widget_get_window(widget), cursor); g_object_unref(cursor); gtk_widget_add_events(widget, GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); } /****************************************************************************** * * * Paramètres : widget = composant GTK à préparer. * * allocation = nouvelle taille à considérer. * * * * Description : Réagit à un changement de taille du composant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_binary_strip_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { GtkBinaryStrip *strip; /* Autre version du composant */ GExeFormat *format; /* Format du binaire */ GBinPortion *portions; /* Couche première de portions */ GdkRectangle area; /* Surface du composant */ GTK_WIDGET_CLASS(gtk_binary_strip_parent_class)->size_allocate(widget, allocation); strip = GTK_BINARY_STRIP(widget); if (strip->binary == NULL) return; format = g_loaded_binary_get_format(strip->binary); portions = g_exe_format_get_portions(format); area.x = 0; area.y = 0; area.width = allocation->width; area.height = allocation->height; if (!get_binary_portion_pos_from_addr(portions, &strip->cursor_addr, &area, &strip->cursor_pos)) strip->cursor_pos = 0; g_object_unref(G_OBJECT(portions)); g_object_unref(G_OBJECT(format)); } /****************************************************************************** * * * Paramètres : widget = composant GTK visé par l'opération. * * event = informations liées à l'événement. * * * * Description : Suit la progression de la souris sur le composant. * * * * Retour : FALSE pour poursuivre la propagation de l'événement. * * * * Remarques : - * * * ******************************************************************************/ static gboolean gtk_binary_strip_button_release(GtkWidget *widget, GdkEventButton *event) { gint width; /* Laugeur du composant */ gint height; /* Hauteur du composant */ GtkBinaryStrip *strip; /* Autre version du composant */ GExeFormat *format; /* Format du binaire */ GBinPortion *portions; /* Couche première de portions */ GdkRectangle area; /* Surface du composant */ vmpa2t addr; /* Adresse à sélectionner */ if (event->x < 0 || event->y < 0) return FALSE; width = gtk_widget_get_allocated_width(widget); height = gtk_widget_get_allocated_height(widget); if (event->x >= width || event->y >= height) return FALSE; strip = GTK_BINARY_STRIP(widget); format = g_loaded_binary_get_format(strip->binary); portions = g_exe_format_get_portions(format); area.x = 0; area.y = 0; area.width = width; area.height = height; if (get_binary_portion_addr_from_pos(portions, event->x, &area, &addr)) { copy_vmpa(&strip->cursor_addr, &addr); strip->cursor_pos = event->x; gtk_widget_queue_draw(GTK_WIDGET(strip)); g_signal_emit_by_name(strip, "select-address"); } g_object_unref(G_OBJECT(portions)); g_object_unref(G_OBJECT(format)); return FALSE; } /****************************************************************************** * * * Paramètres : widget = composant GTK à redessiner. * * cr = contexte graphique associé à l'événement. * * * * Description : Met à jour l'affichage du composant d'affichage. * * * * Retour : FALSE pour poursuivre la propagation de l'événement. * * * * Remarques : - * * * ******************************************************************************/ static gboolean gtk_binary_strip_draw(GtkWidget *widget, cairo_t *cr) { GtkBinaryStrip *strip; /* Autre vision du composant */ GtkStyleContext *context; /* Contexte du thème actuel */ GExeFormat *format; /* Format du binaire */ GBinPortion *portions; /* Portions de binaire */ GdkRectangle full; /* Taille totale de la surface */ GdkRGBA *color; /* Couleur du curseur */ strip = GTK_BINARY_STRIP(widget); if (strip->binary == NULL) return FALSE; context = gtk_widget_get_style_context(widget); /* Dessin des portions de binaire */ format = g_loaded_binary_get_format(strip->binary); portions = g_exe_format_get_portions(format); full.x = 0; full.y = 1; full.width = gtk_widget_get_allocated_width(widget); full.height = gtk_widget_get_allocated_height(widget) - 1; g_binary_portion_draw(portions, context, cr, &full); g_object_unref(G_OBJECT(portions)); g_object_unref(G_OBJECT(format)); /* Dessin de la position */ if (strip->cursor_pos != -1) { cairo_set_line_width(cr, 1); gtk_style_context_get(context, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_BACKGROUND_COLOR, &color, NULL); cairo_set_source_rgb(cr, color->red, color->green, color->blue); gdk_rgba_free(color); cairo_move_to(cr, strip->cursor_pos, STRIP_MARKER_SIZE); cairo_line_to(cr, strip->cursor_pos + STRIP_MARKER_SIZE, 0); cairo_line_to(cr, strip->cursor_pos - STRIP_MARKER_SIZE, 0); cairo_line_to(cr, strip->cursor_pos, STRIP_MARKER_SIZE); cairo_fill(cr); cairo_move_to(cr, strip->cursor_pos, full.height - STRIP_MARKER_SIZE + 1); cairo_line_to(cr, strip->cursor_pos + STRIP_MARKER_SIZE, full.height + 1); cairo_line_to(cr, strip->cursor_pos - STRIP_MARKER_SIZE, full.height + 1); cairo_line_to(cr, strip->cursor_pos, full.height - STRIP_MARKER_SIZE + 1); cairo_fill(cr); } return FALSE; } /****************************************************************************** * * * Paramètres : widget = composant GTK visé par l'opération. * * x = abscisse de la position du message. * * y = ordonnée de la position du message. * * keyboard = indique une demande suite à obtiention du focus. * * tooltip = astuce à compléter. [OUT] * * * * Description : Prépare l'affichage d'une astuce. * * * * Retour : TRUE pour un affichage validé, FALSE sinon. * * * * Remarques : - * * * ******************************************************************************/ static gboolean gtk_binary_strip_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard, GtkTooltip *tooltip) { gboolean result; /* Bilan à retourner */ GtkBinaryStrip *strip; /* Autre version du composant */ GExeFormat *format; /* Format du binaire */ GBinPortion *portions; /* Couches binaires à consulter*/ GdkRectangle area; /* Surface du composant */ if (keyboard) return FALSE; strip = GTK_BINARY_STRIP(widget); if (strip->binary != NULL) { format = g_loaded_binary_get_format(strip->binary); portions = g_exe_format_get_portions(format); area.x = 0; area.y = 0; area.width = gtk_widget_get_allocated_width(widget); area.height = gtk_widget_get_allocated_height(widget); result = query_tooltip_for_binary_portion(portions, x, y, &area, tooltip); g_object_unref(G_OBJECT(portions)); g_object_unref(G_OBJECT(format)); } else result = FALSE; return result; } /****************************************************************************** * * * Paramètres : strip = composant GTK à mettre à jour. * * binary = nouveau contenu binaire à représenter. * * * * Description : Attache un nouveau binaire à la barre de représentation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void gtk_binary_strip_attach(GtkBinaryStrip *strip, GLoadedBinary *binary) { GtkWidget *widget; /* Autre version du composant */ if (strip->binary != NULL) g_object_unref(G_OBJECT(strip->binary)); strip->binary = binary; if (strip->binary != NULL) g_object_ref(G_OBJECT(strip->binary)); widget = GTK_WIDGET(strip); gtk_widget_set_sensitive(widget, strip->binary != NULL); gtk_widget_queue_draw(widget); } /****************************************************************************** * * * Paramètres : strip = composant GTK à consulter. * * * * Description : Indique l'adresse physique et virtuelle représentée. * * * * Retour : Localisation, initialisée ou non. * * * * Remarques : - * * * ******************************************************************************/ const vmpa2t *gtk_binary_strip_get_location(const GtkBinaryStrip *strip) { return &strip->cursor_addr; } /****************************************************************************** * * * Paramètres : strip = composant GTK à mettre à jour. * * binary = nouveau contenu binaire à représenter. * * * * Description : Place le curseur dans la barre de représentation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ #if 0 void gtk_binary_strip_locate_cursor(GtkBinaryStrip *strip, vmpa_t addr, bool emit) { //srip->cursor_pos = pos; gtk_widget_queue_draw(GTK_WIDGET(strip)); } #endif