7b181cecaa52f4609780d7ab1b91e88b54eee458
[obnox/wireshark/wip.git] / gtk / main_welcome.c
1 /* main_welcome.c
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #ifdef HAVE_SYS_TYPES_H
29 #include <sys/types.h>
30 #endif
31 #include <time.h>
32
33 #include <gtk/gtk.h>
34
35 #include <epan/prefs.h>
36
37 #include "../color.h"
38 #ifdef HAVE_LIBPCAP
39 #include "capture.h"
40 #include "capture-pcap-util.h"
41 #include "capture_opts.h"
42 #include "capture_ui_utils.h"
43 #endif
44 #include "simple_dialog.h"
45 #include <wsutil/file_util.h>
46
47 #include "gtk/gui_utils.h"
48 #include "gtk/color_utils.h"
49 #include "gtk/recent.h"
50 #include "gtk/gtkglobals.h"
51 #include "gtk/main.h"
52 #include "gtk/menus.h"
53 #include "gtk/main_welcome.h"
54 #include "gtk/help_dlg.h"
55 #include "gtk/capture_file_dlg.h"
56 #include "gtk/stock_icons.h"
57 #include "gtk/utf8_entities.h"
58 #ifdef HAVE_LIBPCAP
59 #include "gtk/capture_dlg.h"
60 #include "gtk/capture_if_dlg.h"
61 #include "gtk/capture_globals.h"
62 #endif
63 #include "../image/wssplash-dev.xpm"
64 #include "../version_info.h"
65
66 #ifdef _WIN32
67 #include <tchar.h>
68 #include <windows.h>
69 #endif
70
71 #ifdef HAVE_AIRPCAP
72 #include "airpcap.h"
73 #include "airpcap_loader.h"
74 #include "airpcap_gui_utils.h"
75 #include "../image/toolbar/capture_airpcap_16.xpm"
76 #endif
77
78 /* XXX */
79 extern gint if_list_comparator_alph (const void *first_arg, const void *second_arg);
80
81 static GtkWidget *welcome_hb = NULL;
82 static GtkWidget *header_lb = NULL;
83 /* Foreground colors are set using Pango markup */
84 static GdkColor welcome_bg = { 0, 0xe6e6, 0xe6e6, 0xe6e6 };
85 static GdkColor header_bar_bg = { 0, 0x1818, 0x5c5c, 0xcaca };
86 static GdkColor topic_header_bg = { 0, 0x0101, 0x3939, 0xbebe };
87 static GdkColor topic_content_bg = { 0, 0xffff, 0xffff, 0xffff };
88 static GdkColor topic_item_idle_bg;
89 static GdkColor topic_item_entered_bg = { 0, 0xd3d3, 0xd8d8, 0xdada };
90
91 static GtkWidget *welcome_file_panel_vb = NULL;
92 #ifdef HAVE_LIBPCAP
93 static GtkWidget *welcome_if_panel_vb = NULL;
94 static GtkWidget *if_view = NULL;
95 #endif
96
97 static GSList *status_messages = NULL;
98
99 #ifdef USE_THREADS
100 static GMutex *recent_mtx = NULL;
101 #endif
102
103 /* The "scroll box dynamic" is a (complicated) pseudo widget to */
104 /* place a vertically list of widgets in (currently the interfaces and recent files). */
105 /* Once this list get's higher than a specified amount, */
106 /* it is moved into a scrolled_window. */
107 /* This is all complicated, the scrolled window is a bit ugly, */
108 /* the sizes might not be the same on all systems, ... */
109 /* ... but that's the best what we currently have */
110 #define SCROLL_BOX_CHILD_BOX        "ScrollBoxDynamic_ChildBox"
111 #define SCROLL_BOX_MAX_CHILDS       "ScrollBoxDynamic_MaxChilds"
112 #define SCROLL_BOX_SCROLLW_Y_SIZE   "ScrollBoxDynamic_Scrollw_Y_Size"
113 #define SCROLL_BOX_SCROLLW          "ScrollBoxDynamic_Scrollw"
114 #define TREE_VIEW_INTERFACES        "TreeViewInterfaces"
115
116 static GtkWidget *
117 scroll_box_dynamic_new(GtkWidget *child_box, guint max_childs, guint scrollw_y_size) {
118     GtkWidget * parent_box;
119
120
121     parent_box = gtk_vbox_new(FALSE, 0);
122     gtk_box_pack_start(GTK_BOX(parent_box), GTK_WIDGET(child_box), TRUE, TRUE, 0);
123     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX, child_box);
124     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS, GINT_TO_POINTER(max_childs));
125     g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE, GINT_TO_POINTER(scrollw_y_size));
126     gtk_widget_show_all(parent_box);
127
128     return parent_box;
129 }
130
131
132 static GtkWidget *
133 scroll_box_dynamic_add(GtkWidget *parent_box)
134 {
135     GtkWidget *child_box;
136     GtkWidget *scrollw;
137     guint max_cnt;
138     guint curr_cnt;
139     guint scrollw_y_size;
140     GList *childs;
141
142     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
143     max_cnt = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS));
144
145     /* get the current number of children */
146     childs = gtk_container_get_children(GTK_CONTAINER(child_box));
147     curr_cnt = g_list_length(childs);
148     g_list_free(childs);
149
150     /* have we just reached the max? */
151     if(curr_cnt == max_cnt) {
152         /* create the scrolled window */
153         /* XXX - there's no way to get rid of the shadow frame - except for creating an own widget :-( */
154         scrollw = scrolled_window_new(NULL, NULL);
155         scrollw_y_size = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE));
156         gtk_widget_set_size_request(scrollw, -1, scrollw_y_size);
157
158         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, scrollw);
159         gtk_box_pack_start(GTK_BOX(parent_box), scrollw, TRUE, TRUE, 0);
160
161         /* move child_box from parent_box into scrolled window */
162         g_object_ref(child_box);
163         gtk_container_remove(GTK_CONTAINER(parent_box), child_box);
164         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollw),
165                                               child_box);
166         gtk_widget_show_all(scrollw);
167     }
168
169     return child_box;
170 }
171
172
173 static GtkWidget *
174 scroll_box_dynamic_reset(GtkWidget *parent_box)
175 {
176     GtkWidget *child_box, *scrollw;
177
178
179     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
180     scrollw = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW);
181
182     if(scrollw != NULL) {
183         /* move the child_box back from scrolled window into the parent_box */
184         g_object_ref(child_box);
185         gtk_container_remove(GTK_CONTAINER(parent_box), scrollw);
186         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, NULL);
187         gtk_box_pack_start(GTK_BOX(parent_box), child_box, TRUE, TRUE, 0);
188     }
189
190     return child_box;
191 }
192
193
194 /* mouse entered this widget - change background color */
195 static gboolean
196 welcome_item_enter_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
197 {
198     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_entered_bg);
199
200     return FALSE;
201 }
202
203
204 /* mouse has left this widget - change background color  */
205 static gboolean
206 welcome_item_leave_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
207 {
208     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
209
210     return FALSE;
211 }
212
213
214 typedef gboolean (*welcome_button_callback_t)  (GtkWidget      *widget,
215                                                 GdkEventButton *event,
216                                                 gpointer        user_data);
217
218 /* create a "button widget" */
219 static GtkWidget *
220 welcome_button(const gchar *stock_item,
221                const gchar *title, const gchar *subtitle, const gchar *tooltip,
222                welcome_button_callback_t welcome_button_callback, gpointer welcome_button_callback_data)
223 {
224     GtkWidget *eb, *w, *item_hb, *text_vb;
225     gchar *formatted_text;
226
227     item_hb = gtk_hbox_new(FALSE, 1);
228
229     /* event box (for background color and events) */
230     eb = gtk_event_box_new();
231     gtk_container_add(GTK_CONTAINER(eb), item_hb);
232     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
233     if(tooltip != NULL) {
234                 gtk_widget_set_tooltip_text(eb, tooltip);
235     }
236
237     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), NULL);
238     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), NULL);
239     g_signal_connect(eb, "button-release-event", G_CALLBACK(welcome_button_callback), welcome_button_callback_data);
240
241     /* icon */
242     w = gtk_image_new_from_stock(stock_item, GTK_ICON_SIZE_LARGE_TOOLBAR);
243     gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 5);
244
245     text_vb = gtk_vbox_new(FALSE, 3);
246
247     /* title */
248     w = gtk_label_new(title);
249     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
250     formatted_text = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"black\">%s</span>", title);
251     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
252     g_free(formatted_text);
253     gtk_box_pack_start(GTK_BOX(text_vb), w, FALSE, FALSE, 1);
254
255     /* subtitle */
256     w = gtk_label_new(subtitle);
257     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
258     formatted_text = g_strdup_printf("<span size=\"small\" foreground=\"black\">%s</span>", subtitle);
259     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
260     g_free(formatted_text);
261     gtk_box_pack_start(GTK_BOX(text_vb), w, FALSE, FALSE, 1);
262
263     gtk_box_pack_start(GTK_BOX(item_hb), text_vb, TRUE, TRUE, 5);
264
265     return eb;
266 }
267
268
269 /* Hack to handle welcome-button "button-release-event" callback   */
270 /*  1. Dispatch to desired actual callback                         */
271 /*  2. Return TRUE for the event callback.                         */
272 /* user_data: actual (no arg) callback fcn to be invoked.          */
273 static gboolean
274 welcome_button_callback_helper(GtkWidget *w, GdkEventButton *event _U_, gpointer user_data)
275 {
276     void (*funct)(GtkWidget *, gpointer) = user_data;
277     (*funct)(w, NULL);
278     return TRUE;
279 }
280
281
282 void
283 welcome_header_set_message(gchar *msg) {
284     GString *message;
285     time_t secs = time(NULL);
286     struct tm *now = localtime(&secs);
287
288     message = g_string_new("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">");
289
290     if (msg) {
291         g_string_append(message, msg);
292     } else { /* Use our default header */
293         if ((now->tm_mon == 3 && now->tm_mday == 1) || (now->tm_mon == 6 && now->tm_mday == 14)) {
294             g_string_append(message, "Sniffing the glue that holds the Internet together");
295         } else {
296             g_string_append(message, prefs.gui_start_title);
297         }
298
299         if (prefs.gui_version_in_start_page) {
300             g_string_append_printf(message, "</span>\n<span size=\"large\" foreground=\"white\">Version " VERSION "%s",
301                                    wireshark_svnversion);
302         }
303     }
304
305     g_string_append(message, "</span>");
306
307     gtk_label_set_markup(GTK_LABEL(header_lb), message->str);
308     g_string_free(message, TRUE);
309 }
310
311
312 /* create the banner "above our heads" */
313 static GtkWidget *
314 welcome_header_new(void)
315 {
316     GtkWidget *item_vb;
317     GtkWidget *item_hb;
318     GtkWidget *eb;
319     GtkWidget *icon;
320
321     item_vb = gtk_vbox_new(FALSE, 0);
322
323     /* colorize vbox */
324     eb = gtk_event_box_new();
325     gtk_container_add(GTK_CONTAINER(eb), item_vb);
326     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &header_bar_bg);
327
328     item_hb = gtk_hbox_new(FALSE, 0);
329     gtk_box_pack_start(GTK_BOX(item_vb), item_hb, FALSE, FALSE, 10);
330
331     icon = xpm_to_widget_from_parent(top_level, wssplash_xpm);
332     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 10);
333
334     header_lb = gtk_label_new(NULL);
335     welcome_header_set_message(NULL);
336     gtk_label_set_selectable(GTK_LABEL(header_lb), TRUE);
337     gtk_misc_set_alignment(GTK_MISC(header_lb), 0.0f, 0.5f);
338     gtk_box_pack_start(GTK_BOX(item_hb), header_lb, TRUE, TRUE, 5);
339
340     gtk_widget_show_all(eb);
341
342     return eb;
343 }
344
345
346 void
347 welcome_header_push_msg(const gchar *msg) {
348     gchar *msg_copy = g_strdup(msg);
349
350     status_messages = g_slist_append(status_messages, msg_copy);
351
352     welcome_header_set_message(msg_copy);
353
354     gtk_widget_hide(welcome_hb);
355 }
356
357
358 void
359 welcome_header_pop_msg(void) {
360     gchar *msg = NULL;
361
362     if (status_messages) {
363         g_free(status_messages->data);
364         status_messages = g_slist_delete_link(status_messages, status_messages);
365     }
366
367     if (status_messages) {
368         msg = status_messages->data;
369     }
370
371     welcome_header_set_message(msg);
372
373     if (!status_messages) {
374         gtk_widget_show(welcome_hb);
375     }
376 }
377
378
379 /* create a "topic header widget" */
380 static GtkWidget *
381 welcome_topic_header_new(const char *header)
382 {
383     GtkWidget *w;
384     GtkWidget *eb;
385     gchar *formatted_message;
386
387
388     w = gtk_label_new(header);
389     formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">%s</span>", header);
390     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
391     g_free(formatted_message);
392
393     /* colorize vbox */
394     eb = gtk_event_box_new();
395     gtk_container_add(GTK_CONTAINER(eb), w);
396     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_header_bg);
397
398     return eb;
399 }
400
401
402 /* create a "topic widget" */
403 static GtkWidget *
404 welcome_topic_new(const char *header, GtkWidget **to_fill)
405 {
406     GtkWidget *topic_vb;
407     GtkWidget *layout_vb;
408     GtkWidget *topic_eb;
409     GtkWidget *topic_header;
410
411
412     topic_vb = gtk_vbox_new(FALSE, 0);
413
414     topic_header = welcome_topic_header_new(header);
415     gtk_box_pack_start(GTK_BOX(topic_vb), topic_header, FALSE, FALSE, 0);
416
417     layout_vb = gtk_vbox_new(FALSE, 5);
418     gtk_container_set_border_width(GTK_CONTAINER(layout_vb), 10);
419     gtk_box_pack_start(GTK_BOX(topic_vb), layout_vb, FALSE, FALSE, 0);
420
421     /* colorize vbox (we need an event box for this!) */
422     topic_eb = gtk_event_box_new();
423     gtk_container_add(GTK_CONTAINER(topic_eb), topic_vb);
424     gtk_widget_modify_bg(topic_eb, GTK_STATE_NORMAL, &topic_content_bg);
425     *to_fill = layout_vb;
426
427     return topic_eb;
428 }
429
430
431 /* a file link was pressed */
432 static gboolean
433 welcome_filename_link_press_cb(GtkWidget *widget _U_, GdkEventButton *event _U_, gpointer data)
434 {
435     menu_open_filename(data);
436
437     return FALSE;
438 }
439
440 typedef struct _recent_item_status {
441     gchar     *filename;
442     GtkWidget *label;
443     GObject   *menu_item;
444     GString   *str;
445     gboolean   stat_done;
446     int        err;
447     guint      timer;
448 } recent_item_status;
449
450 /*
451  * Fetch the status of a file.
452  * This function might be called as a thread. We can't use any drawing
453  * routines here: http://developer.gnome.org/gdk/2.24/gdk-Threads.html
454  */
455 static void *get_recent_item_status(void *data)
456 {
457     recent_item_status *ri_stat = (recent_item_status *) data;
458     ws_statb64 stat_buf;
459     int err;
460
461     if (!ri_stat) {
462         return NULL;
463     }
464
465     /*
466      * Add file size. We use binary prefixes instead of IEC because that's what
467      * most OSes use.
468      */
469     err = ws_stat64(ri_stat->filename, &stat_buf);
470 #ifdef USE_THREADS
471     g_mutex_lock(recent_mtx);
472 #endif
473     ri_stat->err = err;
474     if(err == 0) {
475         if (stat_buf.st_size/1024/1024/1024 > 10) {
476             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d GB)", (gint64) (stat_buf.st_size/1024/1024/1024));
477         } else if (stat_buf.st_size/1024/1024 > 10) {
478             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d MB)", (gint64) (stat_buf.st_size/1024/1024));
479         } else if (stat_buf.st_size/1024 > 10) {
480             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d KB)", (gint64) (stat_buf.st_size/1024));
481         } else {
482             g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d Bytes)", (gint64) (stat_buf.st_size));
483         }
484         /* pango format string */
485         g_string_prepend(ri_stat->str, "<span foreground='blue'>");
486         g_string_append(ri_stat->str, "</span>");
487     } else {
488         g_string_append(ri_stat->str, " [not found]");
489     }
490
491     if (!ri_stat->label) { /* The widget went away while we were busy. */
492         g_free(ri_stat->filename);
493         g_string_free(ri_stat->str, TRUE);
494         g_free(ri_stat);
495     } else {
496         ri_stat->stat_done = TRUE;
497     }
498 #ifdef USE_THREADS
499     g_mutex_unlock(recent_mtx);
500 #endif
501
502     return NULL;
503 }
504
505 /* Timeout callback for recent items */
506 static gboolean
507 update_recent_items(gpointer data)
508 {
509     recent_item_status *ri_stat = (recent_item_status *) data;
510     gboolean again = TRUE;
511
512     if (!ri_stat) {
513         return FALSE;
514     }
515
516 #ifdef USE_THREADS
517     g_mutex_lock(recent_mtx);
518 #endif
519     if (ri_stat->stat_done) {
520         again = FALSE;
521         gtk_label_set_markup(GTK_LABEL(ri_stat->label), ri_stat->str->str);
522         if (ri_stat->err == 0) {
523             gtk_widget_set_sensitive(ri_stat->label, TRUE);
524 #ifdef MAIN_MENU_USE_UIMANAGER
525             gtk_action_set_sensitive((GtkAction *) ri_stat->menu_item, TRUE);
526 #else
527             gtk_widget_set_sensitive(GTK_WIDGET(ri_stat->menu_item), TRUE);
528 #endif
529         }
530         ri_stat->timer = 0;
531     }
532     /* Else append some sort of Unicode or ASCII animation to the label? */
533 #ifdef USE_THREADS
534     g_mutex_unlock(recent_mtx);
535 #endif
536     return again;
537 }
538
539 static void welcome_filename_destroy_cb(GtkWidget *w _U_, gpointer data) {
540     recent_item_status *ri_stat = (recent_item_status *) data;
541
542     if (!ri_stat) {
543         return;
544     }
545
546 #ifdef USE_THREADS
547     g_mutex_lock(recent_mtx);
548 #endif
549     if (ri_stat->timer) {
550         g_source_remove(ri_stat->timer);
551         ri_stat->timer = 0;
552     }
553
554     g_object_unref(ri_stat->menu_item);
555
556     if (ri_stat->stat_done) {
557         g_free(ri_stat->filename);
558         g_string_free(ri_stat->str, TRUE);
559         g_free(ri_stat);
560     } else {
561         ri_stat->label = NULL;
562     }
563 #ifdef USE_THREADS
564     g_mutex_unlock(recent_mtx);
565 #endif
566 }
567
568 /* create a "file link widget" */
569 static GtkWidget *
570 welcome_filename_link_new(const gchar *filename, GtkWidget **label, GObject *menu_item)
571 {
572     GtkWidget   *w;
573     GtkWidget   *eb;
574     GString     *str;
575     gchar       *str_escaped;
576     glong        uni_len;
577     gsize        uni_start, uni_end;
578     const glong  max = 60;
579     recent_item_status *ri_stat;
580
581     /* filename */
582     str = g_string_new(filename);
583     uni_len = g_utf8_strlen(str->str, str->len);
584
585     /* cut max filename length */
586     if (uni_len > max) {
587         uni_start = g_utf8_offset_to_pointer(str->str, 20) - str->str;
588         uni_end = g_utf8_offset_to_pointer(str->str, uni_len - max) - str->str;
589         g_string_erase(str, uni_start, uni_end);
590         g_string_insert(str, uni_start, " " UTF8_HORIZONTAL_ELLIPSIS " ");
591     }
592
593     /* escape the possibly shortened filename before adding pango language */
594     str_escaped=g_markup_escape_text(str->str, -1);
595     g_string_free(str, TRUE);
596
597     /* label */
598     w = gtk_label_new(str_escaped);
599     *label = w;
600     gtk_misc_set_padding(GTK_MISC(w), 5, 2);
601     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
602     gtk_widget_set_sensitive(w, FALSE);
603
604     ri_stat = g_malloc(sizeof(recent_item_status));
605     ri_stat->filename = g_strdup(filename);
606     ri_stat->label = w;
607     ri_stat->menu_item = menu_item;
608     ri_stat->str = g_string_new(str_escaped);
609     ri_stat->stat_done = FALSE;
610     ri_stat->timer = 0;
611     g_object_ref(G_OBJECT(menu_item));
612     g_signal_connect(w, "destroy", G_CALLBACK(welcome_filename_destroy_cb), ri_stat);
613     g_free(str_escaped);
614
615 #ifdef USE_THREADS
616     g_thread_create(get_recent_item_status, ri_stat, FALSE, NULL);
617     ri_stat->timer = g_timeout_add(200, update_recent_items, ri_stat);
618 #else
619     get_recent_item_status(ri_stat);
620     update_recent_items(ri_stat);
621 #endif
622
623     /* event box */
624     eb = gtk_event_box_new();
625     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
626     gtk_container_add(GTK_CONTAINER(eb), w);
627     gtk_widget_set_tooltip_text(eb, filename);
628
629     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), w);
630     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), w);
631     g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_filename_link_press_cb), (gchar *) filename);
632
633     return eb;
634 }
635
636
637 /* reset the list of recent files */
638 void
639 main_welcome_reset_recent_capture_files(void)
640 {
641     GtkWidget *child_box;
642     GList* child_list;
643     GList* child_list_item;
644
645
646     if(welcome_file_panel_vb) {
647         child_box = scroll_box_dynamic_reset(welcome_file_panel_vb);
648         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
649         child_list_item = child_list;
650
651         while(child_list_item) {
652             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
653             child_list_item = g_list_next(child_list_item);
654         }
655
656         g_list_free(child_list);
657     }
658 }
659
660
661 /* add a new file to the list of recent files */
662 void
663 main_welcome_add_recent_capture_file(const char *widget_cf_name, GObject *menu_item)
664 {
665     GtkWidget *w;
666     GtkWidget *child_box;
667     GtkWidget *label;
668
669
670     w = welcome_filename_link_new(widget_cf_name, &label, menu_item);
671     child_box = scroll_box_dynamic_add(welcome_file_panel_vb);
672     gtk_box_pack_start(GTK_BOX(child_box), w, FALSE, FALSE, 0);
673     gtk_widget_show_all(w);
674     gtk_widget_show_all(child_box);
675 }
676
677 #ifdef HAVE_LIBPCAP
678 static gboolean select_current_ifaces(GtkTreeModel  *model,
679                                   GtkTreePath   *path _U_,
680                                   GtkTreeIter   *iter,
681                                   gpointer       userdata)
682 {
683     guint i;
684     gchar *if_name;
685     gboolean found = FALSE;
686
687     GtkTreeSelection *selection = (GtkTreeSelection *)userdata;
688     gtk_tree_model_get (model, iter, IFACE_NAME, &if_name, -1);
689     for (i = 0; i < global_capture_opts.ifaces->len; i++) {
690         if (strcmp(g_array_index(global_capture_opts.ifaces, interface_options, i).name, if_name) == 0) {
691             gtk_tree_selection_select_iter(selection, iter);
692             found = TRUE;
693             break;
694         }
695     }
696     if (!found) {
697         gtk_tree_selection_unselect_iter(selection, iter);
698     }
699     return FALSE;
700 }
701
702 gboolean on_selection_changed(GtkTreeSelection *selection _U_,
703                               GtkTreeModel *model,
704                               GtkTreePath *path,
705                               gboolean path_currently_selected,
706                               gpointer data _U_)
707 {
708     GtkTreeIter  iter;
709     gchar *if_name;
710     interface_options interface_opts;
711     guint i;
712     cap_settings_t    cap_settings;
713     gboolean found = FALSE;
714     
715     gtk_tree_model_get_iter (model, &iter, path);
716     gtk_tree_model_get (model, &iter, IFACE_NAME, &if_name, -1);
717     for (i = 0; i < global_capture_opts.ifaces->len; i++) {
718         if (strcmp(g_array_index(global_capture_opts.ifaces, interface_options, i).name, if_name) == 0) {
719             found = TRUE;
720             if (path_currently_selected) {
721                 interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
722                 global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, i);
723                 g_free(interface_opts.name);
724                 g_free(interface_opts.descr);
725                 g_free(interface_opts.cfilter);
726 #ifdef HAVE_PCAP_REMOTE
727                 g_free(interface_opts.remote_host);
728                 g_free(interface_opts.remote_port);
729                 g_free(interface_opts.auth_username);
730                 g_free(interface_opts.auth_password);
731 #endif
732                 break;
733             }
734         } 
735     } 
736     if (!found && !path_currently_selected) {
737         interface_opts.name = g_strdup(if_name);
738         interface_opts.descr = get_interface_descriptive_name(interface_opts.name);
739         interface_opts.linktype = capture_dev_user_linktype_find(interface_opts.name);
740         interface_opts.cfilter = g_strdup(global_capture_opts.default_options.cfilter);
741         interface_opts.has_snaplen = global_capture_opts.default_options.has_snaplen;
742         interface_opts.snaplen = global_capture_opts.default_options.snaplen;
743         cap_settings = capture_get_cap_settings (interface_opts.name);;
744         interface_opts.promisc_mode = global_capture_opts.default_options.promisc_mode;
745 #if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
746         interface_opts.buffer_size =  global_capture_opts.default_options.buffer_size;
747 #endif
748         interface_opts.monitor_mode = cap_settings.monitor_mode;
749 #ifdef HAVE_PCAP_REMOTE
750         interface_opts.src_type = global_capture_opts.default_options.src_type;
751         interface_opts.remote_host = g_strdup(global_capture_opts.default_options.remote_host);
752         interface_opts.remote_port = g_strdup(global_capture_opts.default_options.remote_port);
753         interface_opts.auth_type = global_capture_opts.default_options.auth_type;
754         interface_opts.auth_username = g_strdup(global_capture_opts.default_options.auth_username);
755         interface_opts.auth_password = g_strdup(global_capture_opts.default_options.auth_password);
756         interface_opts.datatx_udp = global_capture_opts.default_options.datatx_udp;
757         interface_opts.nocap_rpcap = global_capture_opts.default_options.nocap_rpcap;
758         interface_opts.nocap_local = global_capture_opts.default_options.nocap_local;
759 #endif
760 #ifdef HAVE_PCAP_SETSAMPLING
761         interface_opts.sampling_method = global_capture_opts.default_options.sampling_method;
762         interface_opts.sampling_param  = global_capture_opts.default_options.sampling_param;
763 #endif
764         g_array_append_val(global_capture_opts.ifaces, interface_opts);
765     }
766     return TRUE;
767 }
768 #endif
769
770 void
771 select_ifaces(void)
772 {
773 #ifdef HAVE_LIBPCAP
774     GtkWidget        *view;
775     GtkTreeModel     *model;
776     GtkTreeSelection *entry;
777
778     if (global_capture_opts.ifaces->len > 0) {
779         view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
780         model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
781         entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
782         gtk_tree_model_foreach(GTK_TREE_MODEL(model), select_current_ifaces, (gpointer) entry);
783         gtk_widget_grab_focus(view);
784     }
785 #endif
786 }
787
788 /* list the interfaces */
789 void
790 welcome_if_tree_load(void)
791 {
792 #ifdef HAVE_LIBPCAP
793     if_info_t     *if_info;
794     GList         *if_list;
795     int err;
796     gchar         *err_str = NULL;
797     GList         *curr;
798     gchar         *user_descr;
799     GtkListStore  *store = NULL;
800     GtkTreeIter   iter;
801     GtkWidget     *icon, *view;
802     GtkTreeSelection *entry;
803
804     /* LOAD THE INTERFACES */
805     if_list = capture_interface_list(&err, &err_str);
806     if_list = g_list_sort (if_list, if_list_comparator_alph);
807     if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
808         simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
809         g_free(err_str);
810         return;
811     } else if (err_str) {
812         g_free(err_str);
813     }
814     if (g_list_length(if_list) > 0) {
815         view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
816         entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
817         gtk_tree_selection_unselect_all(entry);
818         store = gtk_list_store_new(NUMCOLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
819         /* List the interfaces */
820         for (curr = g_list_first(if_list); curr; curr = g_list_next(curr)) {
821             if_info = curr->data;
822             /* Continue if capture device is hidden */
823             if (prefs_is_capture_device_hidden(if_info->name)) {
824                 continue;
825             }
826             gtk_list_store_append (store, &iter);
827
828 #ifdef HAVE_AIRPCAP
829             if (get_airpcap_if_from_name(airpcap_if_list,if_info->name) != NULL)
830                 icon = xpm_to_widget(capture_airpcap_16_xpm);
831             else
832                 icon = capture_get_if_icon(if_info);
833 #else
834             icon = capture_get_if_icon(if_info);
835 #endif
836             user_descr = capture_dev_user_descr_find(if_info->name);
837             if (user_descr) {
838 #ifndef _WIN32
839                 gchar *comment = user_descr;
840                 user_descr = g_strdup_printf("%s (%s)", comment, if_info->name);
841                 g_free (comment);
842 #endif
843                 gtk_list_store_set(store, &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(icon)), IFACE_DESCR, user_descr, IFACE_NAME, if_info->name, -1);
844                 g_free (user_descr);
845             } else if (if_info->description) {
846                 gtk_list_store_set (store, &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(icon)), IFACE_DESCR, if_info->description, IFACE_NAME, if_info->name, -1);
847             } else {
848                 gtk_list_store_set (store, &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(icon)), IFACE_DESCR, if_info->name, IFACE_NAME, if_info->name, -1);
849             }
850         }
851         gtk_tree_view_set_model(GTK_TREE_VIEW(if_view), GTK_TREE_MODEL (store));
852         if (global_capture_opts.ifaces->len > 0) {
853             gtk_tree_model_foreach(GTK_TREE_MODEL(store), select_current_ifaces, (gpointer) entry);
854             gtk_widget_grab_focus(view);
855         }
856         gtk_tree_selection_set_select_function(entry, on_selection_changed, NULL, NULL);
857     }
858     free_interface_list(if_list);
859 #endif  /* HAVE_LIBPCAP */
860 }
861
862
863 /* reload the list of interfaces */
864 void
865 welcome_if_panel_reload(void)
866 {
867 #ifdef HAVE_LIBPCAP
868     GtkWidget *child_box;
869     GList* child_list;
870     GList* child_list_item;
871
872
873     if(welcome_if_panel_vb) {
874         child_box = scroll_box_dynamic_reset(welcome_if_panel_vb);
875         child_list = gtk_container_get_children(GTK_CONTAINER(child_box));
876         child_list_item = child_list;
877
878         while(child_list_item) {
879             gtk_container_remove(GTK_CONTAINER(child_box), child_list_item->data);
880             child_list_item = g_list_next(child_list_item);
881         }
882
883         g_list_free(child_list);
884         welcome_if_tree_load();
885         gtk_widget_show_all(welcome_if_panel_vb);
886     }
887 #endif  /* HAVE_LIBPCAP */
888 }
889
890 #ifdef HAVE_LIBPCAP
891 static void capture_if_start(GtkWidget *w _U_, gpointer data _U_)
892 {
893 #ifdef HAVE_AIRPCAP
894   interface_options interface_opts;
895 #endif
896
897   if (global_capture_opts.ifaces->len == 0) {
898     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
899       "You didn't specify an interface on which to capture packets.");
900     return;
901   }
902 #ifndef USE_THREADS
903   if (global_capture_opts.ifaces->len > 1) {
904     simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
905       "You specified multiple interfaces for capturing which this version of Wireshark doesn't support.");
906     return;
907   }
908 #endif
909
910   /* XXX - remove this? */
911   if (global_capture_opts.save_file) {
912       g_free(global_capture_opts.save_file);
913       global_capture_opts.save_file = NULL;
914   }
915 #ifdef HAVE_AIRPCAP
916   interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, 0);
917   airpcap_if_active = get_airpcap_if_from_name(airpcap_if_list, interface_opts.name);
918   airpcap_if_selected = airpcap_if_active;
919   airpcap_set_toolbar_start_capture(airpcap_if_active);
920 #endif
921   capture_start_cb(NULL, NULL);
922 }
923 #endif
924
925 /* create the welcome page */
926 GtkWidget *
927 welcome_new(void)
928 {
929     GtkWidget *welcome_scrollw;
930     GtkWidget *welcome_eb;
931     GtkWidget *welcome_vb;
932     GtkWidget *column_vb;
933     GtkWidget *item_hb;
934     GtkWidget *w;
935     GtkWidget *header;
936     GtkWidget *topic_vb;
937     GtkWidget *topic_to_fill;
938     GtkWidget *file_child_box;
939     gchar *label_text;
940 #ifdef _WIN32
941     LONG reg_ret;
942     DWORD chimney_enabled = 0;
943     DWORD ce_size = sizeof(chimney_enabled);
944 #endif
945 #ifdef HAVE_LIBPCAP
946     GtkWidget *swindow;
947     GtkTreeSelection *selection;
948     GtkCellRenderer *renderer;
949     GtkTreeViewColumn *column;
950     GList     *if_list;
951     int err;
952     gchar *err_str = NULL;
953 #endif
954
955     /* prepare colors */
956
957     /* "page" background */
958     get_color(&welcome_bg);
959
960     /* header bar background color */
961     get_color(&header_bar_bg);
962
963     /* topic header background color */
964     get_color(&topic_header_bg);
965
966     /* topic content background color */
967     get_color(&topic_content_bg);
968
969     topic_item_idle_bg = topic_content_bg;
970
971     /* topic item entered color */
972     get_color(&topic_item_entered_bg);
973
974     welcome_scrollw = scrolled_window_new(NULL, NULL);
975
976     welcome_vb = gtk_vbox_new(FALSE, 0);
977
978     welcome_eb = gtk_event_box_new();
979     gtk_container_add(GTK_CONTAINER(welcome_eb), welcome_vb);
980     gtk_widget_modify_bg(welcome_eb, GTK_STATE_NORMAL, &welcome_bg);
981
982     /* header */
983     header = welcome_header_new();
984     gtk_box_pack_start(GTK_BOX(welcome_vb), header, FALSE, FALSE, 0);
985
986     /* content */
987     welcome_hb = gtk_hbox_new(FALSE, 10);
988     gtk_container_set_border_width(GTK_CONTAINER(welcome_hb), 10);
989     gtk_box_pack_start(GTK_BOX(welcome_vb), welcome_hb, TRUE, TRUE, 0);
990
991
992     /* column capture */
993     column_vb = gtk_vbox_new(FALSE, 10);
994     gtk_widget_modify_bg(column_vb, GTK_STATE_NORMAL, &welcome_bg);
995     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
996
997     /* capture topic */
998     topic_vb = welcome_topic_new("Capture", &topic_to_fill);
999     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1000
1001 #ifdef HAVE_LIBPCAP
1002     if_list = capture_interface_list(&err, &err_str);
1003     if (g_list_length(if_list) > 0) {
1004         item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_INTERFACES,
1005             "Interface List",
1006             "Live list of the capture interfaces\n(counts incoming packets)",
1007             "Same as Capture/Interfaces menu or toolbar item",
1008             welcome_button_callback_helper, capture_if_cb);
1009         gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1010
1011         swindow = gtk_scrolled_window_new (NULL, NULL);
1012         gtk_widget_set_size_request(swindow, FALSE, 100);
1013         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swindow), GTK_SHADOW_IN);
1014         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1015
1016         if_view = gtk_tree_view_new ();
1017         g_object_set(GTK_OBJECT(if_view), "headers-visible", FALSE, NULL);
1018         g_object_set_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES, if_view);
1019         renderer = gtk_cell_renderer_pixbuf_new();
1020         column = gtk_tree_view_column_new_with_attributes ("",
1021                                                GTK_CELL_RENDERER(renderer),
1022                                                "pixbuf", ICON,
1023                                                NULL);
1024         gtk_tree_view_append_column(GTK_TREE_VIEW(if_view), column);
1025         renderer = gtk_cell_renderer_text_new();
1026         column = gtk_tree_view_column_new_with_attributes ("",
1027                                                GTK_CELL_RENDERER(renderer),
1028                                                "text", IFACE_DESCR,
1029                                                NULL);
1030         gtk_tree_view_append_column(GTK_TREE_VIEW(if_view), column);
1031         gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(if_view), 0), TRUE);
1032         renderer = gtk_cell_renderer_text_new();
1033         column = gtk_tree_view_column_new_with_attributes ("",
1034                                                GTK_CELL_RENDERER(renderer),
1035                                                "text", IFACE_NAME,
1036                                                NULL);
1037         gtk_tree_view_append_column(GTK_TREE_VIEW(if_view), column);
1038         gtk_tree_view_column_set_visible(column, FALSE);
1039         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(if_view));
1040         gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
1041 #ifdef USE_THREADS
1042         item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_START,
1043             "Start",
1044             "Choose one or more interfaces to capture from, then <b>Start</b>",
1045             "Same as Capture/Interfaces with default options",
1046             (welcome_button_callback_t)capture_if_start, (gpointer)if_view);
1047 #else
1048         item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_START,
1049             "Start",
1050             "Choose exactly one interface to capture from, then <b>Start</b>",
1051             "Same as Capture/Interfaces with default options",
1052             (welcome_button_callback_t)capture_if_start, (gpointer)if_view);
1053 #endif
1054         gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1055         welcome_if_tree_load();
1056         gtk_container_add (GTK_CONTAINER (swindow), if_view);
1057         gtk_container_add(GTK_CONTAINER(topic_to_fill), swindow);
1058
1059         item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_OPTIONS,
1060                 "Capture Options",
1061                 "Start a capture with detailed options",
1062                 "Same as Capture/Options menu or toolbar item",
1063                 welcome_button_callback_helper, capture_prep_cb);
1064         gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1065 #ifdef _WIN32
1066         /* Check for chimney offloading */
1067         reg_ret = RegQueryValueEx(HKEY_LOCAL_MACHINE,
1068                                   _T("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\EnableTCPChimney"),
1069                                   NULL, NULL, (LPBYTE) &chimney_enabled, &ce_size);
1070         if (reg_ret == ERROR_SUCCESS && chimney_enabled) {
1071             item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1072                     "Offloading Detected",
1073                     "TCP Chimney offloading is enabled. You \nmight not capture much data.",
1074                     topic_online_url(ONLINEPAGE_CHIMNEY),
1075                     topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_CHIMNEY));
1076             gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1077         }
1078 #endif /* _WIN32 */
1079     } else {
1080         label_text =  g_strdup("No interface can be used for capturing in\n"
1081                                "this system with the current configuration.\n\n"
1082                                "See Capture Help below for details.");
1083         w = gtk_label_new(label_text);
1084         gtk_label_set_markup(GTK_LABEL(w), label_text);
1085         g_free (label_text);
1086         gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
1087         gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
1088     }
1089
1090     free_interface_list(if_list);
1091
1092     /* capture help topic */
1093     topic_vb = welcome_topic_new("Capture Help", &topic_to_fill);
1094     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1095
1096     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1097         "How to Capture",
1098         "Step by step to a successful capture setup",
1099         topic_online_url(ONLINEPAGE_CAPTURE_SETUP),
1100         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_CAPTURE_SETUP));
1101     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1102
1103     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1104         "Network Media",
1105         "Specific information for capturing on:\nEthernet, WLAN, ...",
1106         topic_online_url(ONLINEPAGE_NETWORK_MEDIA),
1107         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_NETWORK_MEDIA));
1108     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1109 #else
1110     label_text =  g_strdup("<span foreground=\"black\">Capturing is not compiled into this version of Wireshark!</span>");
1111     w = gtk_label_new(label_text);
1112     gtk_label_set_markup(GTK_LABEL(w), label_text);
1113     g_free (label_text);
1114     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
1115     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
1116 #endif  /* HAVE_LIBPCAP */
1117
1118     /* fill bottom space */
1119     w = gtk_label_new("");
1120     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
1121
1122
1123     /* column files */
1124     topic_vb = welcome_topic_new("Files", &topic_to_fill);
1125     gtk_box_pack_start(GTK_BOX(welcome_hb), topic_vb, TRUE, TRUE, 0);
1126
1127     item_hb = welcome_button(GTK_STOCK_OPEN,
1128         "Open",
1129         "Open a previously captured file",
1130         "Same as File/Open menu or toolbar item",
1131         welcome_button_callback_helper, file_open_cmd_cb);
1132     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1133
1134     /* prepare list of recent files (will be filled in later) */
1135     label_text =  g_strdup("<span foreground=\"black\">Open Recent:</span>");
1136     w = gtk_label_new(label_text);
1137     gtk_label_set_markup(GTK_LABEL(w), label_text);
1138     g_free (label_text);
1139     gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
1140     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
1141
1142     file_child_box = gtk_vbox_new(FALSE, 1);
1143     /* 17 file items or 300 pixels height is about the size */
1144     /* that still fits on a screen of about 1000*700 */
1145     welcome_file_panel_vb = scroll_box_dynamic_new(GTK_WIDGET(file_child_box), 17, 300);
1146     gtk_box_pack_start(GTK_BOX(topic_to_fill), welcome_file_panel_vb, FALSE, FALSE, 0);
1147
1148     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1149         "Sample Captures",
1150         "A rich assortment of example capture files on the wiki",
1151         topic_online_url(ONLINEPAGE_SAMPLE_CAPTURES),
1152         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_SAMPLE_CAPTURES));
1153     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1154
1155     /* fill bottom space */
1156     w = gtk_label_new("");
1157     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
1158
1159
1160     /* column online */
1161     column_vb = gtk_vbox_new(FALSE, 10);
1162     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
1163
1164     /* topic online */
1165     topic_vb = welcome_topic_new("Online", &topic_to_fill);
1166     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1167
1168     item_hb = welcome_button(GTK_STOCK_HOME,
1169         "Website",
1170         "Visit the project's website",
1171         topic_online_url(ONLINEPAGE_HOME),
1172         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_HOME));
1173     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1174
1175 #ifdef HHC_DIR
1176     item_hb = welcome_button(GTK_STOCK_HELP,
1177         "User's Guide",
1178         "The User's Guide "
1179         "(local version, if installed)",
1180         "Locally installed (if installed) otherwise online version",
1181         topic_menu_cb, GINT_TO_POINTER(HELP_CONTENT));
1182 #else
1183     item_hb = welcome_button(GTK_STOCK_HELP,
1184         "User's Guide",
1185         "The User's Guide "
1186         "(online version)",
1187         topic_online_url(ONLINEPAGE_USERGUIDE),
1188         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_USERGUIDE));
1189 #endif
1190     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1191
1192     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
1193         "Security",
1194         "Work with Wireshark as securely as possible",
1195         topic_online_url(ONLINEPAGE_SECURITY),
1196         topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_SECURITY));
1197     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
1198
1199 #if 0
1200     /* XXX - add this, once the Windows update functionality is implemented */
1201     /* topic updates */
1202     topic_vb = welcome_topic_new("Updates", &topic_to_fill);
1203     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
1204
1205     label_text =  g_strdup("<span foreground=\"black\">No updates available!</span>");
1206     w = gtk_label_new(label_text);
1207     gtk_label_set_markup(GTK_LABEL(w), label_text);
1208     g_free (label_text);
1209     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, TRUE, TRUE, 0);
1210 #endif
1211
1212
1213     /* the end */
1214     gtk_widget_show_all(welcome_eb);
1215
1216     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
1217                                           welcome_eb);
1218     gtk_widget_show_all(welcome_scrollw);
1219
1220 #ifdef USE_THREADS
1221     recent_mtx = g_mutex_new();
1222 #endif
1223
1224     return welcome_scrollw;
1225 }