Annotation of embedaddon/mtr/ui/gtk.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:     mtr  --  a network diagnostic tool
                      3:     Copyright (C) 1997,1998  Matt Kimball
                      4:     Changes/additions Copyright (C) 1998 R.E.Wolff@BitWizard.nl
                      5: 
                      6:     This program is free software; you can redistribute it and/or modify
                      7:     it under the terms of the GNU General Public License version 2 as 
                      8:     published by the Free Software Foundation.
                      9: 
                     10:     This program is distributed in the hope that it will be useful,
                     11:     but WITHOUT ANY WARRANTY; without even the implied warranty of
                     12:     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     13:     GNU General Public License for more details.
                     14: 
                     15:     You should have received a copy of the GNU General Public License
                     16:     along with this program; if not, write to the Free Software
                     17:     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                     18: */
                     19: 
                     20: #include "config.h"
                     21: 
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #include <unistd.h>
                     25: #include <sys/time.h>
                     26: #include <sys/types.h>
                     27: 
                     28: #ifdef HAVE_GTK
                     29: #include <string.h>
                     30: #include <sys/types.h>
                     31: #include <gtk/gtk.h>
                     32: 
                     33: #include "mtr.h"
                     34: #include "net.h"
                     35: #include "dns.h"
                     36: #include "asn.h"
                     37: #include "mtr-gtk.h"
                     38: #include "utils.h"
                     39: 
                     40: #include "img/mtr_icon.xpm"
                     41: #endif
                     42: 
                     43: static gint gtk_ping(
                     44:     gpointer data);
                     45: static gint Copy_activate(
                     46:     GtkWidget * widget,
                     47:     gpointer data);
                     48: static gint NewDestination_activate(
                     49:     GtkWidget * widget,
                     50:     gpointer data);
                     51: static gboolean ReportTreeView_clicked(
                     52:     GtkWidget * Tree,
                     53:     GdkEventButton * event,
                     54:     gpointer data);
                     55: static gchar *getSelectedHost(
                     56:     GtkTreePath * path);
                     57: 
                     58: static int ping_timeout_timer;
                     59: static GtkWidget *Pause_Button;
                     60: static GtkWidget *Entry;
                     61: static GtkWidget *main_window;
                     62: 
                     63: static void gtk_add_ping_timeout(
                     64:     struct mtr_ctl *ctl)
                     65: {
                     66:     int dt;
                     67: 
                     68:     if (gtk_toggle_button_get_active((GtkToggleButton *) Pause_Button)) {
                     69:         return;
                     70:     }
                     71:     dt = calc_deltatime(ctl->WaitTime);
                     72:     gtk_redraw(ctl);
                     73:     ping_timeout_timer = g_timeout_add(dt / 1000, gtk_ping, ctl);
                     74: }
                     75: 
                     76: 
                     77: static void gtk_do_init(
                     78:     int *argc,
                     79:     char ***argv)
                     80: {
                     81:     static int done = 0;
                     82: 
                     83:     if (!done) {
                     84:         gtk_init(argc, argv);
                     85: 
                     86:         done = 1;
                     87:     }
                     88: }
                     89: 
                     90: 
                     91: int gtk_detect(
                     92:     ATTRIBUTE_UNUSED int *argc,
                     93:     ATTRIBUTE_UNUSED char ***argv)
                     94: {
                     95:     if (getenv("DISPLAY") != NULL) {
                     96:         /* If we do this here, gtk_init exits on an error. This happens
                     97:            BEFORE the user has had a chance to tell us not to use the 
                     98:            display... */
                     99:         return TRUE;
                    100:     } else {
                    101:         return FALSE;
                    102:     }
                    103: }
                    104: 
                    105: 
                    106: static gint Window_destroy(
                    107:     ATTRIBUTE_UNUSED GtkWidget * Window,
                    108:     ATTRIBUTE_UNUSED gpointer data)
                    109: {
                    110:     gtk_main_quit();
                    111: 
                    112:     return FALSE;
                    113: }
                    114: 
                    115: 
                    116: static gint Restart_clicked(
                    117:     ATTRIBUTE_UNUSED GtkWidget * Button,
                    118:     gpointer data)
                    119: {
                    120:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    121: 
                    122:     net_reset(ctl);
                    123:     gtk_redraw(ctl);
                    124: 
                    125:     return FALSE;
                    126: }
                    127: 
                    128: 
                    129: static gint Pause_clicked(
                    130:     ATTRIBUTE_UNUSED GtkWidget * Button,
                    131:     gpointer data)
                    132: {
                    133:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    134: 
                    135:     static int paused = 0;
                    136: 
                    137:     if (paused) {
                    138:         gtk_add_ping_timeout(ctl);
                    139:     } else {
                    140:         g_source_remove(ping_timeout_timer);
                    141:     }
                    142:     paused = !paused;
                    143:     gtk_redraw(ctl);
                    144: 
                    145:     return FALSE;
                    146: }
                    147: 
                    148: static gint About_clicked(
                    149:     ATTRIBUTE_UNUSED GtkWidget * Button,
                    150:     ATTRIBUTE_UNUSED gpointer data)
                    151: {
                    152:     static const gchar *authors[] = {
                    153:         "Matt Kimball <matt.kimball@gmail.com>",
                    154:         "Roger Wolff <R.E.Wolff@BitWizard.nl>",
                    155:         "Bohdan Vlasyuk <bohdan@cec.vstu.vinnica.ua>",
                    156:         "Evgeniy Tretyak <evtr@ukr.net>",
                    157:         "John Thacker <thacker@math.cornell.edu>",
                    158:         "Juha Takala",
                    159:         "David Sward <sward@clark.net>",
                    160:         "David Stone <stone@AsIf.com>",
                    161:         "Andrew Stesin",
                    162:         "Greg Stark <gsstark@mit.edu>",
                    163:         "Robert Sparks <rjsparks@nostrum.com>",
                    164:         "Mike Simons <msimons@moria.simons-clan.com>",
                    165:         "Aaron Scarisbrick,",
                    166:         "Craig Milo Rogers <Rogers@ISI.EDU>",
                    167:         "Antonio Querubin <tony@lavanauts.org>",
                    168:         "Russell Nelson <rn-mtr@crynwr.com>",
                    169:         "Davin Milun <milun@acm.org>",
                    170:         "Josh Martin <jmartin@columbiaservices.net>",
                    171:         "Alexander V. Lukyanov <lav@yars.free.net>",
                    172:         "Charles Levert <charles@comm.polymtl.ca> ",
                    173:         "Bertrand Leconte <B.Leconte@mail.dotcom.fr>",
                    174:         "Anand Kumria",
                    175:         "Olav Kvittem <Olav.Kvittem@uninett.no>",
                    176:         "Adam Kramer <l3zqc@qcunix1.acc.qc.edu> ",
                    177:         "Philip Kizer <pckizer@nostrum.com>",
                    178:         "Simon Kirby",
                    179:         "Sami Kerola <kerolasa@iki.fi>",
                    180:         "Christophe Kalt",
                    181:         "Steve Kann <stevek@spheara.horizonlive.com>",
                    182:         "Brett Johnson <brett@jdacareers.com>",
                    183:         "Roland Illig <roland.illig@gmx.de>",
                    184:         "Damian Gryski <dgryski@uwaterloo.ca>",
                    185:         "Rob Foehl <rwf@loonybin.net>",
                    186:         "Mircea Damian",
                    187:         "Cougar <cougar@random.ee>",
                    188:         "Travis Cross <tc@traviscross.com>",
                    189:         "Brian Casey",
                    190:         "Andrew Brown <atatat@atatdot.net>",
                    191:         "Bill Bogstad <bogstad@pobox.com> ",
                    192:         "Marc Bejarano <marc.bejarano@openwave.com>",
                    193:         "Moritz Barsnick <barsnick@gmx.net>",
                    194:         "Thomas Klausner <wiz@NetBSD.org>",
                    195:         NULL
                    196:     };
                    197: 
                    198:     gtk_show_about_dialog(GTK_WINDOW(main_window)
                    199:                           , "version", PACKAGE_VERSION, "copyright",
                    200:                           "Copyright \xc2\xa9 1997,1998  Matt Kimball",
                    201:                           "website", "http://www.bitwizard.nl/mtr/",
                    202:                           "authors", authors, "comments",
                    203:                           "The 'traceroute' and 'ping' programs in a single network diagnostic tool.",
                    204:                           "license",
                    205:                           "This program is free software; you can redistribute it and/or modify\n"
                    206:                           "it under the terms of the GNU General Public License version 2 as\n"
                    207:                           "published by the Free Software Foundation.\n"
                    208:                           "\n"
                    209:                           "This program is distributed in the hope that it will be useful,\n"
                    210:                           "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
                    211:                           "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
                    212:                           "GNU General Public License for more details.",
                    213:                           NULL);
                    214:     return TRUE;
                    215: }
                    216: 
                    217: /*
                    218:  * There is a small problem with the following code:
                    219:  * The timeout is canceled and removed in order to ensure that
                    220:  * it takes effect (consider what happens if you set the timeout to 999,
                    221:  * then try to undo the change); is a better approach possible?
                    222:  *
                    223:  * What's the problem with this? (-> "I don't think so)
                    224:  */
                    225: 
                    226: static gint WaitTime_changed(
                    227:     ATTRIBUTE_UNUSED GtkAdjustment * Adj,
                    228:     GtkWidget * data)
                    229: {
                    230:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    231:     GtkWidget *Button = (GtkWidget *) ctl->gtk_data;
                    232: 
                    233:     ctl->WaitTime = gtk_spin_button_get_value(GTK_SPIN_BUTTON(Button));
                    234:     g_source_remove(ping_timeout_timer);
                    235:     gtk_add_ping_timeout(ctl);
                    236:     gtk_redraw(ctl);
                    237: 
                    238:     return FALSE;
                    239: }
                    240: 
                    241: 
                    242: static gint Host_activate(
                    243:     GtkWidget * entry,
                    244:     gpointer data)
                    245: {
                    246:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    247:     struct hostent *addr;
                    248: 
                    249:     addr = dns_forward(gtk_entry_get_text(GTK_ENTRY(entry)));
                    250:     if (addr) {
                    251:         net_reopen(ctl, addr);
                    252:         /* If we are "Paused" at this point it is usually because someone
                    253:            entered a non-existing host. Therefore do the go-ahead... */
                    254:         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Pause_Button), 0);
                    255:     } else {
                    256:         int pos = strlen(gtk_entry_get_text(GTK_ENTRY(entry)));
                    257:         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Pause_Button), 1);
                    258:         gtk_editable_insert_text(GTK_EDITABLE(entry), ": not found", -1,
                    259:                                  &pos);
                    260:     }
                    261: 
                    262:     return FALSE;
                    263: }
                    264: 
                    265: 
                    266: 
                    267: static void Toolbar_fill(
                    268:     struct mtr_ctl *ctl,
                    269:     GtkWidget * Toolbar)
                    270: {
                    271:     GtkWidget *Button;
                    272:     GtkWidget *Label;
                    273:     GtkAdjustment *Adjustment;
                    274: 
                    275:     Button = gtk_button_new_from_stock(GTK_STOCK_QUIT);
                    276:     gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
                    277:     g_signal_connect(GTK_OBJECT(Button), "clicked",
                    278:                      GTK_SIGNAL_FUNC(Window_destroy), NULL);
                    279: 
                    280:     Button = gtk_button_new_from_stock(GTK_STOCK_ABOUT);
                    281:     gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
                    282:     g_signal_connect(GTK_OBJECT(Button), "clicked",
                    283:                      GTK_SIGNAL_FUNC(About_clicked), NULL);
                    284: 
                    285:     Button = gtk_button_new_with_mnemonic("_Restart");
                    286:     gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
                    287:     g_signal_connect(GTK_OBJECT(Button), "clicked",
                    288:                      GTK_SIGNAL_FUNC(Restart_clicked), ctl);
                    289: 
                    290:     Pause_Button = gtk_toggle_button_new_with_mnemonic("_Pause");
                    291:     gtk_box_pack_end(GTK_BOX(Toolbar), Pause_Button, FALSE, FALSE, 0);
                    292:     g_signal_connect(GTK_OBJECT(Pause_Button), "clicked",
                    293:                      GTK_SIGNAL_FUNC(Pause_clicked), ctl);
                    294: 
                    295:     /* allow root only to set zero delay */
                    296:     Adjustment = (GtkAdjustment *) gtk_adjustment_new(ctl->WaitTime,
                    297:                                                       getuid() ==
                    298:                                                       0 ? 0.01 : 1.00,
                    299:                                                       999.99, 1.0, 10.0,
                    300:                                                       0.0);
                    301:     Button = gtk_spin_button_new(Adjustment, 0.5, 2);
                    302:     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(Button), TRUE);
                    303:     gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
                    304:     ctl->gtk_data = Button;
                    305:     g_signal_connect(GTK_OBJECT(Adjustment), "value_changed",
                    306:                      GTK_SIGNAL_FUNC(WaitTime_changed), ctl);
                    307: 
                    308:     Label = gtk_label_new_with_mnemonic("_Hostname:");
                    309:     gtk_box_pack_start(GTK_BOX(Toolbar), Label, FALSE, FALSE, 0);
                    310: 
                    311:     Entry = gtk_entry_new();
                    312:     gtk_entry_set_text(GTK_ENTRY(Entry), ctl->Hostname);
                    313:     g_signal_connect(GTK_OBJECT(Entry), "activate",
                    314:                      GTK_SIGNAL_FUNC(Host_activate), ctl);
                    315:     gtk_box_pack_start(GTK_BOX(Toolbar), Entry, TRUE, TRUE, 0);
                    316: 
                    317:     gtk_label_set_mnemonic_widget(GTK_LABEL(Label), Entry);
                    318: }
                    319: 
                    320: static GtkWidget *ReportTreeView;
                    321: static GtkListStore *ReportStore;
                    322: 
                    323: enum {
                    324: #ifdef HAVE_IPINFO
                    325:     COL_ASN,
                    326: #endif
                    327:     COL_HOSTNAME,
                    328:     COL_LOSS,
                    329:     COL_RCV,
                    330:     COL_SNT,
                    331:     COL_LAST,
                    332:     COL_BEST,
                    333:     COL_AVG,
                    334:     COL_WORST,
                    335:     COL_STDEV,
                    336:     COL_COLOR,
                    337:     N_COLS
                    338: };
                    339: 
                    340: /* Trick to cast a pointer to integer.  We are mis-using a pointer as a
                    341:    single integer.  On 64-bit architectures, the pointer is 64 bits and the
                    342:    integer only 32.  The compiler warns us of loss of precision.  However we
                    343:    know we casted a normal 32-bit integer into this pointer a few
                    344:    microseconds earlier, so it is ok.  Nothing to worry about.  */
                    345: #define POINTER_TO_INT(p) ((int)(long)(p))
                    346: 
                    347: static void float_formatter(
                    348:     GtkTreeViewColumn * tree_column ATTRIBUTE_UNUSED,
                    349:     GtkCellRenderer * cell,
                    350:     GtkTreeModel * tree_model,
                    351:     GtkTreeIter * iter,
                    352:     gpointer data)
                    353: {
                    354:     gfloat f;
                    355:     gchar text[64];
                    356:     gtk_tree_model_get(tree_model, iter, POINTER_TO_INT(data), &f, -1);
                    357:     sprintf(text, "%.2f", f);
                    358:     g_object_set(cell, "text", text, NULL);
                    359: }
                    360: 
                    361: static void percent_formatter(
                    362:     GtkTreeViewColumn * tree_column ATTRIBUTE_UNUSED,
                    363:     GtkCellRenderer * cell,
                    364:     GtkTreeModel * tree_model,
                    365:     GtkTreeIter * iter,
                    366:     gpointer data)
                    367: {
                    368:     gfloat f;
                    369:     gchar text[64];
                    370:     gtk_tree_model_get(tree_model, iter, POINTER_TO_INT(data), &f, -1);
                    371:     sprintf(text, "%.1f%%", f);
                    372:     g_object_set(cell, "text", text, NULL);
                    373: }
                    374: 
                    375: static void TreeViewCreate(
                    376:     struct mtr_ctl *ctl)
                    377: {
                    378:     GtkCellRenderer *renderer;
                    379:     GtkTreeViewColumn *column;
                    380: 
                    381:     ReportStore = gtk_list_store_new(N_COLS,
                    382: #ifdef HAVE_IPINFO
                    383:                                      G_TYPE_STRING,
                    384: #endif
                    385:                                      G_TYPE_STRING,
                    386:                                      G_TYPE_FLOAT,
                    387:                                      G_TYPE_INT,
                    388:                                      G_TYPE_INT,
                    389:                                      G_TYPE_INT,
                    390:                                      G_TYPE_INT,
                    391:                                      G_TYPE_INT,
                    392:                                      G_TYPE_INT,
                    393:                                      G_TYPE_FLOAT, G_TYPE_STRING);
                    394: 
                    395:     ReportTreeView =
                    396:         gtk_tree_view_new_with_model(GTK_TREE_MODEL(ReportStore));
                    397: 
                    398:     g_signal_connect(GTK_OBJECT(ReportTreeView), "button_press_event",
                    399:                      G_CALLBACK(ReportTreeView_clicked), ctl);
                    400: 
                    401: #ifdef HAVE_IPINFO
                    402:     if (is_printii(ctl)) {
                    403:         renderer = gtk_cell_renderer_text_new();
                    404:         column = gtk_tree_view_column_new_with_attributes("ASN",
                    405:                                                           renderer,
                    406:                                                           "text", COL_ASN,
                    407:                                                           "foreground",
                    408:                                                           COL_COLOR, NULL);
                    409:         gtk_tree_view_column_set_resizable(column, TRUE);
                    410:         gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    411:     }
                    412: #endif
                    413: 
                    414:     renderer = gtk_cell_renderer_text_new();
                    415:     column = gtk_tree_view_column_new_with_attributes("Hostname",
                    416:                                                       renderer,
                    417:                                                       "text", COL_HOSTNAME,
                    418:                                                       "foreground",
                    419:                                                       COL_COLOR, NULL);
                    420:     gtk_tree_view_column_set_expand(column, TRUE);
                    421:     gtk_tree_view_column_set_resizable(column, TRUE);
                    422:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    423: 
                    424:     renderer = gtk_cell_renderer_text_new();
                    425:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    426:     column = gtk_tree_view_column_new_with_attributes("Loss",
                    427:                                                       renderer,
                    428:                                                       "text", COL_LOSS,
                    429:                                                       "foreground",
                    430:                                                       COL_COLOR, NULL);
                    431:     gtk_tree_view_column_set_resizable(column, TRUE);
                    432:     gtk_tree_view_column_set_cell_data_func(column, renderer,
                    433:                                             percent_formatter,
                    434:                                             (void *) COL_LOSS, NULL);
                    435:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    436: 
                    437:     renderer = gtk_cell_renderer_text_new();
                    438:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    439:     column = gtk_tree_view_column_new_with_attributes("Snt",
                    440:                                                       renderer,
                    441:                                                       "text", COL_SNT,
                    442:                                                       "foreground",
                    443:                                                       COL_COLOR, NULL);
                    444:     gtk_tree_view_column_set_resizable(column, TRUE);
                    445:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    446: 
                    447:     renderer = gtk_cell_renderer_text_new();
                    448:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    449:     column = gtk_tree_view_column_new_with_attributes("Last",
                    450:                                                       renderer,
                    451:                                                       "text", COL_LAST,
                    452:                                                       "foreground",
                    453:                                                       COL_COLOR, NULL);
                    454:     gtk_tree_view_column_set_resizable(column, TRUE);
                    455:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    456: 
                    457:     renderer = gtk_cell_renderer_text_new();
                    458:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    459:     column = gtk_tree_view_column_new_with_attributes("Avg",
                    460:                                                       renderer,
                    461:                                                       "text", COL_AVG,
                    462:                                                       "foreground",
                    463:                                                       COL_COLOR, NULL);
                    464:     gtk_tree_view_column_set_resizable(column, TRUE);
                    465:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    466: 
                    467:     renderer = gtk_cell_renderer_text_new();
                    468:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    469:     column = gtk_tree_view_column_new_with_attributes("Best",
                    470:                                                       renderer,
                    471:                                                       "text", COL_BEST,
                    472:                                                       "foreground",
                    473:                                                       COL_COLOR, NULL);
                    474:     gtk_tree_view_column_set_resizable(column, TRUE);
                    475:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    476: 
                    477:     renderer = gtk_cell_renderer_text_new();
                    478:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    479:     column = gtk_tree_view_column_new_with_attributes("Worst",
                    480:                                                       renderer,
                    481:                                                       "text", COL_WORST,
                    482:                                                       "foreground",
                    483:                                                       COL_COLOR, NULL);
                    484:     gtk_tree_view_column_set_resizable(column, TRUE);
                    485:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    486: 
                    487:     renderer = gtk_cell_renderer_text_new();
                    488:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    489:     column = gtk_tree_view_column_new_with_attributes("StDev",
                    490:                                                       renderer,
                    491:                                                       "text", COL_STDEV,
                    492:                                                       "foreground",
                    493:                                                       COL_COLOR, NULL);
                    494:     gtk_tree_view_column_set_resizable(column, TRUE);
                    495:     gtk_tree_view_column_set_cell_data_func(column, renderer,
                    496:                                             float_formatter,
                    497:                                             (void *) COL_STDEV, NULL);
                    498:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    499: 
                    500: }
                    501: 
                    502: static void update_tree_row(
                    503:     struct mtr_ctl *ctl,
                    504:     int row,
                    505:     GtkTreeIter * iter)
                    506: {
                    507:     ip_t *addr;
                    508:     char str[256] = "???", *name = str;
                    509: 
                    510:     addr = net_addr(row);
                    511:     if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) {
                    512:         if ((name = dns_lookup(ctl, addr))) {
                    513:             if (ctl->show_ips) {
                    514:                 snprintf(str, sizeof(str), "%s (%s)", name,
                    515:                          strlongip(ctl, addr));
                    516:                 name = str;
                    517:             }
                    518:         } else
                    519:             name = strlongip(ctl, addr);
                    520:     }
                    521: 
                    522:     gtk_list_store_set(ReportStore, iter,
                    523:                        COL_HOSTNAME, name,
                    524:                        COL_LOSS, (float) (net_loss(row) / 1000.0),
                    525:                        COL_RCV, net_returned(row),
                    526:                        COL_SNT, net_xmit(row),
                    527:                        COL_LAST, net_last(row) / 1000,
                    528:                        COL_BEST, net_best(row) / 1000,
                    529:                        COL_AVG, net_avg(row) / 1000,
                    530:                        COL_WORST, net_worst(row) / 1000,
                    531:                        COL_STDEV, (float) (net_stdev(row) / 1000.0),
                    532:                        COL_COLOR, net_up(row) ? NULL : "red", -1);
                    533: #ifdef HAVE_IPINFO
                    534:     if (is_printii(ctl))
                    535:         gtk_list_store_set(ReportStore, iter, COL_ASN,
                    536:                            fmt_ipinfo(ctl, addr), -1);
                    537: #endif
                    538: }
                    539: 
                    540: void gtk_redraw(
                    541:     struct mtr_ctl *ctl)
                    542: {
                    543:     int max = net_max(ctl);
                    544: 
                    545:     GtkTreeIter iter;
                    546:     int row = net_min(ctl);
                    547:     gboolean valid;
                    548: 
                    549:     valid =
                    550:         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ReportStore), &iter);
                    551: 
                    552:     while (valid) {
                    553:         if (row < max) {
                    554:             update_tree_row(ctl, row++, &iter);
                    555:             valid =
                    556:                 gtk_tree_model_iter_next(GTK_TREE_MODEL(ReportStore),
                    557:                                          &iter);
                    558:         } else {
                    559:             valid = gtk_list_store_remove(ReportStore, &iter);
                    560:         }
                    561:     }
                    562:     while (row < max) {
                    563:         gtk_list_store_append(ReportStore, &iter);
                    564:         update_tree_row(ctl, row++, &iter);
                    565:     }
                    566: }
                    567: 
                    568: 
                    569: static void Window_fill(
                    570:     struct mtr_ctl *ctl,
                    571:     GtkWidget * Window)
                    572: {
                    573:     GtkWidget *VBox;
                    574:     GtkWidget *Toolbar;
                    575:     GtkWidget *scroll;
                    576: 
                    577:     gtk_window_set_title(GTK_WINDOW(Window), "My traceroute");
                    578:     gtk_window_set_default_size(GTK_WINDOW(Window), 650, 400);
                    579:     gtk_container_set_border_width(GTK_CONTAINER(Window), 10);
                    580:     VBox = gtk_vbox_new(FALSE, 10);
                    581: 
                    582:     Toolbar = gtk_hbox_new(FALSE, 10);
                    583:     Toolbar_fill(ctl, Toolbar);
                    584:     gtk_box_pack_start(GTK_BOX(VBox), Toolbar, FALSE, FALSE, 0);
                    585: 
                    586:     TreeViewCreate(ctl);
                    587:     scroll = gtk_scrolled_window_new(NULL, NULL);
                    588:     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
                    589:                                    GTK_POLICY_AUTOMATIC,
                    590:                                    GTK_POLICY_AUTOMATIC);
                    591:     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
                    592:                                         GTK_SHADOW_IN);
                    593:     gtk_container_add(GTK_CONTAINER(scroll), ReportTreeView);
                    594:     gtk_box_pack_start(GTK_BOX(VBox), scroll, TRUE, TRUE, 0);
                    595: 
                    596:     gtk_container_add(GTK_CONTAINER(Window), VBox);
                    597: }
                    598: 
                    599: 
                    600: void gtk_open(
                    601:     struct mtr_ctl *ctl)
                    602: {
                    603:     GdkPixbuf *icon;
                    604:     int argc = 1;
                    605:     char *args[2];
                    606:     char **argv;
                    607: 
                    608:     argv = args;
                    609:     argv[0] = xstrdup("");
                    610:     argv[1] = NULL;
                    611:     gtk_do_init(&argc, &argv);
                    612:     free(argv[0]);
                    613: 
                    614:     icon = gdk_pixbuf_new_from_xpm_data((const char **) mtr_icon);
                    615:     gtk_window_set_default_icon(icon);
                    616: 
                    617:     main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
                    618: 
                    619:     g_set_application_name("My traceroute");
                    620: 
                    621:     Window_fill(ctl, main_window);
                    622: 
                    623:     g_signal_connect(GTK_OBJECT(main_window), "delete_event",
                    624:                      GTK_SIGNAL_FUNC(Window_destroy), NULL);
                    625:     g_signal_connect(GTK_OBJECT(main_window), "destroy",
                    626:                      GTK_SIGNAL_FUNC(Window_destroy), NULL);
                    627: 
                    628:     gtk_widget_show_all(main_window);
                    629: }
                    630: 
                    631: 
                    632: void gtk_close(
                    633:     void)
                    634: {
                    635: }
                    636: 
                    637: 
                    638: int gtk_keyaction(
                    639:     void)
                    640: {
                    641:     return 0;
                    642: }
                    643: 
                    644: 
                    645: static gint gtk_ping(
                    646:     gpointer data)
                    647: {
                    648:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    649: 
                    650:     gtk_redraw(ctl);
                    651:     net_send_batch(ctl);
                    652:     net_harvest_fds(ctl);
                    653:     g_source_remove(ping_timeout_timer);
                    654:     gtk_add_ping_timeout(ctl);
                    655:     return TRUE;
                    656: }
                    657: 
                    658: 
                    659: static gboolean gtk_net_data(
                    660:     ATTRIBUTE_UNUSED GIOChannel * channel,
                    661:     ATTRIBUTE_UNUSED GIOCondition cond,
                    662:     gpointer data)
                    663: {
                    664:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    665: 
                    666:     net_process_return(ctl);
                    667:     return TRUE;
                    668: }
                    669: 
                    670: 
                    671: static gboolean gtk_dns_data(
                    672:     ATTRIBUTE_UNUSED GIOChannel * channel,
                    673:     ATTRIBUTE_UNUSED GIOCondition cond,
                    674:     gpointer data)
                    675: {
                    676:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    677: 
                    678:     dns_ack(ctl);
                    679:     gtk_redraw(ctl);
                    680:     return TRUE;
                    681: }
                    682: 
                    683: #ifdef ENABLE_IPV6
                    684: static gboolean gtk_dns_data6(
                    685:     ATTRIBUTE_UNUSED GIOChannel * channel,
                    686:     ATTRIBUTE_UNUSED GIOCondition cond,
                    687:     gpointer data)
                    688: {
                    689:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    690: 
                    691:     dns_ack6();
                    692:     gtk_redraw(ctl);
                    693:     return TRUE;
                    694: }
                    695: #endif
                    696: 
                    697: 
                    698: void gtk_loop(
                    699:     struct mtr_ctl *ctl)
                    700: {
                    701:     GIOChannel *net_iochannel, *dns_iochannel;
                    702: 
                    703:     gtk_add_ping_timeout(ctl);
                    704: 
                    705:     net_iochannel = g_io_channel_unix_new(net_waitfd());
                    706:     g_io_add_watch(net_iochannel, G_IO_IN, gtk_net_data, ctl);
                    707: #ifdef ENABLE_IPV6
                    708:     if (dns_waitfd6() > 0) {
                    709:         dns_iochannel = g_io_channel_unix_new(dns_waitfd6());
                    710:         g_io_add_watch(dns_iochannel, G_IO_IN, gtk_dns_data6, ctl);
                    711:     }
                    712: #endif
                    713:     dns_iochannel = g_io_channel_unix_new(dns_waitfd());
                    714:     g_io_add_watch(dns_iochannel, G_IO_IN, gtk_dns_data, ctl);
                    715: 
                    716:     gtk_main();
                    717: }
                    718: 
                    719: static gboolean NewDestination_activate(
                    720:     GtkWidget * widget ATTRIBUTE_UNUSED,
                    721:     gpointer data)
                    722: {
                    723:     gchar *hostname;
                    724:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    725:     GtkTreePath *path = (GtkTreePath *) ctl->gtk_data;
                    726: 
                    727:     hostname = getSelectedHost(path);
                    728:     if (hostname) {
                    729:         ctl->gtk_data = hostname;
                    730:         gtk_entry_set_text(GTK_ENTRY(Entry), hostname);
                    731:         Host_activate(Entry, ctl);
                    732:         g_free(hostname);
                    733:     }
                    734:     return TRUE;
                    735: }
                    736: 
                    737: 
                    738: static gboolean Copy_activate(
                    739:     GtkWidget * widget ATTRIBUTE_UNUSED,
                    740:     gpointer data)
                    741: {
                    742:     gchar *hostname;
                    743:     GtkTreePath *path = (GtkTreePath *) data;
                    744: 
                    745:     hostname = getSelectedHost(path);
                    746:     if (hostname != NULL) {
                    747:         GtkClipboard *clipboard;
                    748: 
                    749:         clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
                    750:         gtk_clipboard_set_text(clipboard, hostname, -1);
                    751: 
                    752:         clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
                    753:         gtk_clipboard_set_text(clipboard, hostname, -1);
                    754: 
                    755:         g_free(hostname);
                    756:     }
                    757: 
                    758:     return TRUE;
                    759: }
                    760: 
                    761: static gchar *getSelectedHost(
                    762:     GtkTreePath * path)
                    763: {
                    764:     GtkTreeIter iter;
                    765:     gchar *name = NULL;
                    766: 
                    767:     if (gtk_tree_model_get_iter(GTK_TREE_MODEL(ReportStore), &iter, path)) {
                    768:         gtk_tree_model_get(GTK_TREE_MODEL(ReportStore), &iter,
                    769:                            COL_HOSTNAME, &name, -1);
                    770:     }
                    771:     gtk_tree_path_free(path);
                    772:     return name;
                    773: }
                    774: 
                    775: 
                    776: static gboolean ReportTreeView_clicked(
                    777:     GtkWidget * Tree ATTRIBUTE_UNUSED,
                    778:     GdkEventButton * event,
                    779:     gpointer data)
                    780: {
                    781:     GtkWidget *popup_menu;
                    782:     GtkWidget *copy_item;
                    783:     GtkWidget *newdestination_item;
                    784:     GtkTreePath *path;
                    785:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    786: 
                    787:     if (event->type != GDK_BUTTON_PRESS || event->button != 3)
                    788:         return FALSE;
                    789: 
                    790:     if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(ReportTreeView),
                    791:                                        event->x, event->y, &path, NULL,
                    792:                                        NULL, NULL))
                    793:         return FALSE;
                    794: 
                    795:     gtk_tree_view_set_cursor(GTK_TREE_VIEW(ReportTreeView), path, NULL,
                    796:                              FALSE);
                    797: 
                    798:     /* Single right click: prepare and show the popup menu */
                    799:     popup_menu = gtk_menu_new();
                    800: 
                    801:     copy_item = gtk_menu_item_new_with_label("Copy to clipboard");
                    802:     newdestination_item =
                    803:         gtk_menu_item_new_with_label("Set as new destination");
                    804: 
                    805:     gtk_menu_append(GTK_MENU(popup_menu), copy_item);
                    806:     gtk_menu_append(GTK_MENU(popup_menu), newdestination_item);
                    807: 
                    808:     g_signal_connect(GTK_OBJECT(copy_item), "activate",
                    809:                      GTK_SIGNAL_FUNC(Copy_activate), path);
                    810: 
                    811:     ctl->gtk_data = path;
                    812:     g_signal_connect(GTK_OBJECT(newdestination_item), "activate",
                    813:                      GTK_SIGNAL_FUNC(NewDestination_activate), ctl);
                    814: 
                    815:     gtk_widget_show(copy_item);
                    816:     gtk_widget_show(newdestination_item);
                    817: 
                    818:     gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL, NULL, NULL,
                    819:                    0, event->time);
                    820:     return TRUE;
                    821: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>