/* Chrysalide - Outil d'analyse de fichiers binaires * editor.c - fenêtre principale de l'interface graphique * * Copyright (C) 2015-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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "editor.h" #include #include #include #include #include #include "agroup.h" #include "status.h" #include "menus/file.h" #include "menus/menubar.h" #include "core/core.h" #include "core/panels.h" #include "core/global.h" #include "core/items.h" #include "tb/portions.h" #include "../common/extstr.h" #include "../core/global.h" #include "../core/params.h" #include "../glibext/signal.h" #include "../gtkext/easygtk.h" #include "../gtkext/gtkdisplaypanel.h" #include "../gtkext/gtkdockable.h" #include "../gtkext/gtkdockstation.h" #include "../gtkext/tiledgrid.h" #include "../gtkext/support.h" /* Met en place la liste des icônes de l'éditeur. */ static GList *build_editor_icons_list(void); /* Construit la fenêtre de l'éditeur. */ GtkWidget *create_editor(void); /* Quitte le programme en sortie de la boucle de GTK. */ static gboolean on_delete_editor(GtkWidget *, GdkEvent *, gpointer); /* Quitte le programme en sortie de la boucle de GTK. */ static void on_destroy_editor(GtkWidget *, GObject *); /* Réagit à un changement de focus pour l'éditeur. */ static gboolean on_focus_out(GtkWidget *, GdkEventFocus *, GObject *); /* Encadre certains raccourcis actionnés sur un menu. */ static gboolean track_espace_on_main_submenu(GtkWidget *, GdkEventKey *, GtkWidget *); /* Permet la disparition de la barre de menus avec le clavier. */ static void track_root_menubars(GtkContainer *, bool); /* Suit la frappe de touches sur la fenêtre principale. */ static gboolean on_key_event(GtkWidget *, GdkEventKey *, GObject *); /* ------------------------ INTEGRATION DE LA BARRE D'OUTILS ------------------------ */ /* Suit les évolutions d'affichage dans la barre d'outils. */ static void on_toolbar_item_visibility_change(GtkWidget *, GtkToolbar *); /* Construit la barre d'outils de l'éditeur. */ static GtkWidget *build_editor_toolbar(GObject *); /* ------------------- INTERACTIONS GRAPHIQUES LIEES AUX PANNEAUX ------------------- */ /* Réagit à la mise en place d'une nouvelle station d'accueil. */ static void on_dock_station_created(GtkTiledGrid *, GtkDockStation *, gpointer); /* Réagit au changement d'onglet d'un panneau quelconque. */ static void on_dock_item_switch(GtkDockStation *, GtkWidget *, gpointer); /* Encastre comme demandé un panneau dans l'éditeur. */ static void dock_panel_into_current_station(GtkCheckMenuItem *, GPanelItem *); /* Réagit à une demande de menu pour rajouter des panneaux. */ static void on_dock_menu_request(GtkDockStation *, GtkWidget *, gpointer); /* Réagit à une demande de fermeture du panneau courant. */ static void on_dock_close_request(GtkDockStation *, GtkWidget *, gpointer); /* ------------------------- INTEGRATION ET SUIVI DE PROJET ------------------------- */ /* Réagit à un changement du projet principal. */ static void notify_editor_project_change(GStudyProject *, bool); /* Assure un positionnement initial idéal. */ static gboolean scroll_for_the_first_time(GtkWidget *, GdkEvent *, GLoadedContent *); /* Affiche le contenu qui vient de rejoindre un projet donné. */ void on_editor_loaded_content_added(GStudyProject *, GLoadedContent *, void *); /****************************************************************************** * * * Paramètres : - * * * * Description : Met en place la liste des icônes de l'éditeur. * * * * Retour : Liste d'images dimensionnées. * * * * Remarques : - * * * ******************************************************************************/ static GList *build_editor_icons_list(void) { GList *result; /* Liste à retourner */ GdkPixbuf *pixbuf; /* Image chargée en mémoire */ result = NULL; pixbuf = get_pixbuf_from_file("chrysalide-32.png"); if (pixbuf != NULL) result = g_list_append(result, pixbuf); pixbuf = get_pixbuf_from_file("chrysalide-64.png"); if (pixbuf != NULL) result = g_list_append(result, pixbuf); pixbuf = get_pixbuf_from_file("chrysalide-128.png"); if (pixbuf != NULL) result = g_list_append(result, pixbuf); return result; } /****************************************************************************** * * * Paramètres : - * * * * Description : Construit la fenêtre de l'éditeur. * * * * Retour : Adresse de la fenêtre mise en place. * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *create_editor(void) { GtkWidget *result; /* Fenêtre à renvoyer */ bool hide; /* Cachette de la barre ? */ bool maximized; /* Affichage en plein écran ? */ GList *icons; /* Liste d'images dimensionnées*/ GObject *ref; /* Version de référence */ GtkAccelGroup *accgroup; /* Groupe de raccourcis clavier*/ GEditorItem *editem; /* Menus réactifs principaux */ GtkWidget *menuboard; /* Barre de menus principale */ GtkWidget *toolbar; /* Barre d'outils */ GtkWidget *grid; /* Affichage en tuiles */ GtkWidget *vbox1; GtkWidget *widget; /* Composant à intégrer */ result = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_widget_set_size_request(result, 1024, 800); gtk_window_set_position(GTK_WINDOW(result), GTK_WIN_POS_CENTER); gtk_container_set_border_width(GTK_CONTAINER(result), 4); gtk_window_set_title(GTK_WINDOW(result), _("Chrysalide")); set_editor_window(GTK_WINDOW(result)); g_generic_config_get_value(get_main_configuration(), MPK_TITLE_BAR, &hide); gtk_window_set_hide_titlebar_when_maximized(GTK_WINDOW(result), hide); g_generic_config_get_value(get_main_configuration(), MPK_MAXIMIZED, &maximized); gtk_window_maximize(GTK_WINDOW(result)); icons = build_editor_icons_list(); gtk_window_set_icon_list(GTK_WINDOW(result), icons); g_list_free_full(icons, (GDestroyNotify)g_object_unref); ref = G_OBJECT(result); g_signal_connect(ref, "delete-event", G_CALLBACK(on_delete_editor), NULL); g_signal_connect(ref, "destroy", G_CALLBACK(on_destroy_editor), ref); g_signal_connect(ref, "focus-out-event", G_CALLBACK(on_focus_out), ref); g_signal_connect(ref, "key-press-event", G_CALLBACK(on_key_event), ref); g_signal_connect(ref, "key-release-event", G_CALLBACK(on_key_event), ref); accgroup = gtk_accel_group_new(); set_accel_group(accgroup); gtk_window_add_accel_group(GTK_WINDOW(result), accgroup); vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4); gtk_widget_show(vbox1); gtk_container_add(GTK_CONTAINER(result), vbox1); /* Intégration des menus */ editem = g_menu_bar_new(ref); register_editor_item(editem); menuboard = g_editor_item_get_widget(editem); gtk_box_pack_start(GTK_BOX(vbox1), menuboard, FALSE, FALSE, 0); g_object_set_data(ref, "menubar", editem); g_object_set_data(ref, "menuboard", menuboard); gtk_widget_hide(menuboard); /* Barre d'outils */ toolbar = build_editor_toolbar(ref); gtk_box_pack_start(GTK_BOX(vbox1), toolbar, FALSE, FALSE, 0); /* Coeur de la fenêtre principale */ grid = gtk_tiled_grid_new(); gtk_widget_show(grid); set_tiled_grid(GTK_TILED_GRID(grid)); g_signal_connect(grid, "station-created", G_CALLBACK(on_dock_station_created), NULL); gtk_box_pack_start(GTK_BOX(vbox1), grid, TRUE, TRUE, 0); /* Barre de statut générale */ editem = g_status_info_new(ref); register_editor_item(editem); widget = g_editor_item_get_widget(editem); gtk_box_pack_start(GTK_BOX(vbox1), widget, FALSE, FALSE, 0); /* Autre */ /* ... = */prepare_drag_and_drop_window(); /* Actualisation des contenus */ register_project_change_notification(notify_editor_project_change); change_editor_items_current_content(NULL); change_editor_items_current_view(NULL); return result; } /****************************************************************************** * * * Paramètres : widget = fenêtre de l'éditeur de préférences. * * event = informations liées à l'événement. * * data = adresse non utilisée ici. * * * * Description : Quitte le programme en sortie de la boucle de GTK. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static gboolean on_delete_editor(GtkWidget *widget, GdkEvent *event, gpointer data) { gboolean result; /* Continuation à retourner */ bool skip; /* Saut de la vérification ? */ GStudyProject *project; /* Projet courant */ GtkWidget *dialog; /* Boîte à afficher */ result = FALSE; g_generic_config_get_value(get_main_configuration(), MPK_SKIP_EXIT_MSG, &skip); if (skip) goto skip_warning; project = get_current_project(); if (g_study_project_get_filename(project) == NULL) { dialog = gtk_message_dialog_new(GTK_WINDOW(widget), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, _("The current project will be lost. Do you you want to save it ?")); gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Yes"), GTK_RESPONSE_YES); gtk_dialog_add_button(GTK_DIALOG(dialog), _("_No"), GTK_RESPONSE_NO); gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Cancel"), GTK_RESPONSE_CANCEL); switch (gtk_dialog_run(GTK_DIALOG(dialog))) { case GTK_RESPONSE_YES: mcb_file_save_project(NULL, NULL); break; case GTK_RESPONSE_NO: break; case GTK_RESPONSE_CANCEL: result = TRUE; break; } gtk_widget_destroy(dialog); } g_object_unref(G_OBJECT(project)); skip_warning: return result; } /****************************************************************************** * * * Paramètres : widget = fenêtre de l'éditeur de préférences. * * ref = espace de référencement global. * * * * Description : Quitte le programme en sortie de la boucle de GTK. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_destroy_editor(GtkWidget *widget, GObject *ref) { /* Fermeture propre */ gtk_tiled_grid_save_positions(get_tiled_grid(), get_main_configuration()); /* ... */ on_focus_out(widget, NULL, ref); /* Si la boucle principale est bien lancée, on en sort ! */ if (gtk_main_level() > 0) gtk_main_quit(); } /****************************************************************************** * * * Paramètres : widget = fenêtre de l'éditeur de préférences. * * event = informations liées à l'événement. * * ref = espace de référencement global. * * * * Description : Réagit à un changement de focus pour l'éditeur. * * * * Retour : TRUE pour arrêter la propagation du signal, FALSE sinon. * * * * Remarques : - * * * ******************************************************************************/ static gboolean on_focus_out(GtkWidget *widget, GdkEventFocus *event, GObject *ref) { GtkWidget *menuboard; /* Planche de menu à traiter */ menuboard = GTK_WIDGET(g_object_get_data(ref, "menuboard")); if (gtk_widget_get_visible(menuboard)) { track_root_menubars(GTK_CONTAINER(menuboard), false); gtk_widget_hide(menuboard); } return FALSE; } /****************************************************************************** * * * Paramètres : menu = composant actif pour la réception des touches. * * event = informations liées à l'événement. * * item = menu parent à manipuler au besoin. * * * * Description : Encadre certains raccourcis actionnés sur un menu. * * * * Retour : FALSE afin de poursuivre la propagation de l'événement. * * * * Remarques : - * * * ******************************************************************************/ static gboolean track_espace_on_main_submenu(GtkWidget *menu, GdkEventKey *event, GtkWidget *item) { GtkWidget *mbar; /* Barre de menus principale */ if (event->keyval == GDK_KEY_Escape) { mbar = gtk_widget_get_parent(item); track_root_menubars(GTK_CONTAINER(mbar), false); gtk_widget_hide(mbar); } return FALSE; } /****************************************************************************** * * * Paramètres : menubar = barre de menu principale à traiter. * * set = indique si la surveillance est à activer ou non. * * * * Description : Permet la disparition de la barre de menus avec le clavier. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void track_root_menubars(GtkContainer *menubar, bool set) { void browse_all_main_items(GtkWidget *item, bool *track) { GtkWidget *menu; /* Menu à traiter */ menu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item)); if (*track) g_signal_connect(menu, "key-press-event", G_CALLBACK(track_espace_on_main_submenu), item); else g_signal_handlers_disconnect_by_func(menu, G_CALLBACK(track_espace_on_main_submenu), item); } gtk_container_foreach(menubar, (GtkCallback)browse_all_main_items, &set); } /****************************************************************************** * * * Paramètres : widget = fenêtre de l'éditeur de préférences. * * event = informations liées à l'événement. * * ref = espace de référencement global. * * * * Description : Suit la frappe de touches sur la fenêtre principale. * * * * Retour : FALSE pour poursuivre la propagation de l'événement. * * * * Remarques : - * * * ******************************************************************************/ static gboolean on_key_event(GtkWidget *widget, GdkEventKey *event, GObject *ref) { GtkWidget *menuboard; /* Planche de menu à traiter */ static bool skip_event = false; menuboard = GTK_WIDGET(g_object_get_data(ref, "menuboard")); if (gtk_widget_get_visible(menuboard)) { if (event->type == GDK_KEY_PRESS && event->keyval == GDK_KEY_Alt_L) { skip_event = true; track_root_menubars(GTK_CONTAINER(menuboard), false); gtk_widget_hide(menuboard); } } else { if (event->type == GDK_KEY_PRESS && event->state == GDK_MOD1_MASK) { track_root_menubars(GTK_CONTAINER(menuboard), true); gtk_widget_show(menuboard); } else if (event->type == GDK_KEY_RELEASE && event->keyval == GDK_KEY_Alt_L) { if (skip_event) skip_event = false; else { track_root_menubars(GTK_CONTAINER(menuboard), true); gtk_widget_show(menuboard); } } } return FALSE; } /* ---------------------------------------------------------------------------------- */ /* INTEGRATION DE LA BARRE D'OUTILS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : widget = composant graphique dont l'affichage a basculé. * * toolbar = barre d'outils à mettre à jour. * * * * Description : Suit les évolutions d'affichage dans la barre d'outils. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_toolbar_item_visibility_change(GtkWidget *widget, GtkToolbar *toolbar) { bool show; /* Impose un affichage */ show = false; void visit_all_tb_items(GtkWidget *w, gpointer unused) { show |= gtk_widget_get_visible(w); } gtk_container_foreach(GTK_CONTAINER(toolbar), visit_all_tb_items, NULL); if (show) gtk_widget_show(GTK_WIDGET(toolbar)); else gtk_widget_hide(GTK_WIDGET(toolbar)); } /****************************************************************************** * * * Paramètres : ref = espace de référencement global. * * * * Description : Construit la barre d'outils de l'éditeur. * * * * Retour : Adresse du composant mis en place. * * * * Remarques : - * * * ******************************************************************************/ static GtkWidget *build_editor_toolbar(GObject *ref) { GtkWidget *result; /* Support à retourner */ GEditorItem *item; /* Elément de barre d'outils */ result = gtk_toolbar_new(); gtk_widget_show(result); g_object_set_data(ref, "toolbar", result); item = create_portions_tb_item(ref); register_editor_item(item); void track_tb_items_visibility(GtkWidget *widget, gpointer unused) { g_signal_connect(widget, "hide", G_CALLBACK(on_toolbar_item_visibility_change), result); g_signal_connect(widget, "show", G_CALLBACK(on_toolbar_item_visibility_change), result); } gtk_container_foreach(GTK_CONTAINER(result), track_tb_items_visibility, NULL); return result; } /* ---------------------------------------------------------------------------------- */ /* INTERACTIONS GRAPHIQUES LIEES AUX PANNEAUX */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : grid = composant d'affichage en tuiles concerné. * * station = nouvelle station créée. * * unused = adresse non utilisée ici. * * * * Description : Réagit à la mise en place d'une nouvelle station d'accueil. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_dock_station_created(GtkTiledGrid *grid, GtkDockStation *station, gpointer unused) { g_signal_connect(station, "switch-widget", G_CALLBACK(on_dock_item_switch), NULL); g_signal_connect(station, "menu-requested", G_CALLBACK(on_dock_menu_request), NULL); g_signal_connect(station, "close-requested", G_CALLBACK(on_dock_close_request), NULL); } /****************************************************************************** * * * Paramètres : station = panneau de support des éléments concerné. * * item = nouvel élément présenté à l'affichage. * * unused = adresse non utilisée ici. * * * * Description : Réagit au changement d'onglet d'un panneau quelconque. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_dock_item_switch(GtkDockStation *station, GtkWidget *widget, gpointer unused) { GLoadedPanel *panel; /* Vue du contenu chargé */ GLoadedContent *content; /* Contenu en cours d'édition */ char *path; /* Chemin d'accueil concerné */ if (!G_IS_LOADED_PANEL(widget) && GTK_IS_SCROLLED_WINDOW(widget)) widget = gtk_bin_get_child(GTK_BIN(widget)); if (!G_IS_LOADED_PANEL(widget) && GTK_IS_VIEWPORT(widget)) widget = gtk_bin_get_child(GTK_BIN(widget)); if (G_IS_LOADED_PANEL(widget)) { panel = G_LOADED_PANEL(widget); content = g_loaded_panel_get_content(panel); change_editor_items_current_content(content); g_object_unref(G_OBJECT(content)); change_editor_items_current_view(panel); } else { path = gtk_tiled_grid_get_path_for_station(get_tiled_grid(), station); assert(path != NULL); if (strcmp(path, "M") == 0) { change_editor_items_current_content(NULL); change_editor_items_current_view(NULL); } free(path); } } /****************************************************************************** * * * Paramètres : menuitem = élement de menu actionné. * * item = panneau à ajouter à l'interface graphique. * * * * Description : Encastre comme demandé un panneau dans l'éditeur. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void dock_panel_into_current_station(GtkCheckMenuItem *menuitem, GPanelItem *item) { GtkWidget *parent; /* Menu parent avec chemin */ const char *new_path; /* Nouveau chemin à appliquer */ parent = gtk_widget_get_parent(GTK_WIDGET(menuitem)); new_path = g_object_get_data(G_OBJECT(parent), "path"); gtk_panel_item_set_path(item, new_path); g_panel_item_dock(item); } /****************************************************************************** * * * Paramètres : station = panneau de support des éléments concerné. * * button = bouton à l'origine de la procédure. * * unsued = adresse non utilisée ici. * * * * Description : Réagit à une demande de menu pour rajouter des panneaux. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_dock_menu_request(GtkDockStation *station, GtkWidget *button, gpointer unused) { GtkWidget *active; /* Composant actif modèle */ GPanelItem *model; /* Panneau encapsulé */ GtkContainer *menu; /* Support à retourner */ GList *children; /* Composants mis en place */ GtkWidget *nopanel; /* Sous-élément de menu */ menu = GTK_CONTAINER(qck_create_menu(NULL)); active = gtk_notebook_get_nth_page(GTK_NOTEBOOK(station), 0); model = G_PANEL_ITEM(g_object_get_data(G_OBJECT(active), "dockable")); g_object_set_data_full(G_OBJECT(menu), "path", strdup(gtk_panel_item_get_path(model)), free); /* Ajout des panneaux uniques */ bool add_side_panel_to_menu(GPanelItem *panel, GtkContainer *support) { const char *name; /* Désignation de l'entrée */ GtkWidget *submenuitem; /* Sous-élément de menu */ const char *bindings; /* Raccourcis clavier bruts */ /* Profil qui ne cadre pas ? */ if (gtk_panel_item_get_personality(panel) != PIP_SINGLETON) goto aptm_exit; if (g_panel_item_is_docked(panel)) goto aptm_exit; /* Elément de menu */ name = g_editor_item_get_name(G_EDITOR_ITEM(panel)); submenuitem = qck_create_menu_item(NULL, NULL, name, G_CALLBACK(dock_panel_into_current_station), panel); bindings = gtk_panel_item_get_key_bindings(panel); if (bindings != NULL) add_accelerator_to_widget(submenuitem, bindings); gtk_container_add(support, submenuitem); aptm_exit: return true; } browse_all_item_panels((handle_panel_item_fc)add_side_panel_to_menu, menu); /* Avertissement en cas d'indisponibilité */ children = gtk_container_get_children(GTK_CONTAINER(menu)); if (children == NULL) { nopanel = qck_create_menu_item(NULL, NULL, "No available free panel", NULL, NULL); gtk_widget_set_sensitive(nopanel, FALSE); gtk_container_add(GTK_CONTAINER(menu), nopanel); } else g_list_free(children); /* Affichage du menu */ gtk_menu_popup_at_widget(GTK_MENU(menu), button, GDK_GRAVITY_SOUTH_WEST, GDK_GRAVITY_NORTH_WEST, NULL); } /****************************************************************************** * * * Paramètres : station = panneau de support des éléments concerné. * * button = bouton à l'origine de la procédure. * * unused = adresse non utilisée ici. * * * * Description : Réagit à une demande de fermeture du panneau courant. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_dock_close_request(GtkDockStation *station, GtkWidget *button, gpointer unused) { gint index; /* Indice de la page courante */ GtkWidget *active; /* Composant actif modèle */ GPanelItem *panel; /* Panneau encapsulé */ index = gtk_notebook_get_current_page(GTK_NOTEBOOK(station)); active = gtk_notebook_get_nth_page(GTK_NOTEBOOK(station), index); panel = G_PANEL_ITEM(g_object_get_data(G_OBJECT(active), "dockable")); g_panel_item_undock(panel); } /* ---------------------------------------------------------------------------------- */ /* INTEGRATION ET SUIVI DE PROJET */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : project = projet concerné par la procédure. * * new = indique si le projet est le nouvel actif ou non. * * * * Description : Réagit à un changement du projet principal. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void notify_editor_project_change(GStudyProject *project, bool new) { if (new) { g_signal_connect_to_main(project, "content-added", G_CALLBACK(on_editor_loaded_content_added), NULL, g_cclosure_marshal_VOID__OBJECT); /* TODO : show_all()... */ } else { g_study_project_hide(project); } } /****************************************************************************** * * * Paramètres : project = project impliqué dans l'opération. * * content = nouveau contenu à présenter dans l'éditeur. * * unused = adresse non utilisée ici. * * * * Description : Affiche le contenu qui vient de rejoindre un projet donné. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void on_editor_loaded_content_added(GStudyProject *project, GLoadedContent *content, void *unused) { GtkWidget *selected; /* Interface de prédilection */ const char *name; /* Titre associé au binaire */ const char *lname; /* Description du binaire */ GPanelItem *panel; /* Nouveau panneau à integrer */ selected = g_loaded_content_build_view(content, 0); name = g_loaded_content_describe(content, false); lname = g_loaded_content_describe(content, true); panel = g_panel_item_new(PIP_BINARY_VIEW, name, lname, selected, true, "M"); register_panel_item(panel, get_main_configuration()); g_signal_connect(selected, "size-allocate", G_CALLBACK(scroll_for_the_first_time), content); g_panel_item_dock(panel); update_project_area(project); } /****************************************************************************** * * * Paramètres : widget = composant d'affichage nouvellement porté à l'écran.* * event = informations liées à l'événement. * * content = contenu chargé associé au composant d'affichage. * * * * Description : Assure un positionnement initial idéal. * * * * Retour : FALSE. * * * * Remarques : - * * * ******************************************************************************/ static gboolean scroll_for_the_first_time(GtkWidget *widget, GdkEvent *event, GLoadedContent *content) { GExeFormat *format; /* Format associé au binaire */ vmpa2t target; /* Position initiale à viser */ GtkWidget *panel; /* Panneau à dérouler */ g_signal_handlers_disconnect_by_func(widget, G_CALLBACK(scroll_for_the_first_time), content); if (G_IS_LOADED_BINARY(content)) { format = g_loaded_binary_get_format(G_LOADED_BINARY(content)); if (g_exe_format_get_main_address(format, &target)) { panel = get_loaded_panel_from_built_view(widget); gtk_display_panel_request_move(GTK_DISPLAY_PANEL(panel), &target); } g_object_unref(G_OBJECT(format)); } return FALSE; }