Blame ui/gtk.c

Packit b802ec
/*
Packit b802ec
    mtr  --  a network diagnostic tool
Packit b802ec
    Copyright (C) 1997,1998  Matt Kimball
Packit b802ec
    Changes/additions Copyright (C) 1998 R.E.Wolff@BitWizard.nl
Packit b802ec
Packit b802ec
    This program is free software; you can redistribute it and/or modify
Packit b802ec
    it under the terms of the GNU General Public License version 2 as 
Packit b802ec
    published by the Free Software Foundation.
Packit b802ec
Packit b802ec
    This program is distributed in the hope that it will be useful,
Packit b802ec
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b802ec
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b802ec
    GNU General Public License for more details.
Packit b802ec
Packit b802ec
    You should have received a copy of the GNU General Public License
Packit b802ec
    along with this program; if not, write to the Free Software
Packit b802ec
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Packit b802ec
*/
Packit b802ec
Packit b802ec
#include "config.h"
Packit b802ec
Packit b802ec
#include <stdio.h>
Packit b802ec
#include <stdlib.h>
Packit b802ec
#include <unistd.h>
Packit b802ec
#include <sys/time.h>
Packit b802ec
#include <sys/types.h>
Packit b802ec
Packit b802ec
#ifdef HAVE_GTK
Packit b802ec
#include <string.h>
Packit b802ec
#include <sys/types.h>
Packit b802ec
#include <gtk/gtk.h>
Packit b802ec
Packit b802ec
#include "mtr.h"
Packit b802ec
#include "net.h"
Packit b802ec
#include "dns.h"
Packit b802ec
#include "asn.h"
Packit b802ec
#include "mtr-gtk.h"
Packit b802ec
#include "utils.h"
Packit b802ec
Packit b802ec
#include "img/mtr_icon.xpm"
Packit b802ec
#endif
Packit b802ec
Packit b802ec
static gint gtk_ping(
Packit b802ec
    gpointer data);
Packit b802ec
static gint Copy_activate(
Packit b802ec
    GtkWidget * widget,
Packit b802ec
    gpointer data);
Packit b802ec
static gint NewDestination_activate(
Packit b802ec
    GtkWidget * widget,
Packit b802ec
    gpointer data);
Packit b802ec
static gboolean ReportTreeView_clicked(
Packit b802ec
    GtkWidget * Tree,
Packit b802ec
    GdkEventButton * event,
Packit b802ec
    gpointer data);
Packit b802ec
static gchar *getSelectedHost(
Packit b802ec
    GtkTreePath * path);
Packit b802ec
Packit b802ec
static int ping_timeout_timer;
Packit b802ec
static GtkWidget *Pause_Button;
Packit b802ec
static GtkWidget *Entry;
Packit b802ec
static GtkWidget *main_window;
Packit b802ec
Packit b802ec
static void gtk_add_ping_timeout(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int dt;
Packit b802ec
Packit b802ec
    if (gtk_toggle_button_get_active((GtkToggleButton *) Pause_Button)) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
    dt = calc_deltatime(ctl->WaitTime);
Packit b802ec
    gtk_redraw(ctl);
Packit b802ec
    ping_timeout_timer = g_timeout_add(dt / 1000, gtk_ping, ctl);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static void gtk_do_init(
Packit b802ec
    int *argc,
Packit b802ec
    char ***argv)
Packit b802ec
{
Packit b802ec
    static int done = 0;
Packit b802ec
Packit b802ec
    if (!done) {
Packit b802ec
        gtk_init(argc, argv);
Packit b802ec
Packit b802ec
        done = 1;
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int gtk_detect(
Packit b802ec
    ATTRIBUTE_UNUSED int *argc,
Packit b802ec
    ATTRIBUTE_UNUSED char ***argv)
Packit b802ec
{
Packit b802ec
    if (getenv("DISPLAY") != NULL) {
Packit b802ec
        /* If we do this here, gtk_init exits on an error. This happens
Packit b802ec
           BEFORE the user has had a chance to tell us not to use the 
Packit b802ec
           display... */
Packit b802ec
        return TRUE;
Packit b802ec
    } else {
Packit b802ec
        return FALSE;
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gint Window_destroy(
Packit b802ec
    ATTRIBUTE_UNUSED GtkWidget * Window,
Packit b802ec
    ATTRIBUTE_UNUSED gpointer data)
Packit b802ec
{
Packit b802ec
    gtk_main_quit();
Packit b802ec
Packit b802ec
    return FALSE;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gint Restart_clicked(
Packit b802ec
    ATTRIBUTE_UNUSED GtkWidget * Button,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
Packit b802ec
    net_reset(ctl);
Packit b802ec
    gtk_redraw(ctl);
Packit b802ec
Packit b802ec
    return FALSE;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gint Pause_clicked(
Packit b802ec
    ATTRIBUTE_UNUSED GtkWidget * Button,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
Packit b802ec
    static int paused = 0;
Packit b802ec
Packit b802ec
    if (paused) {
Packit b802ec
        gtk_add_ping_timeout(ctl);
Packit b802ec
    } else {
Packit b802ec
        g_source_remove(ping_timeout_timer);
Packit b802ec
    }
Packit b802ec
    paused = !paused;
Packit b802ec
    gtk_redraw(ctl);
Packit b802ec
Packit b802ec
    return FALSE;
Packit b802ec
}
Packit b802ec
Packit b802ec
static gint About_clicked(
Packit b802ec
    ATTRIBUTE_UNUSED GtkWidget * Button,
Packit b802ec
    ATTRIBUTE_UNUSED gpointer data)
Packit b802ec
{
Packit b802ec
    static const gchar *authors[] = {
Packit b802ec
        "Matt Kimball <matt.kimball@gmail.com>",
Packit b802ec
        "Roger Wolff <R.E.Wolff@BitWizard.nl>",
Packit b802ec
        "Bohdan Vlasyuk <bohdan@cec.vstu.vinnica.ua>",
Packit b802ec
        "Evgeniy Tretyak <evtr@ukr.net>",
Packit b802ec
        "John Thacker <thacker@math.cornell.edu>",
Packit b802ec
        "Juha Takala",
Packit b802ec
        "David Sward <sward@clark.net>",
Packit b802ec
        "David Stone <stone@AsIf.com>",
Packit b802ec
        "Andrew Stesin",
Packit b802ec
        "Greg Stark <gsstark@mit.edu>",
Packit b802ec
        "Robert Sparks <rjsparks@nostrum.com>",
Packit b802ec
        "Mike Simons <msimons@moria.simons-clan.com>",
Packit b802ec
        "Aaron Scarisbrick,",
Packit b802ec
        "Craig Milo Rogers <Rogers@ISI.EDU>",
Packit b802ec
        "Antonio Querubin <tony@lavanauts.org>",
Packit b802ec
        "Russell Nelson <rn-mtr@crynwr.com>",
Packit b802ec
        "Davin Milun <milun@acm.org>",
Packit b802ec
        "Josh Martin <jmartin@columbiaservices.net>",
Packit b802ec
        "Alexander V. Lukyanov <lav@yars.free.net>",
Packit b802ec
        "Charles Levert <charles@comm.polymtl.ca> ",
Packit b802ec
        "Bertrand Leconte <B.Leconte@mail.dotcom.fr>",
Packit b802ec
        "Anand Kumria",
Packit b802ec
        "Olav Kvittem <Olav.Kvittem@uninett.no>",
Packit b802ec
        "Adam Kramer <l3zqc@qcunix1.acc.qc.edu> ",
Packit b802ec
        "Philip Kizer <pckizer@nostrum.com>",
Packit b802ec
        "Simon Kirby",
Packit b802ec
        "Sami Kerola <kerolasa@iki.fi>",
Packit b802ec
        "Christophe Kalt",
Packit b802ec
        "Steve Kann <stevek@spheara.horizonlive.com>",
Packit b802ec
        "Brett Johnson <brett@jdacareers.com>",
Packit b802ec
        "Roland Illig <roland.illig@gmx.de>",
Packit b802ec
        "Damian Gryski <dgryski@uwaterloo.ca>",
Packit b802ec
        "Rob Foehl <rwf@loonybin.net>",
Packit b802ec
        "Mircea Damian",
Packit b802ec
        "Cougar <cougar@random.ee>",
Packit b802ec
        "Travis Cross <tc@traviscross.com>",
Packit b802ec
        "Brian Casey",
Packit b802ec
        "Andrew Brown <atatat@atatdot.net>",
Packit b802ec
        "Bill Bogstad <bogstad@pobox.com> ",
Packit b802ec
        "Marc Bejarano <marc.bejarano@openwave.com>",
Packit b802ec
        "Moritz Barsnick <barsnick@gmx.net>",
Packit b802ec
        "Thomas Klausner <wiz@NetBSD.org>",
Packit b802ec
        NULL
Packit b802ec
    };
Packit b802ec
Packit b802ec
    gtk_show_about_dialog(GTK_WINDOW(main_window)
Packit b802ec
                          , "version", PACKAGE_VERSION, "copyright",
Packit b802ec
                          "Copyright \xc2\xa9 1997,1998  Matt Kimball",
Packit b802ec
                          "website", "http://www.bitwizard.nl/mtr/",
Packit b802ec
                          "authors", authors, "comments",
Packit b802ec
                          "The 'traceroute' and 'ping' programs in a single network diagnostic tool.",
Packit b802ec
                          "license",
Packit b802ec
                          "This program is free software; you can redistribute it and/or modify\n"
Packit b802ec
                          "it under the terms of the GNU General Public License version 2 as\n"
Packit b802ec
                          "published by the Free Software Foundation.\n"
Packit b802ec
                          "\n"
Packit b802ec
                          "This program is distributed in the hope that it will be useful,\n"
Packit b802ec
                          "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
Packit b802ec
                          "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
Packit b802ec
                          "GNU General Public License for more details.",
Packit b802ec
                          NULL);
Packit b802ec
    return TRUE;
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
 * There is a small problem with the following code:
Packit b802ec
 * The timeout is canceled and removed in order to ensure that
Packit b802ec
 * it takes effect (consider what happens if you set the timeout to 999,
Packit b802ec
 * then try to undo the change); is a better approach possible?
Packit b802ec
 *
Packit b802ec
 * What's the problem with this? (-> "I don't think so)
Packit b802ec
 */
Packit b802ec
Packit b802ec
static gint WaitTime_changed(
Packit b802ec
    ATTRIBUTE_UNUSED GtkAdjustment * Adj,
Packit b802ec
    GtkWidget * data)
Packit b802ec
{
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
    GtkWidget *Button = (GtkWidget *) ctl->gtk_data;
Packit b802ec
Packit b802ec
    ctl->WaitTime = gtk_spin_button_get_value(GTK_SPIN_BUTTON(Button));
Packit b802ec
    g_source_remove(ping_timeout_timer);
Packit b802ec
    gtk_add_ping_timeout(ctl);
Packit b802ec
    gtk_redraw(ctl);
Packit b802ec
Packit b802ec
    return FALSE;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gint Host_activate(
Packit b802ec
    GtkWidget * entry,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
    struct hostent *addr;
Packit b802ec
Packit b802ec
    addr = dns_forward(gtk_entry_get_text(GTK_ENTRY(entry)));
Packit b802ec
    if (addr) {
Packit b802ec
        net_reopen(ctl, addr);
Packit b802ec
        /* If we are "Paused" at this point it is usually because someone
Packit b802ec
           entered a non-existing host. Therefore do the go-ahead... */
Packit b802ec
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Pause_Button), 0);
Packit b802ec
    } else {
Packit b802ec
        int pos = strlen(gtk_entry_get_text(GTK_ENTRY(entry)));
Packit b802ec
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Pause_Button), 1);
Packit b802ec
        gtk_editable_insert_text(GTK_EDITABLE(entry), ": not found", -1,
Packit b802ec
                                 &pos;;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return FALSE;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
Packit b802ec
static void Toolbar_fill(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    GtkWidget * Toolbar)
Packit b802ec
{
Packit b802ec
    GtkWidget *Button;
Packit b802ec
    GtkWidget *Label;
Packit b802ec
    GtkAdjustment *Adjustment;
Packit b802ec
Packit b802ec
    Button = gtk_button_new_from_stock(GTK_STOCK_QUIT);
Packit b802ec
    gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
Packit b802ec
    g_signal_connect(GTK_OBJECT(Button), "clicked",
Packit b802ec
                     GTK_SIGNAL_FUNC(Window_destroy), NULL);
Packit b802ec
Packit b802ec
    Button = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
Packit b802ec
    gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
Packit b802ec
    g_signal_connect(GTK_OBJECT(Button), "clicked",
Packit b802ec
                     GTK_SIGNAL_FUNC(About_clicked), NULL);
Packit b802ec
Packit b802ec
    Button = gtk_button_new_with_mnemonic("_Restart");
Packit b802ec
    gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
Packit b802ec
    g_signal_connect(GTK_OBJECT(Button), "clicked",
Packit b802ec
                     GTK_SIGNAL_FUNC(Restart_clicked), ctl);
Packit b802ec
Packit b802ec
    Pause_Button = gtk_toggle_button_new_with_mnemonic("_Pause");
Packit b802ec
    gtk_box_pack_end(GTK_BOX(Toolbar), Pause_Button, FALSE, FALSE, 0);
Packit b802ec
    g_signal_connect(GTK_OBJECT(Pause_Button), "clicked",
Packit b802ec
                     GTK_SIGNAL_FUNC(Pause_clicked), ctl);
Packit b802ec
Packit b802ec
    /* allow root only to set zero delay */
Packit b802ec
    Adjustment = (GtkAdjustment *) gtk_adjustment_new(ctl->WaitTime,
Packit b802ec
                                                      getuid() ==
Packit b802ec
                                                      0 ? 0.01 : 1.00,
Packit b802ec
                                                      999.99, 1.0, 10.0,
Packit b802ec
                                                      0.0);
Packit b802ec
    Button = gtk_spin_button_new(Adjustment, 0.5, 2);
Packit b802ec
    gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(Button), TRUE);
Packit b802ec
    gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
Packit b802ec
    ctl->gtk_data = Button;
Packit b802ec
    g_signal_connect(GTK_OBJECT(Adjustment), "value_changed",
Packit b802ec
                     GTK_SIGNAL_FUNC(WaitTime_changed), ctl);
Packit b802ec
Packit b802ec
    Label = gtk_label_new_with_mnemonic("_Hostname:");
Packit b802ec
    gtk_box_pack_start(GTK_BOX(Toolbar), Label, FALSE, FALSE, 0);
Packit b802ec
Packit b802ec
    Entry = gtk_entry_new();
Packit b802ec
    gtk_entry_set_text(GTK_ENTRY(Entry), ctl->Hostname);
Packit b802ec
    g_signal_connect(GTK_OBJECT(Entry), "activate",
Packit b802ec
                     GTK_SIGNAL_FUNC(Host_activate), ctl);
Packit b802ec
    gtk_box_pack_start(GTK_BOX(Toolbar), Entry, TRUE, TRUE, 0);
Packit b802ec
Packit b802ec
    gtk_label_set_mnemonic_widget(GTK_LABEL(Label), Entry);
Packit b802ec
}
Packit b802ec
Packit b802ec
static GtkWidget *ReportTreeView;
Packit b802ec
static GtkListStore *ReportStore;
Packit b802ec
Packit b802ec
enum {
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
    COL_ASN,
Packit b802ec
#endif
Packit b802ec
    COL_HOSTNAME,
Packit b802ec
    COL_LOSS,
Packit b802ec
    COL_RCV,
Packit b802ec
    COL_SNT,
Packit b802ec
    COL_LAST,
Packit b802ec
    COL_BEST,
Packit b802ec
    COL_AVG,
Packit b802ec
    COL_WORST,
Packit b802ec
    COL_STDEV,
Packit b802ec
    COL_COLOR,
Packit b802ec
    N_COLS
Packit b802ec
};
Packit b802ec
Packit b802ec
/* Trick to cast a pointer to integer.  We are mis-using a pointer as a
Packit b802ec
   single integer.  On 64-bit architectures, the pointer is 64 bits and the
Packit b802ec
   integer only 32.  The compiler warns us of loss of precision.  However we
Packit b802ec
   know we casted a normal 32-bit integer into this pointer a few
Packit b802ec
   microseconds earlier, so it is ok.  Nothing to worry about.  */
Packit b802ec
#define POINTER_TO_INT(p) ((int)(long)(p))
Packit b802ec
Packit b802ec
static void float_formatter(
Packit b802ec
    GtkTreeViewColumn * tree_column ATTRIBUTE_UNUSED,
Packit b802ec
    GtkCellRenderer * cell,
Packit b802ec
    GtkTreeModel * tree_model,
Packit b802ec
    GtkTreeIter * iter,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    gfloat f;
Packit b802ec
    gchar text[64];
Packit b802ec
    gtk_tree_model_get(tree_model, iter, POINTER_TO_INT(data), &f, -1);
Packit b802ec
    sprintf(text, "%.2f", f);
Packit b802ec
    g_object_set(cell, "text", text, NULL);
Packit b802ec
}
Packit b802ec
Packit b802ec
static void percent_formatter(
Packit b802ec
    GtkTreeViewColumn * tree_column ATTRIBUTE_UNUSED,
Packit b802ec
    GtkCellRenderer * cell,
Packit b802ec
    GtkTreeModel * tree_model,
Packit b802ec
    GtkTreeIter * iter,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    gfloat f;
Packit b802ec
    gchar text[64];
Packit b802ec
    gtk_tree_model_get(tree_model, iter, POINTER_TO_INT(data), &f, -1);
Packit b802ec
    sprintf(text, "%.1f%%", f);
Packit b802ec
    g_object_set(cell, "text", text, NULL);
Packit b802ec
}
Packit b802ec
Packit b802ec
static void TreeViewCreate(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    GtkCellRenderer *renderer;
Packit b802ec
    GtkTreeViewColumn *column;
Packit b802ec
Packit b802ec
    ReportStore = gtk_list_store_new(N_COLS,
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
                                     G_TYPE_STRING,
Packit b802ec
#endif
Packit b802ec
                                     G_TYPE_STRING,
Packit b802ec
                                     G_TYPE_FLOAT,
Packit b802ec
                                     G_TYPE_INT,
Packit b802ec
                                     G_TYPE_INT,
Packit b802ec
                                     G_TYPE_INT,
Packit b802ec
                                     G_TYPE_INT,
Packit b802ec
                                     G_TYPE_INT,
Packit b802ec
                                     G_TYPE_INT,
Packit b802ec
                                     G_TYPE_FLOAT, G_TYPE_STRING);
Packit b802ec
Packit b802ec
    ReportTreeView =
Packit b802ec
        gtk_tree_view_new_with_model(GTK_TREE_MODEL(ReportStore));
Packit b802ec
Packit b802ec
    g_signal_connect(GTK_OBJECT(ReportTreeView), "button_press_event",
Packit b802ec
                     G_CALLBACK(ReportTreeView_clicked), ctl);
Packit b802ec
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
    if (is_printii(ctl)) {
Packit b802ec
        renderer = gtk_cell_renderer_text_new();
Packit b802ec
        column = gtk_tree_view_column_new_with_attributes("ASN",
Packit b802ec
                                                          renderer,
Packit b802ec
                                                          "text", COL_ASN,
Packit b802ec
                                                          "foreground",
Packit b802ec
                                                          COL_COLOR, NULL);
Packit b802ec
        gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
        gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
    }
Packit b802ec
#endif
Packit b802ec
Packit b802ec
    renderer = gtk_cell_renderer_text_new();
Packit b802ec
    column = gtk_tree_view_column_new_with_attributes("Hostname",
Packit b802ec
                                                      renderer,
Packit b802ec
                                                      "text", COL_HOSTNAME,
Packit b802ec
                                                      "foreground",
Packit b802ec
                                                      COL_COLOR, NULL);
Packit b802ec
    gtk_tree_view_column_set_expand(column, TRUE);
Packit b802ec
    gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
    gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
Packit b802ec
    renderer = gtk_cell_renderer_text_new();
Packit b802ec
    g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
Packit b802ec
    column = gtk_tree_view_column_new_with_attributes("Loss",
Packit b802ec
                                                      renderer,
Packit b802ec
                                                      "text", COL_LOSS,
Packit b802ec
                                                      "foreground",
Packit b802ec
                                                      COL_COLOR, NULL);
Packit b802ec
    gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
    gtk_tree_view_column_set_cell_data_func(column, renderer,
Packit b802ec
                                            percent_formatter,
Packit b802ec
                                            (void *) COL_LOSS, NULL);
Packit b802ec
    gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
Packit b802ec
    renderer = gtk_cell_renderer_text_new();
Packit b802ec
    g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
Packit b802ec
    column = gtk_tree_view_column_new_with_attributes("Snt",
Packit b802ec
                                                      renderer,
Packit b802ec
                                                      "text", COL_SNT,
Packit b802ec
                                                      "foreground",
Packit b802ec
                                                      COL_COLOR, NULL);
Packit b802ec
    gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
    gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
Packit b802ec
    renderer = gtk_cell_renderer_text_new();
Packit b802ec
    g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
Packit b802ec
    column = gtk_tree_view_column_new_with_attributes("Last",
Packit b802ec
                                                      renderer,
Packit b802ec
                                                      "text", COL_LAST,
Packit b802ec
                                                      "foreground",
Packit b802ec
                                                      COL_COLOR, NULL);
Packit b802ec
    gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
    gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
Packit b802ec
    renderer = gtk_cell_renderer_text_new();
Packit b802ec
    g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
Packit b802ec
    column = gtk_tree_view_column_new_with_attributes("Avg",
Packit b802ec
                                                      renderer,
Packit b802ec
                                                      "text", COL_AVG,
Packit b802ec
                                                      "foreground",
Packit b802ec
                                                      COL_COLOR, NULL);
Packit b802ec
    gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
    gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
Packit b802ec
    renderer = gtk_cell_renderer_text_new();
Packit b802ec
    g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
Packit b802ec
    column = gtk_tree_view_column_new_with_attributes("Best",
Packit b802ec
                                                      renderer,
Packit b802ec
                                                      "text", COL_BEST,
Packit b802ec
                                                      "foreground",
Packit b802ec
                                                      COL_COLOR, NULL);
Packit b802ec
    gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
    gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
Packit b802ec
    renderer = gtk_cell_renderer_text_new();
Packit b802ec
    g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
Packit b802ec
    column = gtk_tree_view_column_new_with_attributes("Worst",
Packit b802ec
                                                      renderer,
Packit b802ec
                                                      "text", COL_WORST,
Packit b802ec
                                                      "foreground",
Packit b802ec
                                                      COL_COLOR, NULL);
Packit b802ec
    gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
    gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
Packit b802ec
    renderer = gtk_cell_renderer_text_new();
Packit b802ec
    g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
Packit b802ec
    column = gtk_tree_view_column_new_with_attributes("StDev",
Packit b802ec
                                                      renderer,
Packit b802ec
                                                      "text", COL_STDEV,
Packit b802ec
                                                      "foreground",
Packit b802ec
                                                      COL_COLOR, NULL);
Packit b802ec
    gtk_tree_view_column_set_resizable(column, TRUE);
Packit b802ec
    gtk_tree_view_column_set_cell_data_func(column, renderer,
Packit b802ec
                                            float_formatter,
Packit b802ec
                                            (void *) COL_STDEV, NULL);
Packit b802ec
    gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
Packit b802ec
Packit b802ec
}
Packit b802ec
Packit b802ec
static void update_tree_row(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    int row,
Packit b802ec
    GtkTreeIter * iter)
Packit b802ec
{
Packit b802ec
    ip_t *addr;
Packit b802ec
    char str[256] = "???", *name = str;
Packit b802ec
Packit b802ec
    addr = net_addr(row);
Packit b802ec
    if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
Packit b802ec
        if ((name = dns_lookup(ctl, addr))) {
Packit b802ec
            if (ctl->show_ips) {
Packit b802ec
                snprintf(str, sizeof(str), "%s (%s)", name,
Packit b802ec
                         strlongip(ctl, addr));
Packit b802ec
                name = str;
Packit b802ec
            }
Packit b802ec
        } else
Packit b802ec
            name = strlongip(ctl, addr);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    gtk_list_store_set(ReportStore, iter,
Packit b802ec
                       COL_HOSTNAME, name,
Packit b802ec
                       COL_LOSS, (float) (net_loss(row) / 1000.0),
Packit b802ec
                       COL_RCV, net_returned(row),
Packit b802ec
                       COL_SNT, net_xmit(row),
Packit b802ec
                       COL_LAST, net_last(row) / 1000,
Packit b802ec
                       COL_BEST, net_best(row) / 1000,
Packit b802ec
                       COL_AVG, net_avg(row) / 1000,
Packit b802ec
                       COL_WORST, net_worst(row) / 1000,
Packit b802ec
                       COL_STDEV, (float) (net_stdev(row) / 1000.0),
Packit b802ec
                       COL_COLOR, net_up(row) ? NULL : "red", -1);
Packit b802ec
#ifdef HAVE_IPINFO
Packit b802ec
    if (is_printii(ctl))
Packit b802ec
        gtk_list_store_set(ReportStore, iter, COL_ASN,
Packit b802ec
                           fmt_ipinfo(ctl, addr), -1);
Packit b802ec
#endif
Packit b802ec
}
Packit b802ec
Packit b802ec
void gtk_redraw(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int max = net_max(ctl);
Packit b802ec
Packit b802ec
    GtkTreeIter iter;
Packit b802ec
    int row = net_min(ctl);
Packit b802ec
    gboolean valid;
Packit b802ec
Packit b802ec
    valid =
Packit b802ec
        gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ReportStore), &iter);
Packit b802ec
Packit b802ec
    while (valid) {
Packit b802ec
        if (row < max) {
Packit b802ec
            update_tree_row(ctl, row++, &iter);
Packit b802ec
            valid =
Packit b802ec
                gtk_tree_model_iter_next(GTK_TREE_MODEL(ReportStore),
Packit b802ec
                                         &iter);
Packit b802ec
        } else {
Packit b802ec
            valid = gtk_list_store_remove(ReportStore, &iter);
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
    while (row < max) {
Packit b802ec
        gtk_list_store_append(ReportStore, &iter);
Packit b802ec
        update_tree_row(ctl, row++, &iter);
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static void Window_fill(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    GtkWidget * Window)
Packit b802ec
{
Packit b802ec
    GtkWidget *VBox;
Packit b802ec
    GtkWidget *Toolbar;
Packit b802ec
    GtkWidget *scroll;
Packit b802ec
Packit b802ec
    gtk_window_set_title(GTK_WINDOW(Window), "My traceroute");
Packit b802ec
    gtk_window_set_default_size(GTK_WINDOW(Window), 650, 400);
Packit b802ec
    gtk_container_set_border_width(GTK_CONTAINER(Window), 10);
Packit b802ec
    VBox = gtk_vbox_new(FALSE, 10);
Packit b802ec
Packit b802ec
    Toolbar = gtk_hbox_new(FALSE, 10);
Packit b802ec
    Toolbar_fill(ctl, Toolbar);
Packit b802ec
    gtk_box_pack_start(GTK_BOX(VBox), Toolbar, FALSE, FALSE, 0);
Packit b802ec
Packit b802ec
    TreeViewCreate(ctl);
Packit b802ec
    scroll = gtk_scrolled_window_new(NULL, NULL);
Packit b802ec
    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
Packit b802ec
                                   GTK_POLICY_AUTOMATIC,
Packit b802ec
                                   GTK_POLICY_AUTOMATIC);
Packit b802ec
    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
Packit b802ec
                                        GTK_SHADOW_IN);
Packit b802ec
    gtk_container_add(GTK_CONTAINER(scroll), ReportTreeView);
Packit b802ec
    gtk_box_pack_start(GTK_BOX(VBox), scroll, TRUE, TRUE, 0);
Packit b802ec
Packit b802ec
    gtk_container_add(GTK_CONTAINER(Window), VBox);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void gtk_open(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    GdkPixbuf *icon;
Packit b802ec
    int argc = 1;
Packit b802ec
    char *args[2];
Packit b802ec
    char **argv;
Packit b802ec
Packit b802ec
    argv = args;
Packit b802ec
    argv[0] = xstrdup("");
Packit b802ec
    argv[1] = NULL;
Packit b802ec
    gtk_do_init(&argc, &argv);
Packit b802ec
    free(argv[0]);
Packit b802ec
Packit b802ec
    icon = gdk_pixbuf_new_from_xpm_data((const char **) mtr_icon);
Packit b802ec
    gtk_window_set_default_icon(icon);
Packit b802ec
Packit b802ec
    main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
Packit b802ec
Packit b802ec
    g_set_application_name("My traceroute");
Packit b802ec
Packit b802ec
    Window_fill(ctl, main_window);
Packit b802ec
Packit b802ec
    g_signal_connect(GTK_OBJECT(main_window), "delete_event",
Packit b802ec
                     GTK_SIGNAL_FUNC(Window_destroy), NULL);
Packit b802ec
    g_signal_connect(GTK_OBJECT(main_window), "destroy",
Packit b802ec
                     GTK_SIGNAL_FUNC(Window_destroy), NULL);
Packit b802ec
Packit b802ec
    gtk_widget_show_all(main_window);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void gtk_close(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int gtk_keyaction(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    return 0;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gint gtk_ping(
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
Packit b802ec
    gtk_redraw(ctl);
Packit b802ec
    net_send_batch(ctl);
Packit b802ec
    net_harvest_fds(ctl);
Packit b802ec
    g_source_remove(ping_timeout_timer);
Packit b802ec
    gtk_add_ping_timeout(ctl);
Packit b802ec
    return TRUE;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gboolean gtk_net_data(
Packit b802ec
    ATTRIBUTE_UNUSED GIOChannel * channel,
Packit b802ec
    ATTRIBUTE_UNUSED GIOCondition cond,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
Packit b802ec
    net_process_return(ctl);
Packit b802ec
    return TRUE;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gboolean gtk_dns_data(
Packit b802ec
    ATTRIBUTE_UNUSED GIOChannel * channel,
Packit b802ec
    ATTRIBUTE_UNUSED GIOCondition cond,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
Packit b802ec
    dns_ack(ctl);
Packit b802ec
    gtk_redraw(ctl);
Packit b802ec
    return TRUE;
Packit b802ec
}
Packit b802ec
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
static gboolean gtk_dns_data6(
Packit b802ec
    ATTRIBUTE_UNUSED GIOChannel * channel,
Packit b802ec
    ATTRIBUTE_UNUSED GIOCondition cond,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
Packit b802ec
    dns_ack6();
Packit b802ec
    gtk_redraw(ctl);
Packit b802ec
    return TRUE;
Packit b802ec
}
Packit b802ec
#endif
Packit b802ec
Packit b802ec
Packit b802ec
void gtk_loop(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    GIOChannel *net_iochannel, *dns_iochannel;
Packit b802ec
Packit b802ec
    gtk_add_ping_timeout(ctl);
Packit b802ec
Packit b802ec
    net_iochannel = g_io_channel_unix_new(net_waitfd());
Packit b802ec
    g_io_add_watch(net_iochannel, G_IO_IN, gtk_net_data, ctl);
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    if (dns_waitfd6() > 0) {
Packit b802ec
        dns_iochannel = g_io_channel_unix_new(dns_waitfd6());
Packit b802ec
        g_io_add_watch(dns_iochannel, G_IO_IN, gtk_dns_data6, ctl);
Packit b802ec
    }
Packit b802ec
#endif
Packit b802ec
    dns_iochannel = g_io_channel_unix_new(dns_waitfd());
Packit b802ec
    g_io_add_watch(dns_iochannel, G_IO_IN, gtk_dns_data, ctl);
Packit b802ec
Packit b802ec
    gtk_main();
Packit b802ec
}
Packit b802ec
Packit b802ec
static gboolean NewDestination_activate(
Packit b802ec
    GtkWidget * widget ATTRIBUTE_UNUSED,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    gchar *hostname;
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
    GtkTreePath *path = (GtkTreePath *) ctl->gtk_data;
Packit b802ec
Packit b802ec
    hostname = getSelectedHost(path);
Packit b802ec
    if (hostname) {
Packit b802ec
        ctl->gtk_data = hostname;
Packit b802ec
        gtk_entry_set_text(GTK_ENTRY(Entry), hostname);
Packit b802ec
        Host_activate(Entry, ctl);
Packit b802ec
        g_free(hostname);
Packit b802ec
    }
Packit b802ec
    return TRUE;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gboolean Copy_activate(
Packit b802ec
    GtkWidget * widget ATTRIBUTE_UNUSED,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    gchar *hostname;
Packit b802ec
    GtkTreePath *path = (GtkTreePath *) data;
Packit b802ec
Packit b802ec
    hostname = getSelectedHost(path);
Packit b802ec
    if (hostname != NULL) {
Packit b802ec
        GtkClipboard *clipboard;
Packit b802ec
Packit b802ec
        clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
Packit b802ec
        gtk_clipboard_set_text(clipboard, hostname, -1);
Packit b802ec
Packit b802ec
        clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
Packit b802ec
        gtk_clipboard_set_text(clipboard, hostname, -1);
Packit b802ec
Packit b802ec
        g_free(hostname);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return TRUE;
Packit b802ec
}
Packit b802ec
Packit b802ec
static gchar *getSelectedHost(
Packit b802ec
    GtkTreePath * path)
Packit b802ec
{
Packit b802ec
    GtkTreeIter iter;
Packit b802ec
    gchar *name = NULL;
Packit b802ec
Packit b802ec
    if (gtk_tree_model_get_iter(GTK_TREE_MODEL(ReportStore), &iter, path)) {
Packit b802ec
        gtk_tree_model_get(GTK_TREE_MODEL(ReportStore), &iter,
Packit b802ec
                           COL_HOSTNAME, &name, -1);
Packit b802ec
    }
Packit b802ec
    gtk_tree_path_free(path);
Packit b802ec
    return name;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static gboolean ReportTreeView_clicked(
Packit b802ec
    GtkWidget * Tree ATTRIBUTE_UNUSED,
Packit b802ec
    GdkEventButton * event,
Packit b802ec
    gpointer data)
Packit b802ec
{
Packit b802ec
    GtkWidget *popup_menu;
Packit b802ec
    GtkWidget *copy_item;
Packit b802ec
    GtkWidget *newdestination_item;
Packit b802ec
    GtkTreePath *path;
Packit b802ec
    struct mtr_ctl *ctl = (struct mtr_ctl *) data;
Packit b802ec
Packit b802ec
    if (event->type != GDK_BUTTON_PRESS || event->button != 3)
Packit b802ec
        return FALSE;
Packit b802ec
Packit b802ec
    if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(ReportTreeView),
Packit b802ec
                                       event->x, event->y, &path, NULL,
Packit b802ec
                                       NULL, NULL))
Packit b802ec
        return FALSE;
Packit b802ec
Packit b802ec
    gtk_tree_view_set_cursor(GTK_TREE_VIEW(ReportTreeView), path, NULL,
Packit b802ec
                             FALSE);
Packit b802ec
Packit b802ec
    /* Single right click: prepare and show the popup menu */
Packit b802ec
    popup_menu = gtk_menu_new();
Packit b802ec
Packit b802ec
    copy_item = gtk_menu_item_new_with_label("Copy to clipboard");
Packit b802ec
    newdestination_item =
Packit b802ec
        gtk_menu_item_new_with_label("Set as new destination");
Packit b802ec
Packit b802ec
    gtk_menu_append(GTK_MENU(popup_menu), copy_item);
Packit b802ec
    gtk_menu_append(GTK_MENU(popup_menu), newdestination_item);
Packit b802ec
Packit b802ec
    g_signal_connect(GTK_OBJECT(copy_item), "activate",
Packit b802ec
                     GTK_SIGNAL_FUNC(Copy_activate), path);
Packit b802ec
Packit b802ec
    ctl->gtk_data = path;
Packit b802ec
    g_signal_connect(GTK_OBJECT(newdestination_item), "activate",
Packit b802ec
                     GTK_SIGNAL_FUNC(NewDestination_activate), ctl);
Packit b802ec
Packit b802ec
    gtk_widget_show(copy_item);
Packit b802ec
    gtk_widget_show(newdestination_item);
Packit b802ec
Packit b802ec
    gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL, NULL, NULL,
Packit b802ec
                   0, event->time);
Packit b802ec
    return TRUE;
Packit b802ec
}