Annotation of embedaddon/mtr/gtk.c, revision 1.1.1.2
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
4: Changes/additions Copyright (C) 1998 R.E.Wolff@BitWizard.nl
5:
6: This program is free software; you can redistribute it and/or modify
7: it under the terms of the GNU General Public License version 2 as
8: published by the Free Software Foundation.
9:
10: This program is distributed in the hope that it will be useful,
11: but WITHOUT ANY WARRANTY; without even the implied warranty of
12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: GNU General Public License for more details.
14:
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:
1.1.1.2 ! misho 20: #include "config.h"
1.1 misho 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
1.1.1.2 ! misho 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: }
1.1 misho 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>