/* Chrysalide - Outil d'analyse de fichiers binaires * editor.c - fenêtre principale de l'interface graphique * * Copyright (C) 2008-2013 Cyrille Bagard * * This file is part of Chrysalide. * * 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 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 "status.h" #include "menus/menubar.h" #include "panels/panel.h" #include "tb/portions.h" #include "tb/source.h" #include "../analysis/project.h" #include "../common/extstr.h" #include "../core/params.h" #include "../gtkext/easygtk.h" #include "../gtkext/gtkdockable.h" #include "../gtkext/gtkdockstation.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 *, gpointer); /* Réagit au changement d'onglet d'un panneau quelconque. */ static void on_dock_item_switch(GtkDockStation *, GtkWidget *, GObject *); /* ------------------------ INTEGRATION DE LA BARRE D'OUTILS ------------------------ */ /* Construit la barre d'outils de l'éditeur. */ static GtkWidget *build_editor_toolbar(GObject *); /* -------------------- MECANISMES DE (DE)PLACEMENT DES PANNEAUX -------------------- */ /* Elément de la hiérarchie des panneaux */ typedef struct _panel_node { struct _panel_node *parent; /* Noeud parent */ union { GtkWidget *widget; /* Accès généraliste */ GtkWidget *station; /* Station d'accueil simple */ GtkWidget *paned; /* Station d'accueil composée */ }; union { /* Version simple */ struct { char *path; /* Chemin du nom courant */ }; /* Version composée */ struct { struct _panel_node *first; /* Premier sous élément */ struct _panel_node *second; /* Second sous élément */ }; }; } panel_node; #define IS_SIMPLE_NODE(nd) \ ({ \ bool __result; \ __result = GTK_IS_DOCK_STATION(nd->station); \ assert(__result || GTK_IS_PANED(nd->paned)); \ __result; \ }) /* Support de fond pour les composants. */ static GObject *_global_ref = NULL; static GtkWidget *_support = NULL; static panel_node *_nodes = NULL; /* Crée un nouveau noeud pour un panneau particulier. */ static panel_node *create_simple_panel_node_for_item(GPanelItem *, const char *); /* Prépare une nouvelle sous-division pour deux panneaux. */ static void switch_panel_node_into_paned(panel_node *, bool, bool); /* Met en place un nouveau noeud dans une division. */ static void attach_panel_node_to_paned(panel_node *, panel_node *, bool); /* Obtient la désignation d'un élément hiérarchie des noeuds. */ static char *get_panel_node_path(const panel_node *); /* Détermine la plus grande longueur commune entre éléments. */ static size_t compute_path_common_length(const panel_node *, const char *); /* Place au bon endroit un panneau donné. */ static void insert_item_as_panel_node(GPanelItem *, panel_node *, const char *, size_t); /* Tente de mettre la main sur une station d'accueil. */ static panel_node *find_node_for_station(panel_node *, GtkWidget *); /* Efface de l'organisation un noeud donné en place. */ static void delete_panel_node(panel_node *); /* ------------------- INTERACTIONS GRAPHIQUES LIEES AUX PANNEAUX ------------------- */ /* Réagit à une demande de placement d'un panneau d'affichage. */ void on_panel_item_dock_request(GPanelItem *, void *); /* Réagit à une demande de suppression d'un panneau d'affichage. */ void on_panel_item_undock_request(GPanelItem *, 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 */ GEditorItem *editem; /* Menus réactifs principaux */ GtkWidget *menuboard; /* Barre de menus principale */ GtkWidget *toolbar; /* Barre d'outils */ GtkWidget *vbox1; GtkAccelGroup *accgroup; 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")); 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); g_signal_connect(G_OBJECT(result), "delete-event", G_CALLBACK(on_delete_editor), NULL); g_signal_connect(G_OBJECT(result), "destroy", G_CALLBACK(on_destroy_editor), NULL); ref = G_OBJECT(result); accgroup = gtk_accel_group_new(); 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, accgroup); register_editor_item(editem); menuboard = g_editor_item_get_widget(editem); gtk_box_pack_start(GTK_BOX(vbox1), menuboard, FALSE, FALSE, 0); /* Barre d'outils */ toolbar = build_editor_toolbar(G_OBJECT(result)); gtk_box_pack_start(GTK_BOX(vbox1), toolbar, FALSE, FALSE, 0); do { _global_ref = ref; _support = gtk_event_box_new(); gtk_widget_show(_support); //_support = init_panels2(G_CALLBACK(on_dock_item_switch), ref); gtk_box_pack_start(GTK_BOX(vbox1), _support, TRUE, TRUE, 0); load_main_panels(ref); } while(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(); 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 */ GStudyProject *project; /* Projet courant */ GtkWidget *dialog; /* Boîte à afficher */ result = FALSE; project = get_current_project(); if (project == NULL) goto ode_no_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_as(NULL, widget); /* FIXME */ break; case GTK_RESPONSE_NO: break; case GTK_RESPONSE_CANCEL: result = TRUE; break; } gtk_widget_destroy(dialog); } ode_no_project: 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 void on_destroy_editor(GtkWidget *widget, gpointer data) { GStudyProject *project; /* Projet courant */ project = get_current_project(); if (project != NULL) g_object_unref(G_OBJECT(project)); //if (!result) save_panel_nodes(); /* Fermeture propre */ /* ... */ gtk_main_quit(); } /****************************************************************************** * * * Paramètres : station = panneau de support des éléments concerné. * * item = nouvel élément présenté à l'affichage. * * ref = adresse de l'espace de référencement global. * * * * Description : Réagit au changement d'onglet d'un panneau quelconque. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void on_dock_item_switch(GtkDockStation *station, GtkWidget *widget, GObject *ref) { GLoadedBinary *old_binary; /* Ancien binaire édité */ GLoadedBinary *binary; /* Binaire en cours d'édition */ if (GTK_IS_SCROLLED_WINDOW(widget)) widget = gtk_bin_get_child(GTK_BIN(widget)); if (GTK_IS_VIEWPORT(widget)) widget = gtk_bin_get_child(GTK_BIN(widget)); if (GTK_IS_VIEW_PANEL(widget)) { /* Changement de binaire ? */ old_binary = G_LOADED_BINARY(g_object_get_data(ref, "current_binary")); binary = gtk_view_panel_get_binary(GTK_VIEW_PANEL(widget)); if (old_binary != binary) { //notify_panels_of_binary_change(binary); change_editor_items_current_binary(ref, binary); } change_editor_items_current_view(ref, GTK_VIEW_PANEL(widget)); //notify_panels_of_view_change(GTK_VIEW_PANEL(widget), false); } } /* ---------------------------------------------------------------------------------- */ /* INTEGRATION DE LA BARRE D'OUTILS */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * 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_source_tb_item(ref); register_editor_item(item); item = create_portions_tb_item(ref); register_editor_item(item); return result; } /* ---------------------------------------------------------------------------------- */ /* MECANISMES DE (DE)PLACEMENT DES PANNEAUX */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : item = composant à présenter à l'affichage. * * path = partie du chemin représentée ici. * * * * Description : Crée un nouveau noeud pour un panneau particulier. * * * * Retour : Structure d'accueil mise en place. * * * * Remarques : - * * * ******************************************************************************/ static panel_node *create_simple_panel_node_for_item(GPanelItem *item, const char *path) { panel_node *result; /* Structure à retourner */ GtkWidget *station; /* Premier support concentré */ /* Partie graphique */ station = gtk_dock_station_new(); g_signal_connect(station, "switch-widget", G_CALLBACK(on_dock_item_switch), _global_ref); gtk_widget_show(station); gtk_dock_station_add_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(item)); /* Partie invisible */ result = (panel_node *)calloc(1, sizeof(panel_node)); result->station = station; result->path = strdup(path); return result; } /****************************************************************************** * * * Paramètres : node = noeud à diviser. * * horiz = indique le type d'orientation désiré. * * first = indication sur l'emplacement à utiliser. * * * * Description : Prépare une nouvelle sous-division pour deux panneaux. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void switch_panel_node_into_paned(panel_node *node, bool horiz, bool first) { GtkWidget *widget; /* Composant à traiter */ panel_node *parent; /* Lien de parenté à conserver */ panel_node *moved; /* Noeud descendu d'un étage */ /* Décroche graphiquement le support */ widget = node->widget; g_object_ref(G_OBJECT(widget)); gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(widget)), widget); /* Descend l'élément actuel */ parent = node->parent; moved = (panel_node *)calloc(1, sizeof(panel_node)); memcpy(moved, node, sizeof(panel_node)); if (!IS_SIMPLE_NODE(moved)) { moved->first->parent = moved; moved->second->parent = moved; } /* Création du nouveau niveau intermédiaire */ if (horiz) node->paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); else node->paned = gtk_paned_new(GTK_ORIENTATION_VERTICAL); gtk_widget_show(node->paned); if (parent == NULL) attach_panel_node_to_paned(parent, node, true); else attach_panel_node_to_paned(parent, node, parent->first == node); /* Premier ajustement */ void split_paned_support(GtkWidget *support, GdkRectangle *alloc, gpointer data) { GtkOrientation orientation; gint position; orientation = gtk_orientable_get_orientation(GTK_ORIENTABLE(support)); if (orientation == GTK_ORIENTATION_HORIZONTAL) position = alloc->width / 2; else position = alloc->height / 2; /* if (position < 50) position *= 2; */ gtk_paned_set_position(GTK_PANED(support), position); fprintf(stderr, "widget size is currently %dx%d\n", alloc->width, alloc->height); fprintf(stderr, "position = %d\n", position); fprintf(stderr, "---\n"); g_signal_handlers_disconnect_by_func(support, G_CALLBACK(split_paned_support), NULL); } //g_signal_connect(current->paned, "size-allocate", G_CALLBACK(split_paned_support), NULL); static int __counter = 0; if (++__counter == 4) gtk_paned_set_position(GTK_PANED(node->paned), 100); /* Replace le composant d'origine */ attach_panel_node_to_paned(node, moved, first); } /****************************************************************************** * * * Paramètres : parent = noeud d'accueil pour le nouveau noeud. * * node = nouveau noeud à intégrer dans l'ensemble. * * first = indication sur l'emplacement à utiliser. * * * * Description : Met en place un nouveau noeud dans une division. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void attach_panel_node_to_paned(panel_node *parent, panel_node *node, bool first) { node->parent = parent; /* On se trouve à la racine... */ if (parent == NULL) gtk_container_add(GTK_CONTAINER(_support), node->widget); else { /* Raccordement hiérarchique */ if (first) parent->first = node; else parent->second = node; /* Raccordement graphique */ assert(!IS_SIMPLE_NODE(parent)); if (first) gtk_paned_pack1(GTK_PANED(parent->paned), node->widget, TRUE, FALSE); else gtk_paned_pack2(GTK_PANED(parent->paned), node->widget, TRUE, FALSE); } } /****************************************************************************** * * * Paramètres : node = noeud dont la désignation est à obtenir. * * * * Description : Obtient la désignation d'un élément hiérarchie des noeuds. * * * * Retour : Chaîne construite à libérer de la mémoire après usage. * * * * Remarques : - * * * ******************************************************************************/ static char *get_panel_node_path(const panel_node *node) { char *result; /* Valeur à retourner */ char *extra; /* Complément à ajouter */ if (IS_SIMPLE_NODE(node)) result = strdup(node->path); else { result = get_panel_node_path(node->first); extra = get_panel_node_path(node->second); result = stradd(result, "-"); result = stradd(result, extra); free(extra); result = strprep(result, "("); result = stradd(result, ")"); } return result; } /****************************************************************************** * * * Paramètres : node = noeud d'où lancer les recherches. * * target = identifiant de la position visée. * * * * Description : Détermine la plus grande longueur commune entre éléments. * * * * Retour : Bilan de l'évaluation. * * * * Remarques : - * * * ******************************************************************************/ static size_t compute_path_common_length(const panel_node *node, const char *target) { size_t result; /* Taille à retourner */ size_t len; /* Longueur de comparaison */ size_t common1; /* Tron common avec le côté #1 */ size_t common2; /* Tron common avec le côté #2 */ if (IS_SIMPLE_NODE(node)) { len = MIN(strlen(node->path), strlen(target)); /** * Il n'y a pas forcément de base commune entre deux branches, * donc on parcourt les chemins depuis leur base respective. */ for (result = 0; result < len; result++) if (node->path[result] != target[result]) break; } else { common1 = compute_path_common_length(node->first, target); common2 = compute_path_common_length(node->second, target); result = MAX(common1, common2); } return result; } /****************************************************************************** * * * Paramètres : item = composant à présenter à l'affichage. * * node = point d'insertion courant. * * path = partie du chemin représentée ici. * * consumed = profondeur du chemin utilisé. * * * * Description : Place au bon endroit un panneau donné. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void insert_item_as_panel_node(GPanelItem *item, panel_node *node, const char *path, size_t consumed) { char div; /* Division demandée */ bool horiz; /* Traduction en composant */ bool first; /* Point d'insertion */ panel_node *new; /* Nouveau noeud créé */ size_t common1; /* Tron common avec le côté #1 */ size_t common2; /* Tron common avec le côté #2 */ fprintf(stderr, "=== INSERTING '%s' (%zu)... -> '%s'\n", path, consumed, IS_SIMPLE_NODE(node) ? node->path : "-"); if (IS_SIMPLE_NODE(node)) { /* Le parcours s'arrête ici ! */ if (strcmp(node->path, path) == 0) gtk_dock_station_add_dockable(GTK_DOCK_STATION(node->station), GTK_DOCKABLE(item)); /* On ne peut aller plus loin, on doit diviser... */ else { div = toupper(path[consumed]); first = (div == 'W' || div == 'N'); horiz = (div == 'W' || div == 'E'); fprintf(stderr, "---%%<--- first=%d horiz=%d\n", first, horiz); fprintf(stderr, "--- cutting %p\n", node->station); switch_panel_node_into_paned(node, horiz, !first); new = create_simple_panel_node_for_item(item, path); attach_panel_node_to_paned(node, new, first); fprintf(stderr, "1# [%p] widget = %p --- split :: %p // %p\n", node, node->station, node->first, node->second); } } /* On regarde des autres côtés... */ else { common1 = compute_path_common_length(node->first, path); common2 = compute_path_common_length(node->second, path); fprintf(stderr, " - L1 :: %zu <-> '%s'\n", common1, get_panel_node_path(node->first)); fprintf(stderr, " - L2 :: %zu <-> '%s'\n", common2, get_panel_node_path(node->second)); /* Si une descente est possible... */ if (common1 > 0 || common2 > 0) { if (common1 > common2) insert_item_as_panel_node(item, node->first, path, common1); else insert_item_as_panel_node(item, node->second, path, common2); } /* Sinon, on doit diviser qqch... */ else { div = toupper(path[consumed]); first = (div == 'W' || div == 'N'); horiz = (div == 'W' || div == 'E'); fprintf(stderr, "---%%<--- first=%d horiz=%d\n", first, horiz); switch_panel_node_into_paned(node, horiz, !first); new = create_simple_panel_node_for_item(item, path); attach_panel_node_to_paned(node, new, first); fprintf(stderr, "2# [%p] split :: %p-%p // %p-%p\n", node, node->first, node->first->widget, node->second, node->second->widget); } } } /****************************************************************************** * * * Paramètres : node = point de départ des recherches locales. * * * * Description : Tente de mettre la main sur une station d'accueil. * * * * Retour : Eventuel noeud trouvé ou NULL. * * * * Remarques : - * * * ******************************************************************************/ static panel_node *find_node_for_station(panel_node *node, GtkWidget *station) { panel_node *result; /* Bilan à remonter */ if (IS_SIMPLE_NODE(node)) result = (node->station == station ? node : NULL); else { result = find_node_for_station(node->first, station); if (result == NULL) result = find_node_for_station(node->second, station); } return result; } /****************************************************************************** * * * Paramètres : node = noeud à supprimer de l'arbre des noeuds. * * * * Description : Efface de l'organisation un noeud donné en place. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void delete_panel_node(panel_node *node) { panel_node *parent; /* Noeud parent à transformer */ GtkWidget *widget; /* Composant à traiter */ panel_node *grandparent; /* Noeud supérieur au parent */ panel_node *remaining; /* Noeud restant */ assert(IS_SIMPLE_NODE(node)); parent = node->parent; /* Destruction du noeud */ widget = node->station; gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(widget)), widget); free(node->path); free(node); /* Suppression du niveau intermédiaire */ if (parent != NULL) { remaining = (node == parent->first ? parent->second : parent->first); /* Décroche graphiquement le support */ widget = remaining->widget; g_object_ref(G_OBJECT(widget)); gtk_container_remove(GTK_CONTAINER(parent->paned), widget); /* Supprime le composant graphique intermédiaire */ gtk_container_remove(GTK_CONTAINER(gtk_widget_get_parent(parent->paned)), parent->paned); /* Réinsère la partie restante */ grandparent = parent->parent; memcpy(parent, remaining, sizeof(panel_node)); if (!IS_SIMPLE_NODE(parent)) { parent->first->parent = parent; parent->second->parent = parent; } free(remaining); if (grandparent == NULL) attach_panel_node_to_paned(grandparent, parent, true); else attach_panel_node_to_paned(grandparent, parent, grandparent->first == parent); } } #if 1 #include "../core/params.h" /****************************************************************************** * * * Paramètres : current = point de départ de la réorganisation graphique. * * * * Description : Met à jour l'affichage suite à un changement hiérarchique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void save_panel_nodes(void) { fprintf(stderr, "Passage avec %p\n", _nodes); return; void store_handle_position(panel_node *node, GGenConfig *config) { size_t i; for (i = 0; i < 0/*node->depth*/; i++) fprintf(stderr, " "); ///fprintf(stderr, "[%s] %s\n", node->path, node->simple ? "[+]" : ">>"); if (0/*!node->simple*/) { store_handle_position(node->first, config); store_handle_position(node->second, config); } } //get_main_configuration() store_handle_position(_nodes, NULL); fflush(NULL); } #endif /* ---------------------------------------------------------------------------------- */ /* INTERACTIONS GRAPHIQUES LIEES AUX PANNEAUX */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : item = composant à retirer de l'affichage. * * unused = adresse non utilisée ici. * * * * Description : Réagit à une demande de placement d'un panneau d'affichage. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void on_panel_item_dock_request(GPanelItem *item, void *unused) { const char *path; /* Chemin d'accès */ path = gtk_panel_item_get_path(item); /* Tout est à faire... */ if (_nodes == NULL) { _nodes = create_simple_panel_node_for_item(item, path); gtk_container_add(GTK_CONTAINER(_support), _nodes->widget); } else insert_item_as_panel_node(item, _nodes, path, 0); g_panel_item_set_dock_status(item, true); } /****************************************************************************** * * * Paramètres : item = composant à retirer de l'affichage. * * unused = adresse non utilisée ici. * * * * Description : Réagit à une demande de suppression d'un panneau d'affichage.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void on_panel_item_undock_request(GPanelItem *item, void *unused) { GtkWidget *station; /* Support courant */ panel_node *node; /* Noeud à supprimer */ gtk_dockable_decompose(GTK_DOCKABLE(item), &station); gtk_dock_station_remove_dockable(GTK_DOCK_STATION(station), GTK_DOCKABLE(item)); if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(station)) == 0) { node = find_node_for_station(_nodes, station); assert(node != NULL); delete_panel_node(node); } g_panel_item_set_dock_status(item, false); }