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

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: 
1.1.1.2 ! misho      15:     You should have received a copy of the GNU General Public License along
        !            16:     with this program; if not, write to the Free Software Foundation, Inc.,
        !            17:     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1       misho      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",
1.1.1.2 ! misho     201:                           "website", "https://www.bitwizard.nl/mtr/",
1.1       misho     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: 
1.1.1.2 ! misho     275:     Button = gtk_button_new_with_label("Quit");
1.1       misho     276:     gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
1.1.1.2 ! misho     277:     g_signal_connect(G_OBJECT(Button), "clicked",
        !           278:                      G_CALLBACK(Window_destroy), NULL);
1.1       misho     279: 
1.1.1.2 ! misho     280:     Button = gtk_button_new_with_label("About");
1.1       misho     281:     gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
1.1.1.2 ! misho     282:     g_signal_connect(G_OBJECT(Button), "clicked",
        !           283:                      G_CALLBACK(About_clicked), NULL);
1.1       misho     284: 
                    285:     Button = gtk_button_new_with_mnemonic("_Restart");
                    286:     gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
1.1.1.2 ! misho     287:     g_signal_connect(G_OBJECT(Button), "clicked",
        !           288:                      G_CALLBACK(Restart_clicked), ctl);
1.1       misho     289: 
                    290:     Pause_Button = gtk_toggle_button_new_with_mnemonic("_Pause");
                    291:     gtk_box_pack_end(GTK_BOX(Toolbar), Pause_Button, FALSE, FALSE, 0);
1.1.1.2 ! misho     292:     g_signal_connect(G_OBJECT(Pause_Button), "clicked",
        !           293:                      G_CALLBACK(Pause_clicked), ctl);
1.1       misho     294: 
                    295:     /* allow root only to set zero delay */
                    296:     Adjustment = (GtkAdjustment *) gtk_adjustment_new(ctl->WaitTime,
1.1.1.2 ! misho     297:                                                       running_as_root() ? 0.01 : 1.00,
1.1       misho     298:                                                       999.99, 1.0, 10.0,
                    299:                                                       0.0);
                    300:     Button = gtk_spin_button_new(Adjustment, 0.5, 2);
                    301:     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(Button), TRUE);
                    302:     gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0);
                    303:     ctl->gtk_data = Button;
1.1.1.2 ! misho     304:     g_signal_connect(G_OBJECT(Adjustment), "value_changed",
        !           305:                      G_CALLBACK(WaitTime_changed), ctl);
1.1       misho     306: 
                    307:     Label = gtk_label_new_with_mnemonic("_Hostname:");
                    308:     gtk_box_pack_start(GTK_BOX(Toolbar), Label, FALSE, FALSE, 0);
                    309: 
                    310:     Entry = gtk_entry_new();
                    311:     gtk_entry_set_text(GTK_ENTRY(Entry), ctl->Hostname);
1.1.1.2 ! misho     312:     g_signal_connect(G_OBJECT(Entry), "activate",
        !           313:                      G_CALLBACK(Host_activate), ctl);
1.1       misho     314:     gtk_box_pack_start(GTK_BOX(Toolbar), Entry, TRUE, TRUE, 0);
                    315: 
                    316:     gtk_label_set_mnemonic_widget(GTK_LABEL(Label), Entry);
                    317: }
                    318: 
                    319: static GtkWidget *ReportTreeView;
                    320: static GtkListStore *ReportStore;
                    321: 
                    322: enum {
                    323: #ifdef HAVE_IPINFO
                    324:     COL_ASN,
                    325: #endif
                    326:     COL_HOSTNAME,
                    327:     COL_LOSS,
                    328:     COL_RCV,
                    329:     COL_SNT,
                    330:     COL_LAST,
                    331:     COL_BEST,
                    332:     COL_AVG,
                    333:     COL_WORST,
                    334:     COL_STDEV,
                    335:     COL_COLOR,
                    336:     N_COLS
                    337: };
                    338: 
                    339: /* Trick to cast a pointer to integer.  We are mis-using a pointer as a
                    340:    single integer.  On 64-bit architectures, the pointer is 64 bits and the
                    341:    integer only 32.  The compiler warns us of loss of precision.  However we
                    342:    know we casted a normal 32-bit integer into this pointer a few
                    343:    microseconds earlier, so it is ok.  Nothing to worry about.  */
                    344: #define POINTER_TO_INT(p) ((int)(long)(p))
                    345: 
                    346: static void float_formatter(
                    347:     GtkTreeViewColumn * tree_column ATTRIBUTE_UNUSED,
                    348:     GtkCellRenderer * cell,
                    349:     GtkTreeModel * tree_model,
                    350:     GtkTreeIter * iter,
                    351:     gpointer data)
                    352: {
                    353:     gfloat f;
                    354:     gchar text[64];
                    355:     gtk_tree_model_get(tree_model, iter, POINTER_TO_INT(data), &f, -1);
                    356:     sprintf(text, "%.2f", f);
                    357:     g_object_set(cell, "text", text, NULL);
                    358: }
                    359: 
                    360: static void percent_formatter(
                    361:     GtkTreeViewColumn * tree_column ATTRIBUTE_UNUSED,
                    362:     GtkCellRenderer * cell,
                    363:     GtkTreeModel * tree_model,
                    364:     GtkTreeIter * iter,
                    365:     gpointer data)
                    366: {
                    367:     gfloat f;
                    368:     gchar text[64];
                    369:     gtk_tree_model_get(tree_model, iter, POINTER_TO_INT(data), &f, -1);
                    370:     sprintf(text, "%.1f%%", f);
                    371:     g_object_set(cell, "text", text, NULL);
                    372: }
                    373: 
                    374: static void TreeViewCreate(
                    375:     struct mtr_ctl *ctl)
                    376: {
                    377:     GtkCellRenderer *renderer;
                    378:     GtkTreeViewColumn *column;
                    379: 
                    380:     ReportStore = gtk_list_store_new(N_COLS,
                    381: #ifdef HAVE_IPINFO
                    382:                                      G_TYPE_STRING,
                    383: #endif
                    384:                                      G_TYPE_STRING,
                    385:                                      G_TYPE_FLOAT,
                    386:                                      G_TYPE_INT,
                    387:                                      G_TYPE_INT,
                    388:                                      G_TYPE_INT,
                    389:                                      G_TYPE_INT,
                    390:                                      G_TYPE_INT,
                    391:                                      G_TYPE_INT,
                    392:                                      G_TYPE_FLOAT, G_TYPE_STRING);
                    393: 
                    394:     ReportTreeView =
                    395:         gtk_tree_view_new_with_model(GTK_TREE_MODEL(ReportStore));
                    396: 
1.1.1.2 ! misho     397:     g_signal_connect(G_OBJECT(ReportTreeView), "button_press_event",
1.1       misho     398:                      G_CALLBACK(ReportTreeView_clicked), ctl);
                    399: 
                    400: #ifdef HAVE_IPINFO
                    401:     if (is_printii(ctl)) {
                    402:         renderer = gtk_cell_renderer_text_new();
                    403:         column = gtk_tree_view_column_new_with_attributes("ASN",
                    404:                                                           renderer,
                    405:                                                           "text", COL_ASN,
                    406:                                                           "foreground",
                    407:                                                           COL_COLOR, NULL);
                    408:         gtk_tree_view_column_set_resizable(column, TRUE);
                    409:         gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    410:     }
                    411: #endif
                    412: 
                    413:     renderer = gtk_cell_renderer_text_new();
                    414:     column = gtk_tree_view_column_new_with_attributes("Hostname",
                    415:                                                       renderer,
                    416:                                                       "text", COL_HOSTNAME,
                    417:                                                       "foreground",
                    418:                                                       COL_COLOR, NULL);
                    419:     gtk_tree_view_column_set_expand(column, TRUE);
                    420:     gtk_tree_view_column_set_resizable(column, TRUE);
                    421:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    422: 
                    423:     renderer = gtk_cell_renderer_text_new();
                    424:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    425:     column = gtk_tree_view_column_new_with_attributes("Loss",
                    426:                                                       renderer,
                    427:                                                       "text", COL_LOSS,
                    428:                                                       "foreground",
                    429:                                                       COL_COLOR, NULL);
                    430:     gtk_tree_view_column_set_resizable(column, TRUE);
                    431:     gtk_tree_view_column_set_cell_data_func(column, renderer,
                    432:                                             percent_formatter,
                    433:                                             (void *) COL_LOSS, NULL);
                    434:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    435: 
                    436:     renderer = gtk_cell_renderer_text_new();
                    437:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    438:     column = gtk_tree_view_column_new_with_attributes("Snt",
                    439:                                                       renderer,
                    440:                                                       "text", COL_SNT,
                    441:                                                       "foreground",
                    442:                                                       COL_COLOR, NULL);
                    443:     gtk_tree_view_column_set_resizable(column, TRUE);
                    444:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    445: 
                    446:     renderer = gtk_cell_renderer_text_new();
                    447:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    448:     column = gtk_tree_view_column_new_with_attributes("Last",
                    449:                                                       renderer,
                    450:                                                       "text", COL_LAST,
                    451:                                                       "foreground",
                    452:                                                       COL_COLOR, NULL);
                    453:     gtk_tree_view_column_set_resizable(column, TRUE);
                    454:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    455: 
                    456:     renderer = gtk_cell_renderer_text_new();
                    457:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    458:     column = gtk_tree_view_column_new_with_attributes("Avg",
                    459:                                                       renderer,
                    460:                                                       "text", COL_AVG,
                    461:                                                       "foreground",
                    462:                                                       COL_COLOR, NULL);
                    463:     gtk_tree_view_column_set_resizable(column, TRUE);
                    464:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    465: 
                    466:     renderer = gtk_cell_renderer_text_new();
                    467:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    468:     column = gtk_tree_view_column_new_with_attributes("Best",
                    469:                                                       renderer,
                    470:                                                       "text", COL_BEST,
                    471:                                                       "foreground",
                    472:                                                       COL_COLOR, NULL);
                    473:     gtk_tree_view_column_set_resizable(column, TRUE);
                    474:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    475: 
                    476:     renderer = gtk_cell_renderer_text_new();
                    477:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    478:     column = gtk_tree_view_column_new_with_attributes("Worst",
                    479:                                                       renderer,
                    480:                                                       "text", COL_WORST,
                    481:                                                       "foreground",
                    482:                                                       COL_COLOR, NULL);
                    483:     gtk_tree_view_column_set_resizable(column, TRUE);
                    484:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    485: 
                    486:     renderer = gtk_cell_renderer_text_new();
                    487:     g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
                    488:     column = gtk_tree_view_column_new_with_attributes("StDev",
                    489:                                                       renderer,
                    490:                                                       "text", COL_STDEV,
                    491:                                                       "foreground",
                    492:                                                       COL_COLOR, NULL);
                    493:     gtk_tree_view_column_set_resizable(column, TRUE);
                    494:     gtk_tree_view_column_set_cell_data_func(column, renderer,
                    495:                                             float_formatter,
                    496:                                             (void *) COL_STDEV, NULL);
                    497:     gtk_tree_view_append_column(GTK_TREE_VIEW(ReportTreeView), column);
                    498: 
                    499: }
                    500: 
                    501: static void update_tree_row(
                    502:     struct mtr_ctl *ctl,
                    503:     int row,
                    504:     GtkTreeIter * iter)
                    505: {
                    506:     ip_t *addr;
                    507:     char str[256] = "???", *name = str;
                    508: 
                    509:     addr = net_addr(row);
1.1.1.2 ! misho     510:     if (addrcmp(addr, &ctl->unspec_addr, ctl->af)) {
1.1       misho     511:         if ((name = dns_lookup(ctl, addr))) {
                    512:             if (ctl->show_ips) {
                    513:                 snprintf(str, sizeof(str), "%s (%s)", name,
                    514:                          strlongip(ctl, addr));
                    515:                 name = str;
                    516:             }
                    517:         } else
                    518:             name = strlongip(ctl, addr);
                    519:     }
                    520: 
                    521:     gtk_list_store_set(ReportStore, iter,
                    522:                        COL_HOSTNAME, name,
                    523:                        COL_LOSS, (float) (net_loss(row) / 1000.0),
                    524:                        COL_RCV, net_returned(row),
                    525:                        COL_SNT, net_xmit(row),
                    526:                        COL_LAST, net_last(row) / 1000,
                    527:                        COL_BEST, net_best(row) / 1000,
                    528:                        COL_AVG, net_avg(row) / 1000,
                    529:                        COL_WORST, net_worst(row) / 1000,
                    530:                        COL_STDEV, (float) (net_stdev(row) / 1000.0),
                    531:                        COL_COLOR, net_up(row) ? NULL : "red", -1);
                    532: #ifdef HAVE_IPINFO
                    533:     if (is_printii(ctl))
                    534:         gtk_list_store_set(ReportStore, iter, COL_ASN,
                    535:                            fmt_ipinfo(ctl, addr), -1);
                    536: #endif
                    537: }
                    538: 
                    539: void gtk_redraw(
                    540:     struct mtr_ctl *ctl)
                    541: {
                    542:     int max = net_max(ctl);
                    543: 
                    544:     GtkTreeIter iter;
                    545:     int row = net_min(ctl);
                    546:     gboolean valid;
                    547: 
                    548:     valid =
                    549:         gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ReportStore), &iter);
                    550: 
                    551:     while (valid) {
                    552:         if (row < max) {
                    553:             update_tree_row(ctl, row++, &iter);
                    554:             valid =
                    555:                 gtk_tree_model_iter_next(GTK_TREE_MODEL(ReportStore),
                    556:                                          &iter);
                    557:         } else {
                    558:             valid = gtk_list_store_remove(ReportStore, &iter);
                    559:         }
                    560:     }
                    561:     while (row < max) {
                    562:         gtk_list_store_append(ReportStore, &iter);
                    563:         update_tree_row(ctl, row++, &iter);
                    564:     }
                    565: }
                    566: 
1.1.1.2 ! misho     567: // GTK 3 has changed the interface a bit. Here a few defines so that we can
        !           568: // work with GTK2 or GTK3 as required. 
        !           569: #ifdef HAVE_GTK3
        !           570: #define gtk_vbox_new_(orientation,sz) gtk_box_new(orientation, sz)
        !           571: #define gtk_hbox_new_(orientation,sz) gtk_box_new(orientation, sz)
        !           572: #else
        !           573: #define gtk_vbox_new_(orientation,sz) gtk_vbox_new(FALSE, sz)
        !           574: #define gtk_hbox_new_(orientation,sz) gtk_hbox_new(FALSE, sz)
        !           575: #endif
1.1       misho     576: 
                    577: static void Window_fill(
                    578:     struct mtr_ctl *ctl,
                    579:     GtkWidget * Window)
                    580: {
                    581:     GtkWidget *VBox;
                    582:     GtkWidget *Toolbar;
                    583:     GtkWidget *scroll;
                    584: 
                    585:     gtk_window_set_title(GTK_WINDOW(Window), "My traceroute");
                    586:     gtk_window_set_default_size(GTK_WINDOW(Window), 650, 400);
                    587:     gtk_container_set_border_width(GTK_CONTAINER(Window), 10);
                    588: 
1.1.1.2 ! misho     589:     VBox    = gtk_vbox_new_(GTK_ORIENTATION_VERTICAL,   10);
        !           590:     Toolbar = gtk_hbox_new_(GTK_ORIENTATION_HORIZONTAL, 10);
        !           591: 
1.1       misho     592:     Toolbar_fill(ctl, Toolbar);
                    593:     gtk_box_pack_start(GTK_BOX(VBox), Toolbar, FALSE, FALSE, 0);
                    594: 
                    595:     TreeViewCreate(ctl);
                    596:     scroll = gtk_scrolled_window_new(NULL, NULL);
                    597:     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
                    598:                                    GTK_POLICY_AUTOMATIC,
                    599:                                    GTK_POLICY_AUTOMATIC);
                    600:     gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll),
                    601:                                         GTK_SHADOW_IN);
                    602:     gtk_container_add(GTK_CONTAINER(scroll), ReportTreeView);
                    603:     gtk_box_pack_start(GTK_BOX(VBox), scroll, TRUE, TRUE, 0);
                    604: 
                    605:     gtk_container_add(GTK_CONTAINER(Window), VBox);
                    606: }
                    607: 
                    608: 
                    609: void gtk_open(
                    610:     struct mtr_ctl *ctl)
                    611: {
                    612:     GdkPixbuf *icon;
                    613:     int argc = 1;
                    614:     char *args[2];
                    615:     char **argv;
                    616: 
                    617:     argv = args;
                    618:     argv[0] = xstrdup("");
                    619:     argv[1] = NULL;
                    620:     gtk_do_init(&argc, &argv);
                    621:     free(argv[0]);
                    622: 
                    623:     icon = gdk_pixbuf_new_from_xpm_data((const char **) mtr_icon);
                    624:     gtk_window_set_default_icon(icon);
                    625: 
                    626:     main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
                    627: 
                    628:     g_set_application_name("My traceroute");
                    629: 
                    630:     Window_fill(ctl, main_window);
                    631: 
1.1.1.2 ! misho     632:     g_signal_connect(G_OBJECT(main_window), "delete_event",
        !           633:                      G_CALLBACK(Window_destroy), NULL);
        !           634:     g_signal_connect(G_OBJECT(main_window), "destroy",
        !           635:                      G_CALLBACK(Window_destroy), NULL);
1.1       misho     636: 
                    637:     gtk_widget_show_all(main_window);
                    638: }
                    639: 
                    640: 
                    641: void gtk_close(
                    642:     void)
                    643: {
                    644: }
                    645: 
                    646: 
                    647: int gtk_keyaction(
                    648:     void)
                    649: {
                    650:     return 0;
                    651: }
                    652: 
                    653: 
                    654: static gint gtk_ping(
                    655:     gpointer data)
                    656: {
                    657:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    658: 
                    659:     gtk_redraw(ctl);
                    660:     net_send_batch(ctl);
                    661:     net_harvest_fds(ctl);
                    662:     g_source_remove(ping_timeout_timer);
                    663:     gtk_add_ping_timeout(ctl);
                    664:     return TRUE;
                    665: }
                    666: 
                    667: 
                    668: static gboolean gtk_net_data(
                    669:     ATTRIBUTE_UNUSED GIOChannel * channel,
                    670:     ATTRIBUTE_UNUSED GIOCondition cond,
                    671:     gpointer data)
                    672: {
                    673:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    674: 
                    675:     net_process_return(ctl);
                    676:     return TRUE;
                    677: }
                    678: 
                    679: 
                    680: static gboolean gtk_dns_data(
                    681:     ATTRIBUTE_UNUSED GIOChannel * channel,
                    682:     ATTRIBUTE_UNUSED GIOCondition cond,
                    683:     gpointer data)
                    684: {
                    685:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    686: 
                    687:     dns_ack(ctl);
                    688:     gtk_redraw(ctl);
                    689:     return TRUE;
                    690: }
                    691: 
                    692: #ifdef ENABLE_IPV6
                    693: static gboolean gtk_dns_data6(
                    694:     ATTRIBUTE_UNUSED GIOChannel * channel,
                    695:     ATTRIBUTE_UNUSED GIOCondition cond,
                    696:     gpointer data)
                    697: {
                    698:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    699: 
                    700:     dns_ack6();
                    701:     gtk_redraw(ctl);
                    702:     return TRUE;
                    703: }
                    704: #endif
                    705: 
                    706: 
                    707: void gtk_loop(
                    708:     struct mtr_ctl *ctl)
                    709: {
                    710:     GIOChannel *net_iochannel, *dns_iochannel;
                    711: 
                    712:     gtk_add_ping_timeout(ctl);
                    713: 
                    714:     net_iochannel = g_io_channel_unix_new(net_waitfd());
                    715:     g_io_add_watch(net_iochannel, G_IO_IN, gtk_net_data, ctl);
                    716: #ifdef ENABLE_IPV6
                    717:     if (dns_waitfd6() > 0) {
                    718:         dns_iochannel = g_io_channel_unix_new(dns_waitfd6());
                    719:         g_io_add_watch(dns_iochannel, G_IO_IN, gtk_dns_data6, ctl);
                    720:     }
                    721: #endif
                    722:     dns_iochannel = g_io_channel_unix_new(dns_waitfd());
                    723:     g_io_add_watch(dns_iochannel, G_IO_IN, gtk_dns_data, ctl);
                    724: 
                    725:     gtk_main();
                    726: }
                    727: 
                    728: static gboolean NewDestination_activate(
                    729:     GtkWidget * widget ATTRIBUTE_UNUSED,
                    730:     gpointer data)
                    731: {
                    732:     gchar *hostname;
                    733:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    734:     GtkTreePath *path = (GtkTreePath *) ctl->gtk_data;
                    735: 
                    736:     hostname = getSelectedHost(path);
                    737:     if (hostname) {
                    738:         ctl->gtk_data = hostname;
                    739:         gtk_entry_set_text(GTK_ENTRY(Entry), hostname);
                    740:         Host_activate(Entry, ctl);
                    741:         g_free(hostname);
                    742:     }
                    743:     return TRUE;
                    744: }
                    745: 
                    746: 
                    747: static gboolean Copy_activate(
                    748:     GtkWidget * widget ATTRIBUTE_UNUSED,
                    749:     gpointer data)
                    750: {
                    751:     gchar *hostname;
                    752:     GtkTreePath *path = (GtkTreePath *) data;
                    753: 
                    754:     hostname = getSelectedHost(path);
                    755:     if (hostname != NULL) {
                    756:         GtkClipboard *clipboard;
                    757: 
                    758:         clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
                    759:         gtk_clipboard_set_text(clipboard, hostname, -1);
                    760: 
                    761:         clipboard = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
                    762:         gtk_clipboard_set_text(clipboard, hostname, -1);
                    763: 
                    764:         g_free(hostname);
                    765:     }
                    766: 
                    767:     return TRUE;
                    768: }
                    769: 
                    770: static gchar *getSelectedHost(
                    771:     GtkTreePath * path)
                    772: {
                    773:     GtkTreeIter iter;
                    774:     gchar *name = NULL;
                    775: 
                    776:     if (gtk_tree_model_get_iter(GTK_TREE_MODEL(ReportStore), &iter, path)) {
                    777:         gtk_tree_model_get(GTK_TREE_MODEL(ReportStore), &iter,
                    778:                            COL_HOSTNAME, &name, -1);
                    779:     }
                    780:     gtk_tree_path_free(path);
                    781:     return name;
                    782: }
                    783: 
                    784: 
                    785: static gboolean ReportTreeView_clicked(
                    786:     GtkWidget * Tree ATTRIBUTE_UNUSED,
                    787:     GdkEventButton * event,
                    788:     gpointer data)
                    789: {
                    790:     GtkWidget *popup_menu;
                    791:     GtkWidget *copy_item;
                    792:     GtkWidget *newdestination_item;
                    793:     GtkTreePath *path;
                    794:     struct mtr_ctl *ctl = (struct mtr_ctl *) data;
                    795: 
                    796:     if (event->type != GDK_BUTTON_PRESS || event->button != 3)
                    797:         return FALSE;
                    798: 
                    799:     if (!gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(ReportTreeView),
                    800:                                        event->x, event->y, &path, NULL,
                    801:                                        NULL, NULL))
                    802:         return FALSE;
                    803: 
                    804:     gtk_tree_view_set_cursor(GTK_TREE_VIEW(ReportTreeView), path, NULL,
                    805:                              FALSE);
                    806: 
                    807:     /* Single right click: prepare and show the popup menu */
                    808:     popup_menu = gtk_menu_new();
                    809: 
                    810:     copy_item = gtk_menu_item_new_with_label("Copy to clipboard");
                    811:     newdestination_item =
                    812:         gtk_menu_item_new_with_label("Set as new destination");
                    813: 
1.1.1.2 ! misho     814:     gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu), copy_item);
        !           815:     gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu), newdestination_item);
1.1       misho     816: 
1.1.1.2 ! misho     817:     g_signal_connect(G_OBJECT(copy_item), "activate",
        !           818:                      G_CALLBACK(Copy_activate), path);
1.1       misho     819: 
                    820:     ctl->gtk_data = path;
1.1.1.2 ! misho     821:     g_signal_connect(G_OBJECT(newdestination_item), "activate",
        !           822:                      G_CALLBACK(NewDestination_activate), ctl);
1.1       misho     823: 
                    824:     gtk_widget_show(copy_item);
                    825:     gtk_widget_show(newdestination_item);
                    826: 
1.1.1.2 ! misho     827: #ifdef HAVE_GTK3
        !           828:     gtk_menu_popup_at_pointer(GTK_MENU(popup_menu), NULL);
        !           829: #else
1.1       misho     830:     gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL, NULL, NULL,
                    831:                    0, event->time);
1.1.1.2 ! misho     832: #endif
1.1       misho     833:     return TRUE;
                    834: }

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