File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / gtk.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:33:48 2016 UTC (7 years, 7 months ago) by misho
Branches: mtr, elwix, MAIN
CVS tags: v0_86, HEAD
mtr 0.86

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

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