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