/* OpenIDA - Outil d'analyse de fichiers binaires * gtkgraphview.c - affichage de morceaux de code sous forme graphique * * Copyright (C) 2009-2012 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 "gtkgraphview.h" #include "gtkblockview.h" #include "gtkbufferview.h" #include "gtkviewpanel-int.h" #include "../graph/layout.h" /* Composant d'affichage sous forme graphique (instance) */ struct _GtkGraphView { GtkViewPanel parent; /* A laisser en premier */ GtkFixed *support; /* Support des vues en bloc */ GtkRequisition requisition; /* Espace requis d'affichage */ /* A garder ?? */ vmpa_t start; /* Début de la portion vue */ vmpa_t end; /* Fin de la portion affichée */ GtkViewPanel **childs; /* Liste des sous-blocs */ size_t childs_count; /* Taille de cette liste */ GtkLinkRenderer **links; /* Liste des liens graphiques */ size_t links_count; /* Nombre de ces liens */ }; /* Composant d'affichage sous forme graphique (classe) */ struct _GtkGraphViewClass { GtkViewPanelClass parent; /* A laisser en premier */ }; /* Initialise la classe générique des graphiques de code. */ static void gtk_graph_view_class_init(GtkGraphViewClass *); /* Initialise une instance d'afficheur de code en graphique. */ static void gtk_graph_view_init(GtkGraphView *); /* Fournit la taille de composant requise pour un plein rendu. */ static void gtk_graph_view_size_request(GtkWidget *, GtkRequisition *); /* S'adapte à la surface concédée par le composant parent. */ static void gtk_graph_view_size_allocate(GtkWidget *, GtkAllocation *); /* Met à jour l'affichage de la vue sous forme graphique. */ static gboolean gtk_graph_view_expose(GtkWidget *, GdkEventExpose *, GtkGraphView *); /* Réagit à la sélection externe d'une adresse. */ static void gtk_graph_view_define_main_address(GtkGraphView *, vmpa_t); /* Indique la position d'affichage d'une adresse donnée. */ static bool gtk_graph_view_get_address_coordinates(const GtkGraphView *, vmpa_t, gint *, gint *); /* Réagit à un défilement quelconque. */ static void gtk_graph_view_scroll(GtkGraphView *); /* Supprime tout contenu de l'afficheur de code en graphique. */ static void gtk_graph_view_reset(GtkGraphView *); /* Liste d'éléments du graphique à placer. */ static GtkViewPanel **gtk_graph_view_load_nodes(GtkGraphView *, GOpenidaBinary *, vmpa_t, vmpa_t); /* Détermine le type du composant d'affichage en graphique. */ G_DEFINE_TYPE(GtkGraphView, gtk_graph_view, GTK_TYPE_VIEW_PANEL) /****************************************************************************** * * * Paramètres : klass = classe GTK à initialiser. * * * * Description : Initialise la classe générique des graphiques de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_class_init(GtkGraphViewClass *klass) { GtkWidgetClass *widget_class; /* Classe version Widget */ widget_class = (GtkWidgetClass *)klass; widget_class->size_request = gtk_graph_view_size_request; widget_class->size_allocate = gtk_graph_view_size_allocate; } /****************************************************************************** * * * Paramètres : view = instance GTK à initialiser. * * * * Description : Initialise une instance d'afficheur de code en graphique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_init(GtkGraphView *view) { GtkViewPanel *viewpanel; /* Instance parente #1 */ //GtkBinView *binview; /* Instance parente #2 */ GdkColor white; /* Couleur de fond normale */ viewpanel = GTK_VIEW_PANEL(view); viewpanel->define = (define_address_fc)gtk_graph_view_define_main_address; viewpanel->get_coordinates = (get_addr_coordinates_fc)gtk_graph_view_get_address_coordinates; viewpanel->scroll = (scroll_fc)gtk_graph_view_scroll; //binview = GTK_BIN_VIEW(view); //binview->set_lines = (set_rendering_lines_fc)gtk_graph_view_set_rendering_lines; //binview->define_address = (define_main_address_fc)gtk_graph_view_define_main_address; //binview->get_coordinates = (get_addr_coordinates_fc)gtk_graph_view_get_address_coordinates; view->support = GTK_FIXED(gtk_fixed_new()); gtk_widget_set_has_window(GTK_WIDGET(view->support), TRUE); g_signal_connect(G_OBJECT(view->support), "expose-event", G_CALLBACK(gtk_graph_view_expose), view); gtk_widget_show(GTK_WIDGET(view->support)); gdk_color_white(gtk_widget_get_colormap(GTK_WIDGET(view->support)), &white); gtk_widget_modify_bg(GTK_WIDGET(view->support), GTK_STATE_NORMAL, &white); gtk_fixed_put(GTK_FIXED(view), GTK_WIDGET(view->support), 0, 0); //view->mutex = g_mutex_new(); //view->cond = g_cond_new(); } /****************************************************************************** * * * 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_graph_view_size_request(GtkWidget *widget, GtkRequisition *requisition) { gpointer fixed_class; /* Classe parente */ GtkGraphView *view; /* Autre vision du composant */ fixed_class = g_type_class_peek_parent(GTK_GRAPH_VIEW_GET_CLASS(widget)); fixed_class = g_type_class_peek_parent(fixed_class); GTK_WIDGET_CLASS(fixed_class)->size_request(widget, requisition); view = GTK_GRAPH_VIEW(widget); if (view->requisition.width == 0 && view->requisition.height == 0) view->requisition = *requisition; } /****************************************************************************** * * * 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_graph_view_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { gpointer fixed_class; /* Classe parente */ GtkViewPanel *panel; /* Autre version du composant */ GtkAllocation valloc; /* Surface utilisable */ gboolean changed; /* Changement de valeur ? */ /* Mise à jour GTK */ fixed_class = g_type_class_peek_parent(GTK_GRAPH_VIEW_GET_CLASS(widget)); fixed_class = g_type_class_peek_parent(fixed_class); GTK_WIDGET_CLASS(fixed_class)->size_allocate(widget, allocation); panel = GTK_VIEW_PANEL(widget); if (panel->hadjustment == NULL || panel->vadjustment == NULL) return; gtk_view_panel_compute_allocation(panel, &valloc); /* Défilement horizontal */ panel->hadjustment->page_size = valloc.width; panel->hadjustment->step_increment = valloc.width * 0.1; panel->hadjustment->page_increment = valloc.width * 0.9; panel->hadjustment->upper = MAX(GTK_GRAPH_VIEW(widget)->requisition.width, valloc.width); gtk_view_panel_reclamp_adjustment(panel->hadjustment, &changed); gtk_adjustment_changed(panel->hadjustment); if (changed) gtk_adjustment_value_changed(panel->hadjustment); /* Défilement vertical */ panel->vadjustment->page_size = valloc.height; panel->vadjustment->step_increment = valloc.width * 0.1; panel->vadjustment->page_increment = valloc.width * 0.9; panel->vadjustment->upper = MAX(GTK_GRAPH_VIEW(widget)->requisition.height, valloc.height); gtk_view_panel_reclamp_adjustment(panel->vadjustment, &changed); gtk_adjustment_changed(panel->vadjustment); if (changed) gtk_adjustment_value_changed(panel->vadjustment); } /****************************************************************************** * * * Paramètres : widget = composant GTK à redessiner. * * event = informations liées à l'événement. * * view = support maître à consulter. * * * * Description : Met à jour l'affichage de la vue sous forme graphique. * * * * Retour : FALSE pour poursuivre la propagation de l'événement. * * * * Remarques : - * * * ******************************************************************************/ static gboolean gtk_graph_view_expose(GtkWidget *widget, GdkEventExpose *event, GtkGraphView *view) { size_t i; /* Boucle de parcours */ for (i = 0; i < view->links_count; i++) gtk_link_renderer_draw(view->links[i], GDK_DRAWABLE(widget->window), GTK_VIEW_PANEL(view)->gc); return FALSE; } /****************************************************************************** * * * Paramètres : view = composant GTK à mettre à jour. * * addr = adresse sélectionnée de manière externe. * * * * Description : Réagit à la sélection externe d'une adresse. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_define_main_address(GtkGraphView *view, vmpa_t addr) { GExeFormat *format; /* Type de fichier chargé */ GBinRoutine **routines; /* Liste des routines trouvées */ size_t routines_count; /* Nombre de ces routines */ size_t i; /* Boucle de parcours */ vmpa_t start; /* Début d'une routine */ vmpa_t end; /* Fin d'une routine */ if (!(view->start <= addr && addr < view->end)) { gtk_graph_view_reset(view); format = g_openida_binary_get_format(GTK_VIEW_PANEL(view)->binary); routines = g_binary_format_get_routines(G_BIN_FORMAT(format), &routines_count); for (i = 0; i < routines_count; i++) { start = g_binary_routine_get_address(routines[i]); end = start + g_binary_routine_get_size(routines[i]); if (start <= addr && addr < end) { view->start = start; view->end = end; view->childs = gtk_graph_view_load_nodes(view, GTK_VIEW_PANEL(view)->binary, start, end); build_graph_view(view, view->childs, view->childs_count); break; } } } } /****************************************************************************** * * * 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_graph_view_get_address_coordinates(const GtkGraphView *view, vmpa_t addr, gint *x, gint *y) { return false; } /****************************************************************************** * * * Paramètres : view = composant GTK à mettre à jour. * * * * Description : Réagit à un défilement quelconque. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_scroll(GtkGraphView *view) { gtk_fixed_move(GTK_FIXED(view), GTK_WIDGET(view->support), -GTK_VIEW_PANEL(view)->hadjustment->value, -GTK_VIEW_PANEL(view)->vadjustment->value); } /****************************************************************************** * * * Paramètres : - * * * * Description : Crée un nouveau composant pour l'affichage en graphique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ GtkWidget *gtk_graph_view_new(void) { return g_object_new(GTK_TYPE_GRAPH_VIEW, NULL); } /****************************************************************************** * * * Paramètres : view = composant GTK à mettre à jour. * * widget = composant GTK à insérer. * * x = abscisse du point d'insertion. * * y = ordonnée du point d'insertion. * * * * Description : Place une vue sous forme de bloc dans le graphique. * * * * Retour : Plutôt que de redéfinir *toutes* les méthodes de * * GtkContainer, on étend ! * * * * Remarques : - * * * ******************************************************************************/ void gtk_graph_view_put(GtkGraphView *view, GtkWidget *widget, gint x, gint y) { gtk_fixed_put(view->support, widget, x, y); } /****************************************************************************** * * * Paramètres : view = composant GTK à mettre à jour. * * links = liens graphiques entre les blocs à intégrer. * * count = quantité de ces liens graphiques. * * * * Description : Définit les liens graphiques à présenter avec la vue. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void gtk_graph_view_attach_links(GtkGraphView *view, GtkLinkRenderer **links, size_t count) { view->links = links; view->links_count = count; } /****************************************************************************** * * * Paramètres : view = instance GTK à réinitialiser. * * * * Description : Supprime tout contenu de l'afficheur de code en graphique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_reset(GtkGraphView *view) { size_t i; /* Boucle de parcours */ view->requisition.width = 0; view->requisition.height = 0; view->start = VMPA_MAX; view->end = VMPA_MAX; for (i = 0; i < view->links_count; i++) gtk_object_destroy(GTK_OBJECT(view->links[i])); if (view->links_count > 0) { free(view->links); view->links = NULL; view->links_count = 0; } for (i = 0; i < view->childs_count; i++) gtk_widget_destroy(GTK_WIDGET(view->childs[i])); if (view->childs_count > 0) { free(view->childs); view->childs = NULL; view->childs_count = 0; } } /****************************************************************************** * * * Paramètres : view = composant d'affichage GTK à mettre à jour. * * binary = contenu binaire à l'origine des lignes. * * start = première adresse à traiter. * * end = première adresse hors cadre de l'opération. * * * * Description : Définit la liste complète des éléments du futur graphique. * * * * Retour : Liste d'éléments du graphique à placer. * * * * Remarques : - * * * ******************************************************************************/ static GtkViewPanel **gtk_graph_view_load_nodes(GtkGraphView *view, GOpenidaBinary *binary, vmpa_t start, vmpa_t end) { GtkViewPanel **result; /* Liste à retourner */ size_t *count; /* Nombre d'éléments créés. */ GArchInstruction *list; /* Liste des instructions */ GCodeBuffer *buffer; /* Tampon brut à découper */ bool *addr; /* Affichage des adresses ? */ bool *code; /* Affichage du binaire ? */ vmpa_t first; /* Début d'un groupe de lignes */ GArchInstruction *iter; /* Boucle de parcours */ vmpa_t last; /* Fin d'un groupe de lignes */ GBufferView *subview; /* Partie affichée du tampon */ result = NULL; count = &view->childs_count; *count = 0; list = g_openida_binary_get_instructions(binary); buffer = g_openida_binary_get_disassembled_buffer(binary); addr = g_openida_binary_display_addresses_in_text(binary); code = g_openida_binary_display_code_in_text(binary); first = start; last = first; for (iter = g_arch_instruction_find_by_address(list, start, true); iter != NULL; iter = g_arch_instruction_get_next_iter(list, iter, end)) { if (g_arch_instruction_has_sources(iter)) { result = (GtkViewPanel **)realloc(result, ++(*count) * sizeof(GtkViewPanel *)); result[*count - 1] = GTK_VIEW_PANEL(gtk_block_view_new()); gtk_widget_show(result[*count - 1]); gtk_view_panel_attach_binary(result[*count - 1], binary, addr, code); gtk_view_panel_show_border(result[*count - 1], true); subview = g_buffer_view_new(buffer); g_buffer_view_restrict(subview, first, last); gtk_buffer_view_attach_buffer(GTK_BUFFER_VIEW(result[*count - 1]), subview, addr, code); first = VMPA_MAX; } g_arch_instruction_get_location(iter, NULL, NULL, &last); if (first == VMPA_MAX) first = last; if (g_arch_instruction_has_destinations(iter)) { result = (GtkViewPanel **)realloc(result, ++(*count) * sizeof(GtkViewPanel *)); result[*count - 1] = GTK_VIEW_PANEL(gtk_block_view_new()); gtk_widget_show(result[*count - 1]); gtk_view_panel_attach_binary(result[*count - 1], binary, addr, code); gtk_view_panel_show_border(result[*count - 1], true); subview = g_buffer_view_new(buffer); g_buffer_view_restrict(subview, first, last); gtk_buffer_view_attach_buffer(GTK_BUFFER_VIEW(result[*count - 1]), subview, addr, code); first = VMPA_MAX; } } if (first != VMPA_MAX) { result = (GtkViewPanel **)realloc(result, ++(*count) * sizeof(GtkViewPanel *)); result[*count - 1] = GTK_VIEW_PANEL(gtk_block_view_new()); gtk_widget_show(result[*count - 1]); gtk_view_panel_attach_binary(result[*count - 1], binary, addr, code); gtk_view_panel_show_border(result[*count - 1], true); subview = g_buffer_view_new(buffer); g_buffer_view_restrict(subview, first, last); gtk_buffer_view_attach_buffer(GTK_BUFFER_VIEW(result[*count - 1]), subview, addr, code); } return result; } #if 0 #include "gtkbinview-int.h" #include "gtkblockview.h" #include "../format/format.h" #include "../graph/layout.h" #include /* Représentation de code binaire sous forme graphique (instace) */ struct _GtkGraphView { GtkBinView parent; /* A laisser en premier */ GtkFixed *support; /* Support des vues en bloc */ GtkRequisition requisition; /* Espace requis d'affichage */ vmpa_t start; /* Début de la portion vue */ vmpa_t end; /* Fin de la portion affichée */ GtkBinView **childs; /* Liste des sous-blocs */ size_t childs_count; /* Taille de cette liste */ size_t ready; /* Construction complète */ GMutex *mutex; /* Accès à la variable */ GCond *cond; /* Attente de changement */ GtkLinkRenderer **links; /* Liste des liens graphiques */ size_t links_count; /* Nombre de ces liens */ }; /* Représentation de code binaire sous forme graphique (classe) */ struct _GtkGraphViewClass { GtkBinViewClass parent; /* A laisser en premier */ }; /* Initialise la classe générique des graphiques de code. */ static void gtk_graph_view_class_init(GtkGraphViewClass *); /* Initialise une instance d'afficheur de code en graphique. */ static void gtk_graph_view_init(GtkGraphView *); /* Définit les lignes du graphique de représentation. */ static void gtk_graph_view_set_rendering_lines(GtkGraphView *, GRenderingLine *, GRenderingLine *); /* Réagit à la sélection externe d'une adresse. */ static void gtk_graph_view_define_main_address(GtkGraphView *, vmpa_t); /* Indique la position d'affichage d'une adresse donnée. */ static bool gtk_graph_view_get_address_coordinates(const GtkGraphView *, vmpa_t, gint *, gint *); /* Définit la liste complète des éléments du futur graphique. */ static GtkBinView **gtk_graph_view_load_nodes(GtkGraphView *, GOpenidaBinary *, GRenderingLine *, GRenderingLine *); /* Prend note de la fin d'une construction d'une visualisation. */ static void notify_graph_view(GtkBinView *, GtkGraphView *); /* Détermine le type du composant d'affichage en graphique. */ G_DEFINE_TYPE(GtkGraphView, gtk_graph_view, GTK_TYPE_BIN_VIEW) /****************************************************************************** * * * Paramètres : klass = classe GTK à initialiser. * * * * Description : Initialise la classe générique des graphiques de code. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_class_init(GtkGraphViewClass *klass) { GtkWidgetClass *widget_class; /* Classe version Widget */ widget_class = (GtkWidgetClass *)klass; widget_class->size_request = gtk_graph_view_size_request; widget_class->size_allocate = gtk_graph_view_size_allocate; } /****************************************************************************** * * * Paramètres : view = instance GTK à initialiser. * * * * Description : Initialise une instance d'afficheur de code en graphique. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_init(GtkGraphView *view) { GtkViewPanel *viewpanel; /* Instance parente #1 */ GtkBinView *binview; /* Instance parente #2 */ GdkColor white; /* Couleur de fond normale */ viewpanel = GTK_VIEW_PANEL(view); viewpanel->scroll = (scroll_fc)gtk_graph_view_scroll; binview = GTK_BIN_VIEW(view); binview->set_lines = (set_rendering_lines_fc)gtk_graph_view_set_rendering_lines; binview->define_address = (define_main_address_fc)gtk_graph_view_define_main_address; binview->get_coordinates = (get_addr_coordinates_fc)gtk_graph_view_get_address_coordinates; view->support = GTK_FIXED(gtk_fixed_new()); gtk_fixed_set_has_window(view->support, TRUE); g_signal_connect(G_OBJECT(view->support), "expose-event", G_CALLBACK(gtk_graph_view_expose), view); gtk_widget_show(GTK_WIDGET(view->support)); gdk_color_white(gtk_widget_get_colormap(GTK_WIDGET(view->support)), &white); gtk_widget_modify_bg(GTK_WIDGET(view->support), GTK_STATE_NORMAL, &white); gtk_fixed_put(GTK_FIXED(view), GTK_WIDGET(view->support), 0, 0); view->mutex = g_mutex_new(); view->cond = g_cond_new(); } /****************************************************************************** * * * 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 graphique de représentation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_set_rendering_lines(GtkGraphView *view, GRenderingLine *lines, GRenderingLine *last) { gtk_graph_view_reset(view); g_signal_emit_by_name(view, "lines-set"); } /****************************************************************************** * * * Paramètres : view = composant GTK à mettre à jour. * * addr = adresse sélectionnée de manière externe. * * * * Description : Réagit à la sélection externe d'une adresse. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void gtk_graph_view_define_main_address(GtkGraphView *view, vmpa_t addr) { GExeFormat *format; /* Type de fichier chargé */ GBinRoutine **routines; /* Liste des routines trouvées */ size_t routines_count; /* Nombre de ces routines */ size_t i; /* Boucle de parcours */ vmpa_t start; /* Début d'une routine */ vmpa_t end; /* Fin d'une routine */ GRenderingLine *first; /* Première ligne à traiter */ GRenderingLine *last; /* Dernière ligne à traiter */ if (!(view->start <= addr && addr < view->end)) { gtk_graph_view_reset(view); format = g_openida_binary_get_format(GTK_BIN_VIEW(view)->binary); routines = g_binary_format_get_routines(G_BIN_FORMAT(format), &routines_count); for (i = 0; i < routines_count; i++) { start = g_binary_routine_get_address(routines[i]); end = start + g_binary_routine_get_size(routines[i]); if (start <= addr && addr < end) { view->start = start; view->end = end; first = g_rendering_line_find_by_address(GTK_BIN_VIEW(view)->lines, GTK_BIN_VIEW(view)->last, start); last = g_rendering_line_find_by_address(GTK_BIN_VIEW(view)->lines, GTK_BIN_VIEW(view)->last, end - 1); view->childs = gtk_graph_view_load_nodes(view, GTK_BIN_VIEW(view)->binary, first, last); build_graph_view(view, view->childs, view->childs_count); break; } } } } /****************************************************************************** * * * 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_graph_view_get_address_coordinates(const GtkGraphView *view, vmpa_t addr, gint *x, gint *y) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ result = false; *x = 0; *y = 0; for (i = 0; i < view->childs_count && !result; i++) if (view->childs[i]->get_coordinates(view->childs[i], addr, x, y)) { *x += GTK_WIDGET(view->childs[i])->allocation.x; *y += GTK_WIDGET(view->childs[i])->allocation.y; result = true; } return result; } /****************************************************************************** * * * Paramètres : view = composant d'affichage GTK à mettre à jour. * * binary = contenu binaire à l'origine des lignes. * * first = première ligne à analyser. * * last = dernière ligne à analyser. * * * * Description : Définit la liste complète des éléments du futur graphique. * * * * Retour : Liste d'éléments du graphique à placer. * * * * Remarques : - * * * ******************************************************************************/ static GtkBinView **gtk_graph_view_load_nodes(GtkGraphView *view, GOpenidaBinary *binary, GRenderingLine *first, GRenderingLine *last) { #if 0 GtkBinView **result; /* Liste à retourner */ size_t *count; /* Nombre d'éléments créés. */ GRenderingLine *begin; /* Début d'un groupe de lignes */ GRenderingLine *end; /* Fin d'un groupe de lignes */ GRenderingLine *iter; /* Boucle de parcours */ result = NULL; view->ready = 0; count = &view->childs_count; *count = 0; /** * Comme la fonction est appelée depuis un événement et utilise des threads et GTK, * on doit lever temporairement le verrou GDK. */ gdk_flush (); gdk_threads_leave(); begin = NULL; for (iter = first; iter != NULL; iter = g_rendering_line_get_next_iter(first, iter, last)) { if (begin != NULL && g_rendering_line_has_sources(iter)) { result = (GtkBinView **)realloc(result, ++(*count) * sizeof(GtkBinView *)); result[*count - 1] = GTK_BIN_VIEW(gtk_block_view_new(MRD_GRAPH)); g_signal_connect(result[*count - 1], "lines-set", G_CALLBACK(notify_graph_view), view); gtk_bin_view_show_border(result[*count - 1], true); gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end); begin = NULL; } if (begin == NULL) begin = iter; end = iter; if (g_rendering_line_has_destinations(iter)) { result = (GtkBinView **)realloc(result, ++(*count) * sizeof(GtkBinView *)); result[*count - 1] = GTK_BIN_VIEW(gtk_block_view_new(MRD_GRAPH)); g_signal_connect(result[*count - 1], "lines-set", G_CALLBACK(notify_graph_view), view); gtk_bin_view_show_border(result[*count - 1], true); gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end); begin = NULL; } } if (begin != NULL) { result = (GtkBinView **)realloc(result, ++(*count) * sizeof(GtkBinView *)); result[*count - 1] = GTK_BIN_VIEW(gtk_block_view_new(MRD_GRAPH)); g_signal_connect(result[*count - 1], "lines-set", G_CALLBACK(notify_graph_view), view); gtk_bin_view_show_border(result[*count - 1], true); gtk_bin_view_set_rendering_lines(result[*count - 1], binary, begin, end); } /* Attente de la fin de construction */ g_mutex_lock(view->mutex); while (view->ready < *count) g_cond_wait(view->cond, view->mutex); g_mutex_unlock(view->mutex); gdk_threads_enter(); return result; #endif return NULL; } /****************************************************************************** * * * Paramètres : view = composant d'affichage prêt à utilisation. * * parent = composant d'affichage supérieur. * * * * Description : Prend note de la fin d'une construction d'une visualisation. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void notify_graph_view(GtkBinView *view, GtkGraphView *parent) { g_mutex_lock(parent->mutex); parent->ready++; g_cond_signal(parent->cond); g_mutex_unlock(parent->mutex); g_signal_handlers_disconnect_by_func(view, G_CALLBACK(notify_graph_view), parent); gtk_widget_show(GTK_WIDGET(view)); } #endif