diff options
| author | Cyrille Bagard <nocbos@gmail.com> | 2019-02-15 22:58:40 (GMT) | 
|---|---|---|
| committer | Cyrille Bagard <nocbos@gmail.com> | 2019-02-15 22:58:40 (GMT) | 
| commit | 16242be5838a77690946cbb2f30b2e89f2df0b94 (patch) | |
| tree | d3c2b2725f41f2a0d45ae7f32e2ab9cb1886b230 | |
| parent | 5ed40f0afbd58fbfdf05be7b2a10ab8d0819759f (diff) | |
Displayed tooltips for graph view edges.
| -rw-r--r-- | src/analysis/block-int.h | 4 | ||||
| -rw-r--r-- | src/analysis/block.c | 26 | ||||
| -rw-r--r-- | src/analysis/block.h | 3 | ||||
| -rw-r--r-- | src/analysis/disass/block.c | 349 | ||||
| -rw-r--r-- | src/analysis/routine.c | 2 | ||||
| -rw-r--r-- | src/glibext/gbuffercache.c | 12 | ||||
| -rw-r--r-- | src/gtkext/graph/cluster.c | 25 | ||||
| -rw-r--r-- | src/gtkext/graph/edge.c | 39 | ||||
| -rw-r--r-- | src/gtkext/graph/edge.h | 36 | ||||
| -rw-r--r-- | src/gtkext/gtkgraphdisplay.c | 71 | 
10 files changed, 539 insertions, 28 deletions
diff --git a/src/analysis/block-int.h b/src/analysis/block-int.h index 6759e7b..9eb99d7 100644 --- a/src/analysis/block-int.h +++ b/src/analysis/block-int.h @@ -47,6 +47,9 @@ typedef block_link_t * (* block_get_links_fc) (const GCodeBlock *, const GBlockL  /* Fournit la représentation graphique d'un bloc de code. */  typedef GBufferView * (* block_build_view_fc) (const GCodeBlock *, segcnt_list *); +/* Construit un ensemble d'indications pour bloc. */ +typedef char *(* block_build_tooltip_fc) (const GCodeBlock *); +  /* Description d'un bloc de code (instance) */  struct _GCodeBlock @@ -75,6 +78,7 @@ struct _GCodeBlockClass      block_get_links_fc get_src;             /* Obtention des origines      */      block_get_links_fc get_dest;            /* Obtention des destinations  */      block_build_view_fc build;              /* Construction d'une vue      */ +    block_build_tooltip_fc build_tooltip;   /* Construction d'une bulle    */  }; diff --git a/src/analysis/block.c b/src/analysis/block.c index a7172af..85c8017 100644 --- a/src/analysis/block.c +++ b/src/analysis/block.c @@ -357,6 +357,32 @@ GBufferView *g_code_block_get_view(GCodeBlock *block, segcnt_list *highlighted)  } +/****************************************************************************** +*                                                                             * +*  Paramètres  : block = bloc de code à consulter.                            * +*                                                                             * +*  Description : Construit un ensemble d'indications pour bloc.               * +*                                                                             * +*  Retour      : Informations à présenter sous forme de bulle d'aide.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +char *g_code_block_build_tooltip(const GCodeBlock *block) +{ +    char *result;                           /* Description à retourner     */ +    GCodeBlockClass *class;                 /* Classe des blocs de code    */ + +    class = G_CODE_BLOCK_GET_CLASS(block); + +    result = class->build_tooltip(block); + +    return result; + +} + +  /* ---------------------------------------------------------------------------------- */  /*                     DEFINITION DE LIAISONS ENTRE BLOCS DE CODE                     */ diff --git a/src/analysis/block.h b/src/analysis/block.h index 71092b2..bb3db3e 100644 --- a/src/analysis/block.h +++ b/src/analysis/block.h @@ -77,6 +77,9 @@ void g_code_block_set_rank(GCodeBlock *, size_t);  /* Fournit la représentation graphique d'un bloc de code. */  GBufferView *g_code_block_get_view(GCodeBlock *, segcnt_list *); +/* Construit un ensemble d'indications pour bloc. */ +char *g_code_block_build_tooltip(const GCodeBlock *); +  /* ------------------- DEFINITION DE LIAISONS ENTRE BLOCS DE CODE ------------------- */ diff --git a/src/analysis/disass/block.c b/src/analysis/disass/block.c index 9fce202..3077dc2 100644 --- a/src/analysis/disass/block.c +++ b/src/analysis/disass/block.c @@ -28,7 +28,13 @@  #include <malloc.h> +#include <i18n.h> + +  #include "../block-int.h" +#include "../../arch/raw.h" +#include "../../common/extstr.h" +#include "../../core/params.h"  #include "../../glibext/gbinarycursor.h" @@ -84,6 +90,9 @@ static block_link_t *g_basic_block_get_destinations(const GBasicBlock *, const G  /* Fournit la représentation graphique d'un bloc de code. */  static GBufferView *g_basic_block_build_view(const GBasicBlock *, segcnt_list *); +/* Construit un ensemble d'indications pour bloc. */ +static char *g_basic_block_build_tooltip(const GBasicBlock *); +  /* ---------------------------------------------------------------------------------- */ @@ -124,6 +133,7 @@ static void g_basic_block_class_init(GBasicBlockClass *class)      block->get_src = (block_get_links_fc)g_basic_block_get_sources;      block->get_dest = (block_get_links_fc)g_basic_block_get_destinations;      block->build = (block_build_view_fc)g_basic_block_build_view; +    block->build_tooltip = (block_build_tooltip_fc)g_basic_block_build_tooltip;  } @@ -499,6 +509,345 @@ static GBufferView *g_basic_block_build_view(const GBasicBlock *block, segcnt_li  /******************************************************************************  *                                                                             * +*  Paramètres  : block = bloc de code à consulter.                            * +*                                                                             * +*  Description : Construit un ensemble d'indications pour bloc.               * +*                                                                             * +*  Retour      : Informations à présenter sous forme de bulle d'aide.         * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static char *g_basic_block_build_tooltip(const GBasicBlock *block) +{ +    char *result;                           /* Description à retourner     */ +    const mrange_t *brange[2];              /* Emplacements d'instruction  */ +    phys_t diff;                            /* Espacement entre adresses   */ +    mrange_t range;                         /* Couverture du bloc          */ +    char *name;                             /* Désignation de l'entête     */ +    GBinFormat *format;                     /* Format associé au binaire   */ +    GBinSymbol *symbol;                     /* Symbole lié au bloc         */ +    char *label;                            /* Etiquette à insérer         */ +    GBufferCache *cache;                    /* Tampon d'impression colorée */ +    GBufferLine *line;                      /* Ligne au contenu coloré     */ +    VMPA_BUFFER(loc);                       /* Indication de position      */ +    GGenConfig *config;                     /* Configuration à consulter   */ +    unsigned int max_calls;                 /* Quantité d'appels à afficher*/ +    unsigned int max_strings;               /* Nbre de chaînes à afficher  */ +    unsigned int ins_count;                 /* Quantité d'instructions     */ +    unsigned int call_count;                /* Quantité d'appels           */ +    char *call_info;                        /* Détails des appels          */ +    unsigned int string_count;              /* Quantité de chaînes         */ +    char *string_info;                      /* Détails des chaînes         */ +    GArchProcessor *proc;                   /* Architecture utilisée       */ +    instr_iter_t *iter;                     /* Parcours local d'adresses   */ +    GArchInstruction *instr;                /* Instruction correspondante  */ +    size_t dcount;                          /* Nombre de liens de dest.    */ +    size_t i;                               /* Boucle de parcours          */ +    const instr_link_t *dest;               /* Instr. visée par une autre  */ +    const mrange_t *irange;                 /* Emplacement d'instruction   */ +    GLineCursor *cursor;                    /* Emplacement dans un tampon  */ +    size_t index;                           /* Indice de ligne à traiter   */ +    char *info;                             /* Ligne d'information créée   */ + +    /* Définition de la couverture du bloc */ + +    brange[0] = g_arch_instruction_get_range(block->first); +    brange[1] = g_arch_instruction_get_range(block->last); + +    diff = compute_vmpa_diff(get_mrange_addr(brange[0]), get_mrange_addr(brange[1])); + +    init_mrange(&range, get_mrange_addr(brange[0]), diff + get_mrange_length(brange[1])); + +    /* Recherche d'un symbole de départ */ + +    name = NULL; + +    format = G_BIN_FORMAT(g_loaded_binary_get_format(block->binary)); + +    if (g_binary_format_find_symbol_at(format, get_mrange_addr(brange[0]), &symbol)) +    { +        label = g_binary_symbol_get_label(symbol); + +        if (label != NULL) +        { +            cache = g_buffer_cache_new(NULL); +            g_buffer_cache_append(cache, G_LINE_GENERATOR(symbol), BLF_NONE); + +            line = g_buffer_cache_find_line_by_index(cache, 0); +            name = g_buffer_line_get_text(line, BLC_ASSEMBLY_LABEL, BLC_COUNT, true); +            g_object_unref(G_OBJECT(line)); + +            g_object_unref(G_OBJECT(cache)); + +            /* Suppression de la fin de l'étiquette... */ +            name = strrpl(name, ":", ""); + +        } + +        else +            name = NULL; + +        free(label); + +        g_object_unref(G_OBJECT(symbol)); + +    } + +    if (name == NULL) +    { +        proc = g_loaded_binary_get_processor(block->binary); + +        if (g_arch_processor_has_virtual_space(proc) && has_virt_addr(get_mrange_addr(&range))) +            vmpa2_virt_to_string(get_mrange_addr(&range), MDS_UNDEFINED, loc, NULL); +        else +            vmpa2_phys_to_string(get_mrange_addr(&range), MDS_UNDEFINED, loc, NULL); + +        name = strdup(loc); + +        g_object_unref(G_OBJECT(proc)); + +    } + +    result = name; + +    /* Lecture des paramètres de configuration */ + +    config = get_main_configuration(); + +    if (!g_generic_config_get_value(config, MPK_TOOLTIP_MAX_CALLS, &max_calls)) +        max_calls = 0; + +    max_calls++; + +    if (!g_generic_config_get_value(config, MPK_TOOLTIP_MAX_STRINGS, &max_strings)) +        max_strings = 0; + +    max_strings++; + +    /* Parcours des instructions */ + +    ins_count = 0; + +    call_count = 0; +    call_info = NULL; + +    string_count = 0; +    string_info = NULL; + +    proc = g_loaded_binary_get_processor(block->binary); +    cache = g_loaded_binary_get_disassembled_cache(block->binary); + +    iter = g_arch_processor_get_iter_from_address(proc, get_mrange_addr(&range)); +    if (iter == NULL) goto no_iter; + +    restrict_instruction_iterator(iter, &range); + +    for (instr = get_instruction_iterator_current(iter); +         instr != NULL; +         instr = get_instruction_iterator_next(iter)) +    { +        ins_count ++; + +        /* Appels ou références ? */ + +        g_arch_instruction_lock_dest(instr); +        dcount = g_arch_instruction_count_destinations(instr); + +        for (i = 0; i < dcount; i++) +        { +            dest = g_arch_instruction_get_destination(instr, i); + +            switch (dest->type) +            { +                case ILT_CALL: + +                    call_count++; + +                    if (call_count > max_calls) +                        goto next_dest; + +                    if (call_count == max_calls) +                    { +                        call_info = stradd(call_info, "\n    ..."); +                        goto next_dest; +                    } + +                    irange = g_arch_instruction_get_range(instr); + +                    cursor = g_binary_cursor_new(); +                    g_binary_cursor_update(G_BINARY_CURSOR(cursor), get_mrange_addr(irange)); + +                    index = g_buffer_cache_find_index_by_cursor(cache, cursor, true); + +                    g_object_unref(G_OBJECT(cursor)); + +                    index = g_buffer_cache_look_for_flag(cache, index, BLF_HAS_CODE); + +                    line = g_buffer_cache_find_line_by_index(cache, index); + +                    if (line != NULL) +                    { +                        info = g_buffer_line_get_text(line, BLC_ASSEMBLY_HEAD, BLC_COUNT, true); +                        g_object_unref(G_OBJECT(line)); +                    } + +                    else +                        info = NULL; + +                    if (call_info != NULL) +                        call_info = stradd(call_info, "\n"); + +                    if (info != NULL) +                    { +                        call_info = stradd(call_info, "    - "); +                        call_info = stradd(call_info, info); +                        free(info); +                    } + +                    else +                        call_info = stradd(call_info, "    - ???"); + +                    break; + +                case ILT_REF: + +                    if (!G_IS_RAW_INSTRUCTION(dest->linked)) +                        goto next_dest; + +                    if (!g_raw_instruction_is_string(G_RAW_INSTRUCTION(dest->linked))) +                        goto next_dest; + +                    string_count++; + +                    if (string_count > max_strings) +                        goto next_dest; + +                    if (string_count == max_strings) +                    { +                        string_info = stradd(string_info, "\n    ..."); +                        goto next_dest; +                    } + +                    irange = g_arch_instruction_get_range(dest->linked); + +                    cursor = g_binary_cursor_new(); +                    g_binary_cursor_update(G_BINARY_CURSOR(cursor), get_mrange_addr(irange)); + +                    index = g_buffer_cache_find_index_by_cursor(cache, cursor, true); + +                    g_object_unref(G_OBJECT(cursor)); + +                    index = g_buffer_cache_look_for_flag(cache, index, BLF_HAS_CODE); + +                    line = g_buffer_cache_find_line_by_index(cache, index); + +                    if (line != NULL) +                    { +                        info = g_buffer_line_get_text(line, BLC_ASSEMBLY, BLC_COUNT, true); +                        g_object_unref(G_OBJECT(line)); +                    } + +                    else +                        info = NULL; + +                    if (string_info != NULL) +                        string_info = stradd(string_info, "\n"); + +                    if (info != NULL) +                    { +                        string_info = stradd(string_info, "    - "); +                        string_info = stradd(string_info, info); +                        free(info); +                    } + +                    else +                        string_info = stradd(string_info, "    - ???"); + +                    break; + +                default: +                    break; + +            } + + next_dest: + +            unref_instr_link(dest); + +        } + +        g_arch_instruction_unlock_dest(instr); + +        g_object_unref(G_OBJECT(instr)); + +    } + +    delete_instruction_iterator(iter); + + no_iter: + +    g_object_unref(G_OBJECT(cache)); +    g_object_unref(G_OBJECT(proc)); + +    /* Construction du résumé */ + +    result = stradd(result, "\n"); + +    if (ins_count > 1) +        asprintf(&info, " - %u %s", ins_count, _("instructions")); +    else +        asprintf(&info, " - %u %s", ins_count, _("instruction")); + +    result = stradd(result, info); +    free(info); + +    result = stradd(result, "\n"); + +    if (call_count > 1) +        asprintf(&info, " - %u %s", call_count, _("calls:")); +    else if (call_count == 1) +        asprintf(&info, " - 1 %s", _("call:")); +    else +        asprintf(&info, " - 0 %s", _("call")); + +    if (call_count > 0) +    { +        info = stradd(info, "\n"); +        info = stradd(info, call_info); +        free(call_info); +    } + +    info = stradd(info, "\n"); + +    result = stradd(result, info); +    free(info); + +    if (string_count > 1) +        asprintf(&info, " - %u %s", string_count, _("strings:")); +    else if (string_count == 1) +        asprintf(&info, " - 1 %s", _("string:")); +    else +        asprintf(&info, " - 0 %s", _("string")); + +    if (string_count > 0) +    { +        info = stradd(info, "\n"); +        info = stradd(info, call_info); +        free(call_info); +    } + +    result = stradd(result, info); +    free(info); + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : block = bloc d'instructions à consulter.                     *  *                first = instruction de départ du bloc. [OUT]                 *  *                last  = dernière instruction du bloc. [OUT]                  * diff --git a/src/analysis/routine.c b/src/analysis/routine.c index d206e5e..20b5162 100644 --- a/src/analysis/routine.c +++ b/src/analysis/routine.c @@ -1134,7 +1134,7 @@ char *g_binary_routine_build_tooltip(const GBinRoutine *routine, const GLoadedBi      {          ins_count ++; -        /* Appels ? */ +        /* Appels ou références ? */          g_arch_instruction_lock_dest(instr);          dcount = g_arch_instruction_count_destinations(instr); diff --git a/src/glibext/gbuffercache.c b/src/glibext/gbuffercache.c index e4ddf06..8d02dd8 100644 --- a/src/glibext/gbuffercache.c +++ b/src/glibext/gbuffercache.c @@ -609,26 +609,24 @@ static void g_buffer_cache_dispose(GBufferCache *cache)      cache_info *info;                       /* Accès direct à une ligne    */      size_t j;                               /* Boucle de parcours #2       */ -    if (cache->content != NULL) -        g_object_unref(G_OBJECT(cache->content)); +    g_clear_object(&cache->content);      for (i = 0; i < cache->used; i++)      {          info = &cache->lines[i];          if (info->count == 1) -            g_object_unref(G_OBJECT(info->generator.instance)); +            g_clear_object(&info->generator.instance);          else              for (j = 0; j < info->count; j++) -                g_object_unref(G_OBJECT(info->generators[j].instance)); +                g_clear_object(&info->generators[j].instance); -        if (info->line) -            g_object_unref(G_OBJECT(info->line)); +        g_clear_object(&info->line);      } -    g_object_unref(G_OBJECT(cache->tracker)); +    g_clear_object(&cache->tracker);      G_OBJECT_CLASS(g_buffer_cache_parent_class)->dispose(G_OBJECT(cache)); diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c index c4deeaa..765bbac 100644 --- a/src/gtkext/graph/cluster.c +++ b/src/gtkext/graph/cluster.c @@ -460,6 +460,8 @@ static gint compute_leaving_link_position(const leaving_link_t *link)  static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLinkType type, leaving_link_t *other)  {      incoming_link_t *result;                /* Structure à retourner       */ +    GCodeBlock *src;                        /* Bloc d'origine du lien      */ +    GCodeBlock *dst;                        /* Bloc de destination du lien */      result = malloc(sizeof(incoming_link_t)); @@ -467,14 +469,23 @@ static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLi      result->type = type; +    src = other->owner->block; +    dst = owner->block; +      if (type == ILT_JUMP_IF_TRUE) -        result->edge = g_graph_edge_new_true(&other->start[0], &other->start[1], &result->end[0], &result->end[1]); +        result->edge = g_graph_edge_new_true(src, dst, +                                             &other->start[0], &other->start[1], +                                             &result->end[0], &result->end[1]);      else if (type == ILT_JUMP_IF_FALSE) -        result->edge = g_graph_edge_new_false(&other->start[0], &other->start[1], &result->end[0], &result->end[1]); +        result->edge = g_graph_edge_new_false(src, dst, +                                              &other->start[0], &other->start[1], +                                              &result->end[0], &result->end[1]);      else -        result->edge = g_graph_edge_new(&other->start[0], &other->start[1], &result->end[0], &result->end[1]); +        result->edge = g_graph_edge_new(src, dst, +                                        &other->start[0], &other->start[1], +                                        &result->end[0], &result->end[1]);      result->other = other; @@ -499,6 +510,8 @@ static incoming_link_t *create_incoming_link(GGraphCluster *owner, InstructionLi  static incoming_link_t *create_incoming_loop_link(GGraphCluster *owner, const GdkPoint *midpts, leaving_link_t *other)  {      incoming_link_t *result;                /* Structure à retourner       */ +    GCodeBlock *src;                        /* Bloc d'origine du lien      */ +    GCodeBlock *dst;                        /* Bloc de destination du lien */      result = malloc(sizeof(incoming_link_t)); @@ -506,7 +519,11 @@ static incoming_link_t *create_incoming_loop_link(GGraphCluster *owner, const Gd      result->type = ILT_LOOP; -    result->edge = g_graph_edge_new_loop(&other->start[0], &other->start[1], +    src = other->owner->block; +    dst = owner->block; + +    result->edge = g_graph_edge_new_loop(src, dst, +                                         &other->start[0], &other->start[1],                                           &midpts[0], &midpts[1],                                           &result->end[0], &result->end[1]); diff --git a/src/gtkext/graph/edge.c b/src/gtkext/graph/edge.c index 9a2f848..20f1988 100644 --- a/src/gtkext/graph/edge.c +++ b/src/gtkext/graph/edge.c @@ -36,6 +36,9 @@ struct _GGraphEdge  {      GObject parent;                         /* A laisser en premier        */ +    GCodeBlock *src;                        /* Bloc d'origine du lien      */ +    GCodeBlock *dst;                        /* Bloc de destination du lien */ +      EdgeColor color;                        /* Couleur du rendu            */      union @@ -137,6 +140,9 @@ static void g_graph_edge_init(GGraphEdge *edge)  static void g_graph_edge_dispose(GGraphEdge *edge)  { +    g_clear_object(&edge->src); +    g_clear_object(&edge->dst); +      G_OBJECT_CLASS(g_graph_edge_parent_class)->dispose(G_OBJECT(edge));  } @@ -177,12 +183,18 @@ static void g_graph_edge_finalize(GGraphEdge *edge)  *                                                                             *  ******************************************************************************/ -GGraphEdge *_g_graph_edge_new(const GdkPoint **templates, size_t count, EdgeColor color) +GGraphEdge *_g_graph_edge_new(GCodeBlock *src, GCodeBlock *dst, const GdkPoint **templates, size_t count, EdgeColor color)  {      GGraphEdge *result;                     /* Structure à retourner       */      result = g_object_new(G_TYPE_GRAPH_EDGE, NULL); +    result->src = src; +    result->dst = dst; + +    g_object_ref(G_OBJECT(src)); +    g_object_ref(G_OBJECT(dst)); +      result->color = color;      assert(count == 4 || count == 6); @@ -200,6 +212,31 @@ GGraphEdge *_g_graph_edge_new(const GdkPoint **templates, size_t count, EdgeColo  /******************************************************************************  *                                                                             *  *  Paramètres  : edge = ligne de rendu à consulter.                           * +*                src  = bloc d'origine du lien. [OUT]                         * +*                dst  = bloc de destination du lien. [OUT]                    * +*                                                                             * +*  Description : Fournit les deux blocs aux extrémités d'un lien.             * +*                                                                             * +*  Retour      : -                                                            * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +void g_graph_edge_get_boundaries(const GGraphEdge *edge, GCodeBlock **src, GCodeBlock **dst) +{ +    *src = edge->src; +    *dst = edge->dst; + +    g_object_ref(G_OBJECT(*src)); +    g_object_ref(G_OBJECT(*dst)); + +} + + +/****************************************************************************** +*                                                                             * +*  Paramètres  : edge = ligne de rendu à consulter.                           *  *                x1   = abscisse du point de départ de la ligne. [OUT]        *  *                x2   = abscisse du point d'arrivée de la ligne. [OUT]        *  *                                                                             * diff --git a/src/gtkext/graph/edge.h b/src/gtkext/graph/edge.h index e905685..ec33544 100644 --- a/src/gtkext/graph/edge.h +++ b/src/gtkext/graph/edge.h @@ -30,13 +30,16 @@  #include <gtk/gtk.h> +#include "../../analysis/disass/block.h" -#define G_TYPE_GRAPH_EDGE               g_graph_edge_get_type() -#define G_GRAPH_EDGE(obj)               (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_GRAPH_EDGE, GGraphEdge)) -#define G_IS_GRAPH_EDGE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_GRAPH_EDGE)) -#define G_GRAPH_EDGE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_GRAPH_EDGE, GGraphEdgeClass)) -#define G_IS_GRAPH_EDGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_GRAPH_EDGE)) -#define G_GRAPH_EDGE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_GRAPH_EDGE, GGraphEdgeClass)) + + +#define G_TYPE_GRAPH_EDGE            g_graph_edge_get_type() +#define G_GRAPH_EDGE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_GRAPH_EDGE, GGraphEdge)) +#define G_IS_GRAPH_EDGE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_GRAPH_EDGE)) +#define G_GRAPH_EDGE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_GRAPH_EDGE, GGraphEdgeClass)) +#define G_IS_GRAPH_EDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_GRAPH_EDGE)) +#define G_GRAPH_EDGE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_GRAPH_EDGE, GGraphEdgeClass))  /* Lien graphique entre deux noeuds graphiques (instance) */ @@ -68,19 +71,22 @@ typedef enum _EdgeColor  GType g_graph_edge_get_type(void);  /* Etablit un lien graphique entre deux noeuds graphiques. */ -GGraphEdge *_g_graph_edge_new(const GdkPoint **, size_t, EdgeColor); +GGraphEdge *_g_graph_edge_new(GCodeBlock *, GCodeBlock *, const GdkPoint **, size_t, EdgeColor); + +#define g_graph_edge_new(src, dst, pts0, pts1, pte0, pte1) \ +    _g_graph_edge_new(src, dst, (const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_DEFAULT) -#define g_graph_edge_new(pts0, pts1, pte0, pte1) \ -    _g_graph_edge_new((const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_DEFAULT) +#define g_graph_edge_new_true(src, dst, pts0, pts1, pte0, pte1) \ +    _g_graph_edge_new(src, dst, (const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_GREEN) -#define g_graph_edge_new_true(pts0, pts1, pte0, pte1) \ -    _g_graph_edge_new((const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_GREEN) +#define g_graph_edge_new_false(src, dst, pts0, pts1, pte0, pte1) \ +    _g_graph_edge_new(src, dst, (const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_RED) -#define g_graph_edge_new_false(pts0, pts1, pte0, pte1) \ -    _g_graph_edge_new((const GdkPoint *[]) { pts0, pts1, pte0, pte1 }, 4, EGC_RED) +#define g_graph_edge_new_loop(src, dst, pts0, pts1, ptl0, ptl1, pte0, pte1) \ +    _g_graph_edge_new(src, dst, (const GdkPoint *[]) { pts0, pts1, ptl0, ptl1, pte0, pte1 }, 6, EGC_BLUE) -#define g_graph_edge_new_loop(pts0, pts1, ptl0, ptl1, pte0, pte1) \ -    _g_graph_edge_new((const GdkPoint *[]) { pts0, pts1, ptl0, ptl1, pte0, pte1 }, 6, EGC_BLUE) +/* Fournit les deux blocs aux extrémités d'un lien. */ +void g_graph_edge_get_boundaries(const GGraphEdge *, GCodeBlock **, GCodeBlock **);  /* Fournit les abscisses des points extrèmes de la ligne. */  void g_graph_edge_get_x_borders(const GGraphEdge *, gint *, gint *); diff --git a/src/gtkext/gtkgraphdisplay.c b/src/gtkext/gtkgraphdisplay.c index 0915f3a..0865e04 100644 --- a/src/gtkext/gtkgraphdisplay.c +++ b/src/gtkext/gtkgraphdisplay.c @@ -27,11 +27,15 @@  #include <assert.h> +#include <i18n.h> + +  #include "gtkblockdisplay.h"  #include "gtkbufferdisplay.h"  #include "gtkdisplaypanel-int.h"  #include "graph/cluster.h"  #include "../analysis/routine.h" +#include "../common/extstr.h"  #include "../format/format.h"  #include "../glibext/gbinarycursor.h"  #include "../glibext/gloadedpanel.h" @@ -115,6 +119,9 @@ static gboolean gtk_graph_display_button_release(GtkWidget *, GdkEventButton *,  /* Assure la suivi des déplacements de souris sur le composant. */  static gboolean gtk_graph_display_motion_notify(GtkWidget *, GdkEventMotion *, GtkGraphDisplay *); +/* Prépare l'affichage d'une astuce. */ +static gboolean gtk_graph_display_query_tooltip(GtkWidget *, gint, gint, gboolean, GtkTooltip *, GtkGraphDisplay *); +  /* Ajuste au besoin la zone affichée pour un curseur. */  static void gtk_graph_display_prepare_for_cursor(GtkGraphDisplay *, const GLineCursor *); @@ -213,6 +220,10 @@ static void gtk_graph_display_init(GtkGraphDisplay *display)                        G_CALLBACK(gtk_graph_display_button_release), display);      g_signal_connect(G_OBJECT(display->support), "motion-notify-event",                        G_CALLBACK(gtk_graph_display_motion_notify), display); +    g_signal_connect(G_OBJECT(display->support), "query-tooltip", +                      G_CALLBACK(gtk_graph_display_query_tooltip), display); + +    g_object_set(G_OBJECT(display->support), "has-tooltip", TRUE, NULL);      gtk_widget_add_events(display->support,                            GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK @@ -649,6 +660,66 @@ static gboolean gtk_graph_display_motion_notify(GtkWidget *widget, GdkEventMotio  /******************************************************************************  *                                                                             * +*  Paramètres  : widget   = composant GTK visé par l'opération.               * +*                x        = abscisse de la position du message.               * +*                y        = ordonnée de la position du message.               * +*                keyboard = indique une demande suite à obtiention du focus.  * +*                tooltip  = astuce à compléter. [OUT]                         * +*                display  = support maître à consulter.                       * +*                                                                             * +*  Description : Prépare l'affichage d'une astuce.                            * +*                                                                             * +*  Retour      : TRUE pour un affichage validé, FALSE sinon.                  * +*                                                                             * +*  Remarques   : -                                                            * +*                                                                             * +******************************************************************************/ + +static gboolean gtk_graph_display_query_tooltip(GtkWidget *widget, gint x, gint y, gboolean keyboard, GtkTooltip *tooltip, GtkGraphDisplay *display) +{ +    gboolean result;                        /* Bilan à retourner           */ +    GCodeBlock *src;                        /* Bloc d'origine du lien      */ +    GCodeBlock *dst;                        /* Bloc de destination du lien */ +    char *info;                             /* Information à faire paraître*/ +    char *desc;                             /* Description d'un bloc       */ + +    result = FALSE; + +    if (display->hl_edge_index < display->edges_count) +    { +        g_graph_edge_get_boundaries(display->edges[display->hl_edge_index], &src, &dst); + +        info = stradd(NULL, _("<b>Source:</b> ")); + +        desc = g_code_block_build_tooltip(src); +        info = stradd(info, desc); +        free(desc); + +        info = stradd(info, "\n\n"); + +        info = stradd(info, _("<b>Destination:</b> ")); + +        desc = g_code_block_build_tooltip(dst); +        info = stradd(info, desc); +        free(desc); + +        gtk_tooltip_set_markup(tooltip, info); +        free(info); + +        g_object_unref(G_OBJECT(src)); +        g_object_unref(G_OBJECT(dst)); + +        result = TRUE; + +    } + +    return result; + +} + + +/****************************************************************************** +*                                                                             *  *  Paramètres  : display = composant GTK à mettre à jour.                     *  *                cursor  = emplacement à présenter à l'écran.                 *  *                                                                             *  | 
