Annotation of embedaddon/mtr/ui/gtk.c, revision 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>