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>