update expert info LED also while doing live capturing
[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 #include "about_dlg.h"
39 #include "gui_utils.h"
40 #include "dlg_utils.h"
41 #include "file_dlg.h"
42 #include "compat_macros.h"
43 #include "globals.h"
44 #include "log.h"
45 #if GTK_MAJOR_VERSION >= 2 || GTK_MINOR_VERSION >= 3
46 #include "text_page.h"
47 #endif
48
49 #include "../image/wssplash.xpm"
50 #include "gtkglobals.h"
51 #include "version_info.h"
52 #include "main.h"
53 #include "plugins_dlg.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 #if GTK_MAJOR_VERSION >= 2
72   gchar       *message;
73 #endif
74   const char  *title = "Network Protocol Analyzer";
75
76   icon = xpm_to_widget_from_parent(parent, wssplash_xpm);
77   gtk_container_add(GTK_CONTAINER(main_vb), icon);
78
79   msg_label = gtk_label_new(title);
80 #if GTK_MAJOR_VERSION >= 2
81   message = g_strdup_printf("<span size=\"x-large\" weight=\"bold\">%s</span>", title);
82   gtk_label_set_markup(GTK_LABEL(msg_label), message);
83   g_free(message);
84 #endif
85   gtk_container_add(GTK_CONTAINER(main_vb), msg_label);
86 }
87
88 static void
89 splash_update_label(GtkWidget *win, const char *message)
90 {
91     GtkWidget *main_lb;
92
93     if (win == NULL) return;
94
95     main_lb = OBJECT_GET_DATA(win, "splash_label");
96     gtk_label_set_text(GTK_LABEL(main_lb), message);
97
98     /* Process all pending GUI events before continuing, so that
99        the splash screen window gets updated. */
100     while (gtk_events_pending()) gtk_main_iteration();
101 }
102
103 GtkWidget*
104 splash_new(const char *message)
105 {
106     GtkWidget *win;
107     GtkWidget *main_lb;
108
109     GtkWidget *main_vb;
110     GtkWidget *percentage_hb;
111     GtkWidget *prog_bar;
112     GtkWidget *percentage_lb;
113
114     win = splash_window_new();
115
116     /* When calling about_wireshark(), we must realize the top-level
117        widget for the window, otherwise GTK will throw a warning
118        because we don't have a colormap associated with that window and
119        can't handle the pixmap. */
120     gtk_widget_realize(win);
121
122     main_vb = gtk_vbox_new(FALSE, 6);
123     gtk_container_border_width(GTK_CONTAINER(main_vb), 24);
124     gtk_container_add(GTK_CONTAINER(win), main_vb);
125
126     about_wireshark(win, main_vb);
127
128     main_lb = gtk_label_new(message);
129     gtk_container_add(GTK_CONTAINER(main_vb), main_lb);
130     OBJECT_SET_DATA(win, "splash_label", main_lb);
131
132     main_lb = gtk_label_new("");
133     gtk_container_add(GTK_CONTAINER(main_vb), main_lb);
134     OBJECT_SET_DATA(win, "protocol_label", main_lb);
135
136     percentage_hb = gtk_hbox_new(FALSE, 1);
137     gtk_box_pack_start(GTK_BOX(main_vb), percentage_hb, TRUE, TRUE, 3);
138
139     prog_bar = gtk_progress_bar_new();
140 #if GTK_MAJOR_VERSION < 2
141     gtk_progress_set_activity_mode(GTK_PROGRESS(prog_bar), FALSE);
142 #endif
143     gtk_box_pack_start(GTK_BOX(percentage_hb), prog_bar, TRUE, TRUE, 3);
144     OBJECT_SET_DATA(win, "progress_bar", prog_bar);
145
146     percentage_lb = gtk_label_new("  0%");
147     gtk_misc_set_alignment(GTK_MISC(percentage_lb), 0.0, 0.0);
148     gtk_box_pack_start(GTK_BOX(percentage_hb), percentage_lb, FALSE, TRUE, 3);
149     OBJECT_SET_DATA(win, "percentage_label", percentage_lb);
150
151     gtk_widget_show_all(win);
152
153     splash_update_label(win, message);
154
155     return win;
156 }
157
158 #define REGISTER_FREQ 100 /* Milliseconds */
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 REGISTER_FREQ milliseconds */
187       ul_sofar++;
188       return;
189     }
190     memcpy(&next_tv, &cur_tv, sizeof(next_tv));
191     next_tv.tv_usec += 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 = OBJECT_GET_DATA(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 = OBJECT_GET_DATA(win, "progress_bar");
258 #if GTK_MAJOR_VERSION < 2
259     gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), percentage);
260 #else
261     gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(prog_bar), percentage);
262 #endif
263
264     percentage_lb = OBJECT_GET_DATA(win, "percentage_label");
265     g_snprintf(tmp, sizeof(tmp), "%lu%%", ul_percentage);
266     gtk_label_set_text((GtkLabel*)percentage_lb, tmp);
267
268     /* Process all pending GUI events before continuing, so that
269        the splash screen window gets updated. */
270     while (gtk_events_pending()) gtk_main_iteration();
271
272 }
273
274 guint
275 splash_destroy(GtkWidget *win)
276 {
277     if (win == NULL) return FALSE;
278
279     gtk_widget_destroy(win);
280     return FALSE;
281 }
282
283
284 static GtkWidget *
285 about_wireshark_page_new(void)
286 {
287   GtkWidget   *main_vb, *msg_label /*, *icon*/;
288   gchar       *message;
289
290   main_vb = gtk_vbox_new(FALSE, 6);
291   gtk_container_border_width(GTK_CONTAINER(main_vb), 12);
292
293   about_wireshark(top_level, main_vb);
294
295   /* Construct the message string */
296   message = g_strdup_printf(
297        "Version " VERSION "%s\n"
298        "\n"
299        "%s"
300        "\n"
301        "%s"
302        "\n"
303        "%s"
304        "\n"
305        "Wireshark is Open Source Software released under the GNU General Public License.\n"
306        "\n"
307        "Check the man page and http://www.wireshark.org for more information.",
308        wireshark_svnversion, get_copyright_info(), comp_info_str->str,
309        runtime_info_str->str);
310
311   msg_label = gtk_label_new(message);
312   g_free(message);
313   gtk_label_set_justify(GTK_LABEL(msg_label), GTK_JUSTIFY_FILL);
314 #if GTK_MAJOR_VERSION >= 2
315   gtk_label_set_selectable(GTK_LABEL(msg_label), TRUE);
316 #endif
317   gtk_container_add(GTK_CONTAINER(main_vb), msg_label);
318
319   return main_vb;
320 }
321
322 #if GTK_MAJOR_VERSION >= 2 || GTK_MINOR_VERSION >= 3
323 static GtkWidget *
324 about_authors_page_new(void)
325 {
326   GtkWidget   *page;
327   char *absolute_path;
328
329   absolute_path = get_datafile_path("AUTHORS-SHORT");
330   page = text_page_new(absolute_path);
331
332   return page;
333 }
334 #endif
335
336 static void
337 about_folders_row(GtkWidget *table, const char *label, const char *dir, const char *tip)
338 {
339   simple_list_append(table, 0, label, 1, dir, 2, tip, -1);
340 }
341
342
343 static GtkWidget *
344 about_folders_page_new(void)
345 {
346   GtkWidget   *table;
347   const char *constpath;
348   char *path;
349   const gchar *titles[] = { "Name", "Folder", "Typical Files"};
350   GtkWidget *scrolledwindow;
351
352   scrolledwindow = scrolled_window_new(NULL, NULL);
353 #if GTK_MAJOR_VERSION >= 2
354   gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow),
355                                    GTK_SHADOW_IN);
356 #endif
357
358   /* Container for our data */
359   table = simple_list_new(3, titles);
360
361   /* "file open" */
362   about_folders_row(table, "\"File\" dialogs", get_last_open_dir(),
363       "capture files");
364
365   /* temp */
366   path = get_tempfile_path("");
367   about_folders_row(table, "Temp", path,
368       "untitled capture files");
369   g_free((void *) path);
370
371   /* pers conf */
372   path = get_persconffile_path("", FALSE, FALSE);
373   about_folders_row(table, "Personal configuration", path,
374       "\"dfilters\", \"preferences\", \"ethers\", ...");
375   g_free((void *) path);
376
377   /* global conf */
378   constpath = get_datafile_dir();
379   if (constpath != NULL) {
380     about_folders_row(table, "Global configuration", constpath,
381         "\"dfilters\", \"preferences\", \"manuf\", ...");
382   }
383
384   /* system */
385   constpath = get_systemfile_dir();
386   about_folders_row(table, "System", constpath,
387       "\"ethers\", \"ipxnets\"");
388
389   /* program */
390   constpath = get_progfile_dir();
391   about_folders_row(table, "Program", constpath,
392       "program files");
393
394 #ifdef HAVE_PLUGINS
395   /* pers plugins */
396   path = get_plugins_pers_dir();
397   about_folders_row(table, "Personal Plugins", path,
398       "dissector plugins");
399   g_free((void *) path);
400
401   /* global plugins */
402   about_folders_row(table, "Global Plugins", get_plugin_dir(),
403       "dissector plugins");
404 #endif
405
406 #ifdef HAVE_LIBSMI
407   /* SMI MIBs/PIBs */
408   path = oid_get_default_mib_path();
409   about_folders_row(table, "MIB/PIB paths", path,
410       "SMI MIB/PIB search path");
411   g_free((void *) path);
412 #endif
413
414   gtk_container_add(GTK_CONTAINER(scrolledwindow), table);
415
416   return scrolledwindow;
417 }
418
419 #if GTK_MAJOR_VERSION >= 2 || GTK_MINOR_VERSION >= 3
420 static GtkWidget *
421 about_license_page_new(void)
422 {
423   GtkWidget   *page;
424   char *absolute_path;
425
426   absolute_path = get_datafile_path("COPYING");
427   page = text_page_new(absolute_path);
428
429   return page;
430 }
431 #endif
432
433 void
434 about_wireshark_cb( GtkWidget *w _U_, gpointer data _U_ )
435 {
436   GtkWidget   *main_vb, *main_nb, *bbox, *ok_btn;
437   GtkWidget   *page_lb, *about_page, *folders_page;
438
439 #ifdef HAVE_PLUGINS
440   GtkWidget   *plugins_page;
441 #endif
442
443 #if GTK_MAJOR_VERSION >= 2 || GTK_MINOR_VERSION >= 3
444   GtkWidget   *authors_page, *license_page;
445 #endif
446
447   if (about_wireshark_w != NULL) {
448     /* There's already an "About Wireshark" dialog box; reactivate it. */
449     reactivate_window(about_wireshark_w);
450     return;
451   }
452
453   /*
454    * XXX - use GtkDialog?  The GNOME 2.x GnomeAbout widget does.
455    * Should we use GtkDialog for simple_dialog() as well?  Or
456    * is the GTK+ 2.x GtkDialog appropriate but the 1.2[.x] one
457    * not?  (The GNOME 1.x GnomeAbout widget uses GnomeDialog.)
458    */
459   about_wireshark_w = dlg_window_new("About Wireshark");
460   /* set the initial position (must be done, before show is called!) */
461   /* default position is not appropriate for the about dialog */
462 #if GTK_MAJOR_VERSION >= 2
463   gtk_window_set_position(GTK_WINDOW(about_wireshark_w), GTK_WIN_POS_CENTER_ON_PARENT);
464 #else
465   gtk_window_set_position(GTK_WINDOW(about_wireshark_w), GTK_WIN_POS_CENTER);
466 #endif
467   /* setting the size is dangerous here, as making it too short will
468    * clip content on GTK1, so simply use the natural size */
469   /*gtk_window_set_default_size(GTK_WINDOW(about_wireshark_w), 600, 400);*/
470   gtk_container_border_width(GTK_CONTAINER(about_wireshark_w), 6);
471
472   main_vb = gtk_vbox_new(FALSE, 12);
473   gtk_container_border_width(GTK_CONTAINER(main_vb), 6);
474   gtk_container_add(GTK_CONTAINER(about_wireshark_w), main_vb);
475
476   main_nb = gtk_notebook_new();
477   gtk_box_pack_start(GTK_BOX(main_vb), main_nb, TRUE, TRUE, 0);
478
479   about_page = about_wireshark_page_new();
480   page_lb = gtk_label_new("Wireshark");
481   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), about_page, page_lb);
482
483 #if GTK_MAJOR_VERSION >= 2 || GTK_MINOR_VERSION >= 3
484   authors_page = about_authors_page_new();
485   page_lb = gtk_label_new("Authors");
486   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), authors_page, page_lb);
487 #endif
488
489   folders_page = about_folders_page_new();
490   page_lb = gtk_label_new("Folders");
491   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), folders_page, page_lb);
492
493 #ifdef HAVE_PLUGINS
494   plugins_page = about_plugins_page_new();
495   page_lb = gtk_label_new("Plugins");
496   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), plugins_page, page_lb);
497 #endif
498
499 #if GTK_MAJOR_VERSION >= 2 || GTK_MINOR_VERSION >= 3
500   license_page = about_license_page_new();
501   page_lb = gtk_label_new("License");
502   /* set a minmum width to avoid a lot of line breaks at the wrong places */
503   WIDGET_SET_SIZE(license_page, 600, -1);
504   gtk_notebook_append_page(GTK_NOTEBOOK(main_nb), license_page, page_lb);
505 #endif
506
507   /* Button row */
508   bbox = dlg_button_row_new(GTK_STOCK_OK, NULL);
509   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
510
511   ok_btn = OBJECT_GET_DATA(bbox, GTK_STOCK_OK);
512   gtk_widget_grab_focus(ok_btn);
513   gtk_widget_grab_default(ok_btn);
514   window_set_cancel_button(about_wireshark_w, ok_btn, window_cancel_button_cb);
515
516   SIGNAL_CONNECT(about_wireshark_w, "delete_event", window_delete_event_cb, NULL);
517   SIGNAL_CONNECT(about_wireshark_w, "destroy", about_wireshark_destroy_cb, NULL);
518
519   gtk_widget_show_all(about_wireshark_w);
520   window_present(about_wireshark_w);
521 }
522
523 static void
524 about_wireshark_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
525 {
526   /* Note that we no longer have an "About Wireshark" dialog box. */
527   about_wireshark_w = NULL;
528 }
529
530