File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / ui / gtk.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 21 14:25:31 2019 UTC (4 years, 8 months ago) by misho
Branches: mtr, MAIN
CVS tags: v0_92, HEAD
mtr ver 0.92

    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>