/* Chrysalide - Outil d'analyse de fichiers binaires * view.c - gestion du menu 'Affichage' * * Copyright (C) 2012 Cyrille Bagard * * This view 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "view.h" #include #include #include "../editem-int.h" #include "../core/panels.h" #include "../../analysis/project.h" #include "../../gtkext/easygtk.h" #include "../../gtkext/gtkblockdisplay.h" #include "../../gtkext/gtkgraphdisplay.h" /* Réagit avec le menu "Affichage -> Panneaux latéraux". */ static void mcb_view_update_side_panels_list(GtkMenuItem *, GMenuBar *); /* Réagit avec le menu "Affichage -> Panneaux latéraux -> ...". */ static void mcb_view_change_panel_docking(GtkCheckMenuItem *, GPanelItem *); /* Réagit avec le menu "Affichage -> Vue xxx". */ static void mcb_view_change_support(GtkRadioMenuItem *, GMenuBar *); /* Réagit avec le menu "Affichage -> (colonne xxx)". */ static void mcb_view_display_column(GtkCheckMenuItem *, GMenuBar *); /* Réagit avec le menu "Affichage -> Plein écran". */ static void mcb_view_show_full_screen(GtkCheckMenuItem *, GMenuBar *); /****************************************************************************** * * * Paramètres : ref = espace de référencement global. * * accgroup = groupe d'accélérateurs pour les menus. * * bar = barre de menu parente. * * * * Description : Construit le menu "Affichage". * * * * Retour : Panneau de menus mis en place. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *build_menu_view(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *bar) { GtkWidget *result; /* Support à retourner */ GtkWidget *menubar; /* Support pour éléments #1 */ GtkWidget *submenuitem; /* Sous-élément de menu */ GtkWidget *deepmenubar; /* Support pour éléments #2 */ GSList *rgroup; /* Groupe des boutons radio */ result = gtk_menu_item_new_with_mnemonic(_("_View")); gtk_widget_show(result); menubar = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(result), menubar); /* Affichage -> Panneaux latéraux */ submenuitem = qck_create_menu_item(NULL, NULL, _("Side panels"), NULL, NULL); g_signal_connect(submenuitem, "select", G_CALLBACK(mcb_view_update_side_panels_list), bar); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); deepmenubar = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenuitem), deepmenubar); /* - */ submenuitem = qck_create_menu_separator(); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); /* Types de panneau de code */ submenuitem = qck_create_radio_menu_item(ref, "mnu_view_switch_textview", NULL, _("Text view"), G_CALLBACK(mcb_view_change_support), bar); add_accelerator_to_menu_item(submenuitem, "F3", accgroup); g_object_set_data(G_OBJECT(submenuitem), "kind_of_view", GUINT_TO_POINTER(BVW_BLOCK)); g_object_set_data(G_OBJECT(submenuitem), "kind_of_display", GSIZE_TO_POINTER(GTK_TYPE_BLOCK_DISPLAY)); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); rgroup = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(submenuitem)); submenuitem = qck_create_radio_menu_item(ref, "mnu_view_switch_graphview", rgroup, _("Graph view"), G_CALLBACK(mcb_view_change_support), bar); add_accelerator_to_menu_item(submenuitem, "F4", accgroup); g_object_set_data(G_OBJECT(submenuitem), "kind_of_view", GUINT_TO_POINTER(BVW_GRAPH)); g_object_set_data(G_OBJECT(submenuitem), "kind_of_display", GSIZE_TO_POINTER(GTK_TYPE_GRAPH_DISPLAY)); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); /* - */ submenuitem = qck_create_menu_separator(); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); /* Affichage des données */ submenuitem = qck_create_check_menu_item(ref, "mnu_view_display_off", _("Physical offset"), G_CALLBACK(mcb_view_display_column), bar); g_object_set_data(G_OBJECT(submenuitem), "kind_of_col", GUINT_TO_POINTER(BLC_PHYSICAL)); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); submenuitem = qck_create_check_menu_item(ref, "mnu_view_display_addr", _("Virtual address"), G_CALLBACK(mcb_view_display_column), bar); g_object_set_data(G_OBJECT(submenuitem), "kind_of_col", GUINT_TO_POINTER(BLC_VIRTUAL)); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); submenuitem = qck_create_check_menu_item(ref, "mnu_view_display_code", _("Binary code"), G_CALLBACK(mcb_view_display_column), bar); g_object_set_data(G_OBJECT(submenuitem), "kind_of_col", GUINT_TO_POINTER(BLC_BINARY)); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); /* - */ submenuitem = qck_create_menu_separator(); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); /* Affichage -> Plein écran */ submenuitem = qck_create_check_menu_item(NULL, NULL, _("Full screen"), G_CALLBACK(mcb_view_show_full_screen), bar); add_accelerator_to_menu_item(submenuitem, "F11", accgroup); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); return result; } /****************************************************************************** * * * Paramètres : widget = menu principal à actualiser. * * panel = nouveau panneau d'affichage actif. * * bar = barre de menu parente. * * * * Description : Lance une actualisation du fait d'un changement de vue. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void update_menu_view_for_view(GtkWidget *widget, GtkDisplayPanel *panel, GMenuBar *bar) { GObject *ref; /* Espace de référencements */ GtkRadioMenuItem *item; /* Elément de menu arbitraire */ GSList *radios; /* Liste des menus d'affichage */ GSList *found; /* Elément de menu à activer */ GLoadedBinary *binary; /* Binaire courant */ BinaryView content; /* Type de vue active */ const bool *display; /* Règles d'affichage courantes*/ GtkWidget *submenuitem; /* Sous-élément de menu */ bool status; /* Consigne d'affichage */ ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(bar)); /* Types de panneau de code */ item = GTK_RADIO_MENU_ITEM(g_object_get_data(ref, "mnu_view_switch_graphview")); radios = gtk_radio_menu_item_get_group(item); void disconnect_display_radio(GtkWidget *wgt, gpointer unused) { g_signal_handlers_disconnect_by_func(wgt, G_CALLBACK(mcb_view_change_support), bar); } g_slist_foreach(radios, (GFunc)disconnect_display_radio, NULL); gint find_suitable_display_radio(GObject *rdo, GObject *pnl) { GType rdo_type; /* Type d'affichage supporté */ GType pnl_type; /* Type du panneau affiché */ rdo_type = GPOINTER_TO_SIZE(g_object_get_data(rdo, "kind_of_display")); pnl_type = G_OBJECT_TYPE(pnl); return (rdo_type == pnl_type ? 0 : -1); } found = g_slist_find_custom(radios, G_OBJECT(panel), (GCompareFunc)find_suitable_display_radio); assert(found != NULL); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(found->data), TRUE); void reconnect_display_radio(GtkWidget *wgt, gpointer unused) { g_signal_connect(wgt, "toggled", G_CALLBACK(mcb_view_change_support), bar); } g_slist_foreach(radios, (GFunc)reconnect_display_radio, NULL); /* - */ binary = g_editor_item_get_current_binary(G_EDITOR_ITEM(bar)); content = gtk_display_panel_describe_content(panel); display = g_loaded_binary_get_column_display(binary, content); /* Positions physiques */ submenuitem = g_object_get_data(ref, "mnu_view_display_off"); g_signal_handlers_disconnect_by_func(submenuitem, G_CALLBACK(mcb_view_display_column), bar); status = display[BLC_PHYSICAL]; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(submenuitem), status); g_signal_connect(submenuitem, "toggled", G_CALLBACK(mcb_view_display_column), bar); /* Adresses virtuelles */ submenuitem = g_object_get_data(ref, "mnu_view_display_addr"); g_signal_handlers_disconnect_by_func(submenuitem, G_CALLBACK(mcb_view_display_column), bar); status = display[BLC_VIRTUAL]; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(submenuitem), status); g_signal_connect(submenuitem, "toggled", G_CALLBACK(mcb_view_display_column), bar); /* Code binaire */ submenuitem = g_object_get_data(ref, "mnu_view_display_code"); g_signal_handlers_disconnect_by_func(submenuitem, G_CALLBACK(mcb_view_display_column), bar); status = display[BLC_BINARY]; gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(submenuitem), status); g_signal_connect(submenuitem, "toggled", G_CALLBACK(mcb_view_display_column), bar); } /****************************************************************************** * * * Paramètres : ref = espace de référencements à consulter. * * panel = panneau d'affichage actif ou NULL si aucun. * * * * Description : Met à jour les accès du menu "Affichage" selon le contenu. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void update_access_in_menu_view(GObject *ref, GtkDisplayPanel *panel) { gboolean access; /* Accès à déterminer */ GtkWidget *item; /* Elément de menu à traiter */ /* Préliminaire */ access = (panel != NULL); /* Affichage des données */ item = GTK_WIDGET(g_object_get_data(ref, "mnu_view_display_off")); gtk_widget_set_sensitive(item, access); item = GTK_WIDGET(g_object_get_data(ref, "mnu_view_display_addr")); gtk_widget_set_sensitive(item, access); item = GTK_WIDGET(g_object_get_data(ref, "mnu_view_display_code")); gtk_widget_set_sensitive(item, access); } /****************************************************************************** * * * Paramètres : menuitem = élément de menu sélectionné. * * bar = barre de menu parente. * * * * Description : Réagit avec le menu "Affichage -> Panneaux latéraux". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void mcb_view_update_side_panels_list(GtkMenuItem *menuitem, GMenuBar *bar) { GtkWidget *menubar; /* Support pour éléments */ GtkAccelGroup *accgroup; /* Groupe de raccourcis */ typedef struct _panels_loading_filter { GtkContainer *support; /* Support pour éléments */ GtkAccelGroup *accel; /* Groupe de raccourcis */ PanelItemPersonality personality; /* Nature des éléments attendus*/ bool first; /* Premier ajout ? */ } panels_loading_filter; panels_loading_filter pfilter; menubar = gtk_menu_item_get_submenu(menuitem); /* Réinitialisation */ void remove_panel_menu_item(GtkWidget *widget, GtkContainer *container) { gtk_container_remove(container, widget); } gtk_container_foreach(GTK_CONTAINER(menubar), (GtkCallback)remove_panel_menu_item, menubar); /* Ajout des panneaux uniques */ bool add_side_panel_to_list(GPanelItem *panel, panels_loading_filter *filter) { const char *name; /* Désignation de l'entrée */ GtkWidget *submenuitem; /* Sous-élément de menu */ const char *bindings; /* Raccourcis clavier bruts */ if (gtk_panel_item_get_personality(panel) != filter->personality) goto aptl_exit; /* Séparation */ if (filter->first) { filter->first = false; submenuitem = qck_create_menu_separator(); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); } /* Elément de menu */ name = g_editor_item_get_name(G_EDITOR_ITEM(panel)); submenuitem = qck_create_check_menu_item(NULL, NULL, name, G_CALLBACK(mcb_view_change_panel_docking), panel); bindings = gtk_panel_item_get_key_bindings(panel); if (bindings != NULL) add_accelerator_to_menu_item(submenuitem, bindings, filter->accel); gtk_container_add(filter->support, submenuitem); /* Statut de la coche */ if (g_panel_item_is_docked(panel)) { g_signal_handlers_disconnect_by_func(submenuitem, G_CALLBACK(mcb_view_change_panel_docking), panel); gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(submenuitem), TRUE); g_signal_connect(submenuitem, "toggled", G_CALLBACK(mcb_view_change_panel_docking), panel); } aptl_exit: return true; } accgroup = GTK_ACCEL_GROUP(g_object_get_data(G_OBJECT(bar), "accgroup")); pfilter.support = GTK_CONTAINER(menubar); pfilter.accel = accgroup; pfilter.personality = PIP_SINGLETON; pfilter.first = false; browse_all_item_panels((handle_panel_item_fc)add_side_panel_to_list, &pfilter); pfilter.personality = PIP_OTHER; pfilter.first = true; browse_all_item_panels((handle_panel_item_fc)add_side_panel_to_list, &pfilter); } /****************************************************************************** * * * Paramètres : menuitem = élément de menu ayant basculé. * * bar = barre de menu parente. * * * * Description : Réagit avec le menu "Affichage -> Panneaux latéraux -> ...". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void mcb_view_change_panel_docking(GtkCheckMenuItem *menuitem, GPanelItem *item) { gboolean active; /* Etat de sélection du menu */ active = gtk_check_menu_item_get_active(menuitem); if (active) g_panel_item_dock(item); else g_panel_item_undock(item); } /****************************************************************************** * * * Paramètres : menuitem = élément de menu ayant basculé. * * bar = barre de menu parente. * * * * Description : Réagit avec le menu "Affichage -> Vue xxx". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void mcb_view_change_support(GtkRadioMenuItem *menuitem, GMenuBar *bar) { GSList *group; /* Liste de menus radio */ GSList *iter; /* Boucle de parcours */ BinaryView wanted; /* Nouvelle vue à présenter */ GtkDisplayPanel *panel; /* Afficheur effectif de code */ GtkDockStation *station; /* Base du remplacement */ GtkWidget *scroll; /* Nouveau support à utiliser */ /* On ne traite qu'une seule fois ! */ if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem))) return; group = gtk_radio_menu_item_get_group(menuitem); for (iter = group; iter != NULL; iter = g_slist_next(iter)) { if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(iter->data))) continue; wanted = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(iter->data), "kind_of_view")); panel = g_editor_item_get_current_view(G_EDITOR_ITEM(bar)); station = get_dock_station_for_view_panel(panel); /* En vue du retrait de la station d'accueil... */ scroll = get_scroll_window_for_view_panel(panel); g_object_ref(G_OBJECT(scroll)); panel = get_alt_view_for_view_panel(panel, wanted); scroll = get_scroll_window_for_view_panel(panel); gtk_dock_panel_change_active_widget(station, scroll); change_editor_items_current_view(G_EDITOR_ITEM(bar)->ref, panel); } } /****************************************************************************** * * * Paramètres : menuitem = élément de menu ayant basculé. * * bar = barre de menu parente. * * * * Description : Réagit avec le menu "Affichage -> (colonne xxx)". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void mcb_view_display_column(GtkCheckMenuItem *menuitem, GMenuBar *bar) { BufferLineColumn col; /* Colonne à traiter */ GLoadedBinary *binary; /* Binaire courant */ GtkDisplayPanel *panel; /* Affichage courant */ BinaryView view; /* Type de vue représentée */ gboolean active; /* Etat de sélection du menu */ col = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(menuitem), "kind_of_col")); binary = g_editor_item_get_current_binary(G_EDITOR_ITEM(bar)); panel = g_editor_item_get_current_view(G_EDITOR_ITEM(bar)); view = gtk_display_panel_describe_content(panel); active = gtk_check_menu_item_get_active(menuitem); g_loaded_binary_set_column_display(binary, view, col, active); } /****************************************************************************** * * * Paramètres : menuitem = élément de menu sélectionné. * * bar = barre de menu parente. * * * * Description : Réagit avec le menu "Affichage -> Plein écran". * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void mcb_view_show_full_screen(GtkCheckMenuItem *menuitem, GMenuBar *bar) { GObject *ref; /* Espace de référencements */ gboolean active; /* Etat de sélection du menu */ ref = g_editor_item_get_global_ref(G_EDITOR_ITEM(bar)); active = gtk_check_menu_item_get_active(menuitem); if (active) gtk_window_fullscreen(GTK_WINDOW(ref)); else gtk_window_unfullscreen(GTK_WINDOW(ref)); }