Allow the folders in the About Wireshark/Folders list to be double clicked on to...
[obnox/wireshark/wip.git] / gtk / about_dlg.c
1 /* about_dlg.c
2  *
3  * $Id$
4  *
5  * Ulf Lamping <ulf.lamping@web.de>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 2000 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <gtk/gtk.h>
31 #include <string.h>
32
33 #include <epan/filesystem.h>
34 #include <epan/plugins.h>
35 #ifdef HAVE_LIBSMI
36 #include <epan/oids.h>
37 #endif
38
39 #include "../globals.h"
40 #include "../log.h"
41 #include "../version_info.h"
42
43 #include "gtk/about_dlg.h"
44 #include "gtk/gui_utils.h"
45 #include "gtk/dlg_utils.h"
46 #include "gtk/file_dlg.h"
47 #include "gtk/text_page_utils.h"
48 #include "gtk/gtkglobals.h"
49 #include "gtk/main.h"
50 #include "gtk/plugins_dlg.h"
51
52 #include "../image/wssplash.xpm"
53 #include "webbrowser.h"
54
55 static void about_wireshark_destroy_cb(GtkWidget *, gpointer);
56
57
58 /*
59  * Keep a static pointer to the current "About Wireshark" window, if any, so
60  * that if somebody tries to do "About Wireshark" while there's already an
61  * "About Wireshark" window up, we just pop up the existing one, rather than
62  * creating a new one.
63  */
64 static GtkWidget *about_wireshark_w;
65
66
67 static void
68 about_wireshark(GtkWidget *parent, GtkWidget *main_vb)
69 {
70   GtkWidget   *msg_label, *icon;
71   gchar       *message;
72   const char  *title = "Network Protocol Analyzer";
73
74   icon = xpm_to_widget_from_parent(parent, wssplash_xpm);
75   gtk_container_add(GTK_CONTAINER(main_vb), icon);
76
77   msg_label = gtk_label_new(title);
78   message = g_strdup_printf("<span size=\"x-large\" weight=\"bold\">%s</span>", title);
79   gtk_label_set_markup(GTK_LABEL(msg_label), message);
80   g_free(message);
81   gtk_container_add(GTK_CONTAINER(main_vb), msg_label);
82 }
83
84 static void
85 splash_update_label(GtkWidget *win, const char *message)
86 {
87     GtkWidget *main_lb;
88
89     if (win == NULL) return;
90
91     main_lb = g_object_get_data(G_OBJECT(win), "splash_label");
92     gtk_label_set_text(GTK_LABEL(main_lb), message);
93
94     /* Process all pending GUI events before continuing, so that
95        the splash screen window gets updated. */
96     while (gtk_events_pending()) gtk_main_iteration();
97 }
98
99 GtkWidget*
100 splash_new(const char *message)
101 {
102     GtkWidget *win;
103     GtkWidget *main_lb;
104
105     GtkWidget *main_vb;
106     GtkWidget *percentage_hb;
107     GtkWidget *prog_bar;
108     GtkWidget *percentage_lb;
109
110     win = splash_window_new();
111
112     /* When calling about_wireshark(), we must realize the top-level
113        widget for the window, otherwise GTK will throw a warning
114        because we don't have a colormap associated with that window and
115        can't handle the pixmap. */
116     gtk_widget_realize(win);
117
118     main_vb = gtk_vbox_new(FALSE, 6);
119     gtk_container_border_width(GTK_CONTAINER(main_vb), 24);
120     gtk_container_add(GTK_CONTAINER(win), main_vb);
121
122     about_wireshark(win, main_vb);
123
124     main_lb = gtk_label_new(message);
125     gtk_container_add(GTK_CONTAINER(main_vb), main_lb);
126     g_object_set_data(G_OBJECT(win), "splash_label", main_lb);
127
128     main_lb = gtk_label_new("");
129     gtk_container_add(GTK_CONTAINER(main_vb), main_lb);
130     g_object_set_data(G_OBJECT(win), "protocol_label", main_lb);
131
132     percentage_hb = gtk_hbox_new(FALSE, 1);
133     gtk_box_pack_start(GTK_BOX(main_vb), percentage_hb, TRUE, TRUE, 3);
134
135     prog_bar = gtk_progress_bar_new();
136     gtk_box_pack_start(GTK_BOX(percentage_hb), prog_bar, TRUE, TRUE, 3);
137     g_object_set_data(G_OBJECT(win), "progress_bar", prog_bar);
138
139     percentage_lb = gtk_label_new("  0%");
140     gtk_misc_set_alignment(GTK_MISC(percentage_lb), 0.0, 0.0);
141     gtk_box_pack_start(GTK_BOX(percentage_hb), percentage_lb, FALSE, TRUE, 3);
142     g_object_set_data(G_OBJECT(win), "percentage_label", percentage_lb);
143
144     gtk_widget_show_all(win);
145
146     splash_update_label(win, message);
147
148     return win;
149 }
150
151 #define REGISTER_FREQ 100 /* Milliseconds */
152
153 void
154 splash_update(register_action_e action, const char *message, gpointer client_data)
155 {
156     GtkWidget  *win;
157     GtkWidget  *main_lb;
158     GtkWidget  *prog_bar;
159     GtkWidget  *percentage_lb;
160     gfloat     percentage;
161     gulong     ul_percentage;
162     gchar      tmp[100];
163     const char *action_msg;
164
165     static gulong ul_sofar = 0;
166     static gulong ul_count = 0;
167
168     static register_action_e last_action = RA_NONE;
169
170     static GTimeVal cur_tv;
171     static GTimeVal next_tv = {0, 0};
172
173     win = (GtkWidget *)client_data;
174
175     if (win == NULL) return;
176
177     g_get_current_time(&cur_tv);
178     if (cur_tv.tv_sec <= next_tv.tv_sec && cur_tv.tv_usec <= next_tv.tv_usec && ul_sofar < ul_count - 1) {
179       /* Only update every REGISTER_FREQ milliseconds */
180       ul_sofar++;
181       return;
182     }
183     memcpy(&next_tv, &cur_tv, sizeof(next_tv));
184     next_tv.tv_usec += REGISTER_FREQ * 1000;
185     if (next_tv.tv_usec >= 1000000) {
186         next_tv.tv_sec++;
187         next_tv.tv_usec -= 1000000;
188     }
189
190     if(last_action != action) {
191       /* the action has changed */
192       switch(action) {
193       case RA_DISSECTORS:
194         action_msg = "Initializing dissectors ...";
195         break;
196       case RA_LISTENERS:
197         action_msg = "Initializing tap listeners ...";
198         break;
199       case RA_REGISTER:
200         action_msg = "Registering dissector ...";
201         break;
202       case RA_PLUGIN_REGISTER:
203         action_msg = "Registering plugins ...";
204         break;
205       case RA_HANDOFF:
206         action_msg = "Handing off dissector ...";
207         break;
208       case RA_PLUGIN_HANDOFF:
209         action_msg = "Handing off plugins ...";
210         break;
211       case RA_PREFERENCES:
212         action_msg = "Loading module preferences ...";
213         break;
214       case RA_CONFIGURATION:
215         action_msg = "Loading configuration files ...";
216         break;
217       default:
218         action_msg = "(Unknown action)";;
219         break;
220       }
221       splash_update_label(win, action_msg);
222       last_action = action;
223     }
224
225     if(ul_count == 0) /* get the count of dissectors */
226       ul_count = register_count() + 6; /* additional 6 for:
227                                           dissectors, listeners,
228                                           registering plugins, handingoff plugins,
229                                           preferences and configuration */
230
231     main_lb = g_object_get_data(G_OBJECT(win), "protocol_label");
232     /* make_dissector_reg.py changed -
233        so we need to strip off the leading elements to get back to the protocol */
234     if(message) {
235       if(!strncmp(message, "proto_register_", 15))
236         message += 15;
237       else if(!strncmp(message, "proto_reg_handoff_", 18))
238         message += 18;
239     }
240     gtk_label_set_text(GTK_LABEL(main_lb), message ? message : "");
241
242     ul_sofar++;
243
244     g_assert (ul_sofar <= ul_count);
245
246     percentage = (gfloat)ul_sofar/(gfloat)ul_count;
247     ul_percentage = (gulong)(percentage * 100);
248
249     /* update progress bar */
250     prog_bar = g_object_get_data(G_OBJECT(win), "progress_bar");
251     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(prog_bar), percentage);
252
253     percentage_lb = g_object_get_data(G_OBJECT(win), "percentage_label");
254     g_snprintf(tmp, sizeof(tmp), "%lu%%", ul_percentage);
255     gtk_label_set_text((GtkLabel*)percentage_lb, tmp);
256
257     /* Process all pending GUI events before continuing, so that
258        the splash screen window gets updated. */
259     while (gtk_events_pending()) gtk_main_iteration();
260
261 }
262
263 guint
264 splash_destroy(GtkWidget *win)
265 {
266     if (win == NULL) return FALSE;
267
268     gtk_widget_destroy(win);
269     return FALSE;
270 }
271
272
273 static GtkWidget *
274 about_wireshark_page_new(void)
275 {
276   GtkWidget   *main_vb, *msg_label /*, *icon*/;
277   gchar       *message;
278
279   main_vb = gtk_vbox_new(FALSE, 6);
280   gtk_container_border_width(GTK_CONTAINER(main_vb), 12);
281
282   about_wireshark(top_level, main_vb);
283
284   /* Construct the message string */
285   message = g_strdup_printf(
286        "Version " VERSION "%s\n"
287        "\n"
288        "%s"
289        "\n"
290        "%s"
291        "\n"
292        "%s"
293        "\n"
294        "Wireshark is Open Source Software released under the GNU General Public License.\n"
295        "\n"
296        "Check the man page and http://www.wireshark.org for more information.",
297        wireshark_svnversion, get_copyright_info(), comp_info_str->str,
298        runtime_info_str->str);
299
300   msg_label = gtk_label_new(message);
301   g_free(message);
302   gtk_label_set_justify(GTK_LABEL(msg_label), GTK_JUSTIFY_FILL);
303   gtk_label_set_selectable(GTK_LABEL(msg_label), TRUE);
304   gtk_container_add(GTK_CONTAINER(main_vb), msg_label);
305
306   return main_vb;
307 }
308
309 static GtkWidget *
310 about_authors_page_new(void)
311 {
312   GtkWidget   *page;
313   char *absolute_path;
314
315   absolute_path = get_datafile_path("AUTHORS-SHORT");
316   page = text_page_new(absolute_path);
317
318   return page;
319 }
320
321 static gint about_folders_callback(GtkWidget *widget, GdkEventButton *event, gint id)
322 {
323   gint row = 0, col = 0;
324   GtkTreeSelection *tree_selection;
325   GtkTreeModel *model;
326   GtkTreeIter  iter;
327   gchar        *path;
328
329   tree_selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
330
331   if(gtk_tree_selection_count_selected_rows(tree_selection) == 0)
332     return FALSE;
333
334   if(event->type != GDK_2BUTTON_PRESS)
335     /* not a double click */
336     return FALSE;
337
338   if(gtk_tree_selection_get_selected (tree_selection, &model, &iter)) {
339     gtk_tree_model_get(model, &iter, 1, &path, -1);
340     browser_open_data_file(path);
341   }
342
343   return TRUE;
344 }
345
346 static void
347 about_folders_row(GtkWidget *table, const char *label, const char *dir, const char *tip)
348 {
349   simple_list_append(table, 0, label, 1, dir, 2, tip, -1);
350 }
351
352
353 static GtkWidget *
354 about_folders_page_new(void)
355 {
356   GtkWidget   *table;
357   const char *constpath;
358   char *path;
359   const gchar *titles[] = { "Name", "Folder", "Typical Files"};
360   GtkWidget *scrolledwindow;
361 #ifdef HAVE_LIBSMI
362   gint i; 
363   gchar **resultArray;
364 #endif 
365
366   scrolledwindow = scrolled_window_new(NULL, NULL);
367   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow),
368                                    GTK_SHADOW_IN);
369
370   /* Container for our data */
371   table = simple_list_new(3, titles);
372
373   /* connect a callback so we can spot a double-click */
374   gtk_signal_connect(GTK_OBJECT(table), "button_press_event", 
375                      GTK_SIGNAL_FUNC(about_folders_callback), (gpointer)0);
376
377   simple_list_url_col(table, 1);
378
379   /* "file open" */
380   about_folders_row(table, "\"File\" dialogs", get_last_open_dir(),
381       "capture files");
382
383   /* temp */
384   path = get_tempfile_path("");
385   about_folders_row(table, "Temp", path,
386       "untitled capture files");
387   g_free((void *) path);
388
389   /* pers conf */
390   path = get_persconffile_path("", FALSE, FALSE);
391   about_folders_row(table, "Personal configuration", path,
392       "\"dfilters\", \"preferences\", \"ethers\", ...");
393   g_free((void *) path);
394
395   /* global conf */
396   constpath = get_datafile_dir();
397   if (constpath != NULL) {
398     about_folders_row(table, "Global configuration", constpath,
399         "\"dfilters\", \"preferences\", \"manuf\", ...");
400   }
401
402   /* system */
403   constpath = get_systemfile_dir();
404   about_folders_row(table, "System", constpath,
405       "\"ethers\", \"ipxnets\"");
406
407   /* program */
408   constpath = get_progfile_dir();
409   about_folders_row(table, "Program", constpath,
410       "program files");
411
412 #ifdef HAVE_PLUGINS
413   /* pers plugins */
414   path = get_plugins_pers_dir();
415   about_folders_row(table, "Personal Plugins", path,
416       "dissector plugins");
417   g_free((void *) path);
418
419   /* global plugins */
420   about_folders_row(table, "Global Plugins", get_plugin_dir(),
421       "dissector plugins");
422 #endif
423
424 #ifdef HAVE_LIBSMI
425   /* SMI MIBs/PIBs */
426   path = oid_get_default_mib_path();
427
428   resultArray = g_strsplit(path, ";", 10);
429
430   for(i = 0; resultArray[i]; i++) 
431     about_folders_row(table, "MIB/PIB path", g_strstrip(resultArray[i]),
432                       "SMI MIB/PIB search path");
433   g_strfreev(resultArray);
434   g_free((void *) path);
435 #endif
436
437   gtk_container_add(GTK_CONTAINER(scrolledwindow), table);
438
439   return scrolledwindow;
440 }
441
442 static GtkWidget *
443 about_license_page_new(void)
444 {
445   GtkWidget   *page;
446   char *absolute_path;
447
448   absolute_path = get_datafile_path("COPYING");
449   page = text_page_new(absolute_path);
450
451   return page;
452 }
453
454 void
455 about_wireshark_cb( GtkWidget *w _U_, gpointer data _U_ )
456 {
457   GtkWidget   *main_vb, *main_nb, *bbox, *ok_btn;
458   GtkWidget   *page_lb, *about_page, *folders_page;
459
460 #ifdef HAVE_PLUGINS
461   GtkWidget   *plugins_page;
462 #endif
463
464   GtkWidget   *authors_page, *license_page;
465
466   if (about_wireshark_w != NULL) {
467     /* There's already an "About Wireshark" dialog box; reactivate it. */
468     reactivate_window(about_wireshark_w);
469     return;
470   }
471
472   /*
473    * XXX - use GtkDialog?  The GNOME 2.x GnomeAbout widget does.
474    * Should we use GtkDialog for simple_dialog() as well?  Or
475    * is the GTK+ 2.x GtkDialog appropriate but the 1.2[.x] one
476    * not?  (The GNOME 1.x GnomeAbout widget uses GnomeDialog.)
477    */
478   about_wireshark_w = dlg_window_new("About Wireshark");
479   /* set the initial position (must be done, before show is called!) */
480   /* default position is not appropriate for the about dialog */
481   gtk_window_set_position(GTK_WINDOW(about_wireshark_w), GTK_WIN_POS_CENTER_ON_PARENT);
482   gtk_window_set_default_size(GTK_WINDOW(about_wireshark_w), 600, 400);
483   gtk_container_border_width(GTK_CONTAINER(about_wireshark_w), 6);
484
485   main_vb = gtk_vbox_new(FALSE, 12);
486   gtk_container_border_width(GTK_CONTAINER(main_vb), 6);
487   gtk_container_add(GTK_CONTAINER(about_wireshark_w), main_vb);
488
489   main_nb = gtk_notebook_new();
490   gtk_box_pack_start(GTK_BOX(main_vb), main_nb, TRUE, TRUE, 0);
491
492   about_page = about_wireshark_page_new();
493   page_lb = gtk_label_new("Wireshark");
494   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), about_page, page_lb);
495
496   authors_page = about_authors_page_new();
497   page_lb = gtk_label_new("Authors");
498   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), authors_page, page_lb);
499
500   folders_page = about_folders_page_new();
501   page_lb = gtk_label_new("Folders");
502   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), folders_page, page_lb);
503
504 #ifdef HAVE_PLUGINS
505   plugins_page = about_plugins_page_new();
506   page_lb = gtk_label_new("Plugins");
507   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), plugins_page, page_lb);
508 #endif
509
510   license_page = about_license_page_new();
511   page_lb = gtk_label_new("License");
512   /* set a minmum width to avoid a lot of line breaks at the wrong places */
513   gtk_widget_set_size_request(license_page, 600, -1);
514   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), license_page, page_lb);
515
516   /* Button row */
517   bbox = dlg_button_row_new(GTK_STOCK_OK, NULL);
518   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
519
520   ok_btn = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
521   gtk_widget_grab_focus(ok_btn);
522   gtk_widget_grab_default(ok_btn);
523   window_set_cancel_button(about_wireshark_w, ok_btn, window_cancel_button_cb);
524
525   g_signal_connect(about_wireshark_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
526   g_signal_connect(about_wireshark_w, "destroy", G_CALLBACK(about_wireshark_destroy_cb), NULL);
527
528   gtk_widget_show_all(about_wireshark_w);
529   window_present(about_wireshark_w);
530 }
531
532 static void
533 about_wireshark_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
534 {
535   /* Note that we no longer have an "About Wireshark" dialog box. */
536   about_wireshark_w = NULL;
537 }
538
539