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