Make sure that the Capture/Start menue item will always use the
[obnox/wireshark/wip.git] / gtk / main_welcome.c
index d7f6e049ff4b9e6af6fad6eac8f3ba8c6683f263..c1d19e33d042f9012d6d0eab35ada052fe7b7e4a 100644 (file)
 #include <epan/prefs.h>
 
 #include "../color.h"
+#ifdef HAVE_LIBPCAP
 #include "capture.h"
 #include "capture-pcap-util.h"
 #include "capture_opts.h"
 #include "capture_ui_utils.h"
+#endif
 #include "simple_dialog.h"
 #include <wsutil/file_util.h>
 
 #include "gtk/recent.h"
 #include "gtk/gtkglobals.h"
 #include "gtk/main.h"
-#include "gtk/main_menu.h"
+#include "gtk/menus.h"
 #include "gtk/main_welcome.h"
-#include "gtk/capture_dlg.h"
-#include "gtk/capture_if_dlg.h"
-#include "gtk/capture_file_dlg.h"
 #include "gtk/help_dlg.h"
+#include "gtk/capture_file_dlg.h"
 #include "gtk/stock_icons.h"
+#include "gtk/utf8_entities.h"
+#ifdef HAVE_LIBPCAP
+#include "gtk/capture_dlg.h"
+#include "gtk/capture_if_dlg.h"
 #include "gtk/capture_globals.h"
+#endif
 #include "../image/wssplash-dev.xpm"
 #include "../version_info.h"
 
+#ifdef _WIN32
+#include <tchar.h>
+#include <windows.h>
+#endif
+
 #ifdef HAVE_AIRPCAP
 #include "airpcap.h"
 #include "airpcap_loader.h"
 #include "airpcap_gui_utils.h"
+#include "../image/toolbar/capture_airpcap_16.xpm"
 #endif
 
 /* XXX */
 extern gint if_list_comparator_alph (const void *first_arg, const void *second_arg);
 
-
-static GdkColor header_bar_bg;
-static GdkColor topic_header_bg;
-static GdkColor topic_content_bg;
+static GtkWidget *welcome_hb = NULL;
+static GtkWidget *header_lb = NULL;
+/* Foreground colors are set using Pango markup */
+static GdkColor welcome_bg = { 0, 0xe6e6, 0xe6e6, 0xe6e6 };
+static GdkColor header_bar_bg = { 0, 0x1818, 0x5c5c, 0xcaca };
+static GdkColor topic_header_bg = { 0, 0x0101, 0x3939, 0xbebe };
+static GdkColor topic_content_bg = { 0, 0xffff, 0xffff, 0xffff };
 static GdkColor topic_item_idle_bg;
-static GdkColor topic_item_entered_bg;
+static GdkColor topic_item_entered_bg = { 0, 0xd3d3, 0xd8d8, 0xdada };
 
 static GtkWidget *welcome_file_panel_vb = NULL;
 #ifdef HAVE_LIBPCAP
 static GtkWidget *welcome_if_panel_vb = NULL;
+static GtkWidget *if_view = NULL;
 #endif
 
+static GSList *status_messages = NULL;
+
+#ifdef USE_THREADS
+static GMutex *recent_mtx = NULL;
+#endif
 
 /* The "scroll box dynamic" is a (complicated) pseudo widget to */
 /* place a vertically list of widgets in (currently the interfaces and recent files). */
@@ -91,10 +111,10 @@ static GtkWidget *welcome_if_panel_vb = NULL;
 #define SCROLL_BOX_MAX_CHILDS       "ScrollBoxDynamic_MaxChilds"
 #define SCROLL_BOX_SCROLLW_Y_SIZE   "ScrollBoxDynamic_Scrollw_Y_Size"
 #define SCROLL_BOX_SCROLLW          "ScrollBoxDynamic_Scrollw"
-
+#define TREE_VIEW_INTERFACES        "TreeViewInterfaces"
 
 static GtkWidget *
-scroll_box_dynamic_new(GtkBox *child_box, guint max_childs, guint scrollw_y_size) {
+scroll_box_dynamic_new(GtkWidget *child_box, guint max_childs, guint scrollw_y_size) {
     GtkWidget * parent_box;
 
 
@@ -108,6 +128,7 @@ scroll_box_dynamic_new(GtkBox *child_box, guint max_childs, guint scrollw_y_size
     return parent_box;
 }
 
+
 static GtkWidget *
 scroll_box_dynamic_add(GtkWidget *parent_box)
 {
@@ -118,7 +139,6 @@ scroll_box_dynamic_add(GtkWidget *parent_box)
     guint scrollw_y_size;
     GList *childs;
 
-
     child_box = g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_CHILD_BOX);
     max_cnt = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_MAX_CHILDS));
 
@@ -133,13 +153,13 @@ scroll_box_dynamic_add(GtkWidget *parent_box)
         /* XXX - there's no way to get rid of the shadow frame - except for creating an own widget :-( */
         scrollw = scrolled_window_new(NULL, NULL);
         scrollw_y_size = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW_Y_SIZE));
-           gtk_widget_set_usize(scrollw, -1, scrollw_y_size);
+        gtk_widget_set_size_request(scrollw, -1, scrollw_y_size);
 
         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, scrollw);
         gtk_box_pack_start(GTK_BOX(parent_box), scrollw, TRUE, TRUE, 0);
 
         /* move child_box from parent_box into scrolled window */
-        gtk_widget_ref(child_box);
+        g_object_ref(child_box);
         gtk_container_remove(GTK_CONTAINER(parent_box), child_box);
         gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollw),
                                               child_box);
@@ -149,6 +169,7 @@ scroll_box_dynamic_add(GtkWidget *parent_box)
     return child_box;
 }
 
+
 static GtkWidget *
 scroll_box_dynamic_reset(GtkWidget *parent_box)
 {
@@ -160,7 +181,7 @@ scroll_box_dynamic_reset(GtkWidget *parent_box)
 
     if(scrollw != NULL) {
         /* move the child_box back from scrolled window into the parent_box */
-        gtk_widget_ref(child_box);
+        g_object_ref(child_box);
         gtk_container_remove(GTK_CONTAINER(parent_box), scrollw);
         g_object_set_data(G_OBJECT(parent_box), SCROLL_BOX_SCROLLW, NULL);
         gtk_box_pack_start(GTK_BOX(parent_box), child_box, TRUE, TRUE, 0);
@@ -170,8 +191,6 @@ scroll_box_dynamic_reset(GtkWidget *parent_box)
 }
 
 
-
-
 /* mouse entered this widget - change background color */
 static gboolean
 welcome_item_enter_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
@@ -181,9 +200,10 @@ welcome_item_enter_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_
     return FALSE;
 }
 
+
 /* mouse has left this widget - change background color  */
 static gboolean
-welcome_item_leave_cb(GtkWidget *eb, GdkEvent *event _U_, gpointer user_data _U_)
+welcome_item_leave_cb(GtkWidget *eb, GdkEventCrossing *event _U_, gpointer user_data _U_)
 {
     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
 
@@ -191,18 +211,18 @@ welcome_item_leave_cb(GtkWidget *eb, GdkEvent *event _U_, gpointer user_data _U_
 }
 
 
+typedef gboolean (*welcome_button_callback_t)  (GtkWidget      *widget,
+                                                GdkEventButton *event,
+                                                gpointer        user_data);
+
 /* create a "button widget" */
 static GtkWidget *
 welcome_button(const gchar *stock_item,
-               const gchar * title, const gchar * subtitle, const gchar *tooltip,
-                          GtkSignalFunc callback, void *callback_data)
+               const gchar *title, const gchar *subtitle, const gchar *tooltip,
+               welcome_button_callback_t welcome_button_callback, gpointer welcome_button_callback_data)
 {
     GtkWidget *eb, *w, *item_hb, *text_vb;
     gchar *formatted_text;
-    GtkTooltips *tooltips;
-
-
-    tooltips = gtk_tooltips_new();
 
     item_hb = gtk_hbox_new(FALSE, 1);
 
@@ -211,12 +231,12 @@ welcome_button(const gchar *stock_item,
     gtk_container_add(GTK_CONTAINER(eb), item_hb);
     gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
     if(tooltip != NULL) {
-        gtk_tooltips_set_tip(tooltips, eb, tooltip, "");
+               gtk_widget_set_tooltip_text(eb, tooltip);
     }
 
     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), NULL);
     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), NULL);
-    g_signal_connect(eb, "button-press-event", G_CALLBACK(callback), callback_data);
+    g_signal_connect(eb, "button-release-event", G_CALLBACK(welcome_button_callback), welcome_button_callback_data);
 
     /* icon */
     w = gtk_image_new_from_stock(stock_item, GTK_ICON_SIZE_LARGE_TOOLBAR);
@@ -226,7 +246,7 @@ welcome_button(const gchar *stock_item,
 
     /* title */
     w = gtk_label_new(title);
-    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
+    gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
     formatted_text = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"black\">%s</span>", title);
     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
     g_free(formatted_text);
@@ -234,7 +254,7 @@ welcome_button(const gchar *stock_item,
 
     /* subtitle */
     w = gtk_label_new(subtitle);
-    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
+    gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.5f);
     formatted_text = g_strdup_printf("<span size=\"small\" foreground=\"black\">%s</span>", subtitle);
     gtk_label_set_markup(GTK_LABEL(w), formatted_text);
     g_free(formatted_text);
@@ -246,6 +266,49 @@ welcome_button(const gchar *stock_item,
 }
 
 
+/* Hack to handle welcome-button "button-release-event" callback   */
+/*  1. Dispatch to desired actual callback                         */
+/*  2. Return TRUE for the event callback.                         */
+/* user_data: actual (no arg) callback fcn to be invoked.          */
+static gboolean
+welcome_button_callback_helper(GtkWidget *w, GdkEventButton *event _U_, gpointer user_data)
+{
+    void (*funct)(GtkWidget *, gpointer) = user_data;
+    (*funct)(w, NULL);
+    return TRUE;
+}
+
+
+void
+welcome_header_set_message(gchar *msg) {
+    GString *message;
+    time_t secs = time(NULL);
+    struct tm *now = localtime(&secs);
+
+    message = g_string_new("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">");
+
+    if (msg) {
+        g_string_append(message, msg);
+    } else { /* Use our default header */
+        if ((now->tm_mon == 3 && now->tm_mday == 1) || (now->tm_mon == 6 && now->tm_mday == 14)) {
+            g_string_append(message, "Sniffing the glue that holds the Internet together");
+        } else {
+            g_string_append(message, prefs.gui_start_title);
+        }
+
+        if (prefs.gui_version_in_start_page) {
+            g_string_append_printf(message, "</span>\n<span size=\"large\" foreground=\"white\">Version " VERSION "%s",
+                                   wireshark_svnversion);
+        }
+    }
+
+    g_string_append(message, "</span>");
+
+    gtk_label_set_markup(GTK_LABEL(header_lb), message->str);
+    g_string_free(message, TRUE);
+}
+
+
 /* create the banner "above our heads" */
 static GtkWidget *
 welcome_header_new(void)
@@ -254,10 +317,6 @@ welcome_header_new(void)
     GtkWidget *item_hb;
     GtkWidget *eb;
     GtkWidget *icon;
-    GString *message;
-    GtkWidget *w;
-    time_t secs = time(NULL);
-    struct tm *now = localtime(&secs);
 
     item_vb = gtk_vbox_new(FALSE, 0);
 
@@ -272,28 +331,48 @@ welcome_header_new(void)
     icon = xpm_to_widget_from_parent(top_level, wssplash_xpm);
     gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 10);
 
-    message = g_string_new("<span weight=\"bold\" size=\"x-large\" foreground=\"black\">");
-    if ((now->tm_mon == 3 && now->tm_mday == 1) || (now->tm_mon == 6 && now->tm_mday == 14)) {
-        g_string_append(message, "Sniffing the glue that holds the Internet together");
-    } else {
-        g_string_append(message, prefs.gui_start_title);
-    }
-    g_string_append(message, "</span>");
+    header_lb = gtk_label_new(NULL);
+    welcome_header_set_message(NULL);
+    gtk_label_set_selectable(GTK_LABEL(header_lb), TRUE);
+    gtk_misc_set_alignment(GTK_MISC(header_lb), 0.0f, 0.5f);
+    gtk_box_pack_start(GTK_BOX(item_hb), header_lb, TRUE, TRUE, 5);
+
+    gtk_widget_show_all(eb);
+
+    return eb;
+}
+
 
-    if (prefs.gui_version_in_start_page) {
-        g_string_append_printf(message, "\n<span size=\"large\" foreground=\"black\">Version " VERSION "%s</span>",
-                               wireshark_svnversion);
+void
+welcome_header_push_msg(const gchar *msg) {
+    gchar *msg_copy = g_strdup(msg);
+
+    status_messages = g_slist_append(status_messages, msg_copy);
+
+    welcome_header_set_message(msg_copy);
+
+    gtk_widget_hide(welcome_hb);
+}
+
+
+void
+welcome_header_pop_msg(void) {
+    gchar *msg = NULL;
+
+    if (status_messages) {
+        g_free(status_messages->data);
+        status_messages = g_slist_delete_link(status_messages, status_messages);
     }
 
-    w = gtk_label_new(message->str);
-    gtk_label_set_markup(GTK_LABEL(w), message->str);
-    g_string_free(message, TRUE);
-    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
-    gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
+    if (status_messages) {
+        msg = status_messages->data;
+    }
 
-    gtk_widget_show_all(eb);
+    welcome_header_set_message(msg);
 
-    return eb;
+    if (!status_messages) {
+        gtk_widget_show(welcome_hb);
+    }
 }
 
 
@@ -307,7 +386,7 @@ welcome_topic_header_new(const char *header)
 
 
     w = gtk_label_new(header);
-    formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"black\">%s</span>", header);
+    formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\" foreground=\"white\">%s</span>", header);
     gtk_label_set_markup(GTK_LABEL(w), formatted_message);
     g_free(formatted_message);
 
@@ -351,78 +430,206 @@ welcome_topic_new(const char *header, GtkWidget **to_fill)
 
 /* a file link was pressed */
 static gboolean
-welcome_filename_link_press_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data)
+welcome_filename_link_press_cb(GtkWidget *widget _U_, GdkEventButton *event _U_, gpointer data)
 {
     menu_open_filename(data);
 
     return FALSE;
 }
 
-
-/* create a "file link widget" */
-static GtkWidget *
-welcome_filename_link_new(const gchar *filename, GtkWidget **label)
+typedef struct _recent_item_status {
+    gchar     *filename;
+    GtkWidget *label;
+    GObject   *menu_item;
+    GString   *str;
+    gboolean   stat_done;
+    int        err;
+    guint      timer;
+} recent_item_status;
+
+/*
+ * Fetch the status of a file.
+ * This function might be called as a thread. We can't use any drawing
+ * routines here: http://developer.gnome.org/gdk/2.24/gdk-Threads.html
+ */
+static void *get_recent_item_status(void *data)
 {
-    GtkWidget *w;
-    GtkWidget *eb;
-    GString            *str;
-    const unsigned int max = 60;
+    recent_item_status *ri_stat = (recent_item_status *) data;
+    ws_statb64 stat_buf;
     int err;
-    struct stat stat_buf;
-    GtkTooltips *tooltips;
-
-
-    tooltips = gtk_tooltips_new();
-
-    /* filename */
-    str = g_string_new(filename);
 
-    /* cut max filename length */
-    if( (str->len > max) && (str->len-(max) > 5) ) {
-        g_string_erase(str, 20, str->len-(max+5));
-        g_string_insert(str, 20, " ... ");
+    if (!ri_stat) {
+        return NULL;
     }
 
-    /* add file size */
-    err = ws_stat(filename, &stat_buf);
+    /*
+     * Add file size. We use binary prefixes instead of IEC because that's what
+     * most OSes use.
+     */
+    err = ws_stat64(ri_stat->filename, &stat_buf);
+#ifdef USE_THREADS
+    g_mutex_lock(recent_mtx);
+#endif
+    ri_stat->err = err;
     if(err == 0) {
-        if (stat_buf.st_size/1024/1024 > 10) {
-            g_string_append_printf(str, " %" G_GINT64_MODIFIER "dMB", (gint64) (stat_buf.st_size/1024/1024));
+        if (stat_buf.st_size/1024/1024/1024 > 10) {
+            g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d GB)", (gint64) (stat_buf.st_size/1024/1024/1024));
+        } else if (stat_buf.st_size/1024/1024 > 10) {
+            g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d MB)", (gint64) (stat_buf.st_size/1024/1024));
         } else if (stat_buf.st_size/1024 > 10) {
-            g_string_append_printf(str, " %" G_GINT64_MODIFIER "dKB", (gint64) (stat_buf.st_size/1024));
+            g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d KB)", (gint64) (stat_buf.st_size/1024));
         } else {
-            g_string_append_printf(str, " %" G_GINT64_MODIFIER "d Bytes", (gint64) (stat_buf.st_size));
+            g_string_append_printf(ri_stat->str, " (%" G_GINT64_MODIFIER "d Bytes)", (gint64) (stat_buf.st_size));
         }
+        /* pango format string */
+        g_string_prepend(ri_stat->str, "<span foreground='blue'>");
+        g_string_append(ri_stat->str, "</span>");
     } else {
-        g_string_append(str, " [not found]");
+        g_string_append(ri_stat->str, " [not found]");
     }
 
-    /* pango format string */
-    if(err == 0) {
-        g_string_prepend(str, "<span foreground='blue'>");
-        g_string_append(str, "</span>");
+    if (!ri_stat->label) { /* The widget went away while we were busy. */
+       g_free(ri_stat->filename);
+       g_string_free(ri_stat->str, TRUE);
+       g_free(ri_stat);
+    } else {
+        ri_stat->stat_done = TRUE;
+    }
+#ifdef USE_THREADS
+    g_mutex_unlock(recent_mtx);
+#endif
+
+    return NULL;
+}
+
+/* Timeout callback for recent items */
+static gboolean
+update_recent_items(gpointer data)
+{
+    recent_item_status *ri_stat = (recent_item_status *) data;
+    gboolean again = TRUE;
+
+    if (!ri_stat) {
+        return FALSE;
+    }
+
+#ifdef USE_THREADS
+    g_mutex_lock(recent_mtx);
+#endif
+    if (ri_stat->stat_done) {
+        again = FALSE;
+        gtk_label_set_markup(GTK_LABEL(ri_stat->label), ri_stat->str->str);
+       if (ri_stat->err == 0) {
+           gtk_widget_set_sensitive(ri_stat->label, TRUE);
+#ifdef MAIN_MENU_USE_UIMANAGER
+           gtk_action_set_sensitive((GtkAction *) ri_stat->menu_item, TRUE);
+#else
+           gtk_widget_set_sensitive(GTK_WIDGET(ri_stat->menu_item), TRUE);
+#endif
+       }
+        ri_stat->timer = 0;
+    }
+    /* Else append some sort of Unicode or ASCII animation to the label? */
+#ifdef USE_THREADS
+    g_mutex_unlock(recent_mtx);
+#endif
+    return again;
+}
+
+static void welcome_filename_destroy_cb(GtkWidget *w _U_, gpointer data) {
+    recent_item_status *ri_stat = (recent_item_status *) data;
+
+    if (!ri_stat) {
+       return;
+    }
+
+#ifdef USE_THREADS
+    g_mutex_lock(recent_mtx);
+#endif
+    if (ri_stat->timer) {
+       g_source_remove(ri_stat->timer);
+       ri_stat->timer = 0;
+    }
+
+    g_object_unref(ri_stat->menu_item);
+
+    if (ri_stat->stat_done) {
+       g_free(ri_stat->filename);
+       g_string_free(ri_stat->str, TRUE);
+       g_free(ri_stat);
+    } else {
+        ri_stat->label = NULL;
+    }
+#ifdef USE_THREADS
+    g_mutex_unlock(recent_mtx);
+#endif
+}
+
+/* create a "file link widget" */
+static GtkWidget *
+welcome_filename_link_new(const gchar *filename, GtkWidget **label, GObject *menu_item)
+{
+    GtkWidget   *w;
+    GtkWidget   *eb;
+    GString     *str;
+    gchar       *str_escaped;
+    glong        uni_len;
+    gsize        uni_start, uni_end;
+    const glong  max = 60;
+    recent_item_status *ri_stat;
+
+    /* filename */
+    str = g_string_new(filename);
+    uni_len = g_utf8_strlen(str->str, str->len);
+
+    /* cut max filename length */
+    if (uni_len > max) {
+        uni_start = g_utf8_offset_to_pointer(str->str, 20) - str->str;
+        uni_end = g_utf8_offset_to_pointer(str->str, uni_len - max) - str->str;
+        g_string_erase(str, uni_start, uni_end);
+        g_string_insert(str, uni_start, " " UTF8_HORIZONTAL_ELLIPSIS " ");
     }
 
+    /* escape the possibly shortened filename before adding pango language */
+    str_escaped=g_markup_escape_text(str->str, -1);
+    g_string_free(str, TRUE);
+
     /* label */
-    w = gtk_label_new(str->str);
+    w = gtk_label_new(str_escaped);
     *label = w;
-    gtk_label_set_markup(GTK_LABEL(w), str->str);
     gtk_misc_set_padding(GTK_MISC(w), 5, 2);
+    gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
+    gtk_widget_set_sensitive(w, FALSE);
+
+    ri_stat = g_malloc(sizeof(recent_item_status));
+    ri_stat->filename = g_strdup(filename);
+    ri_stat->label = w;
+    ri_stat->menu_item = menu_item;
+    ri_stat->str = g_string_new(str_escaped);
+    ri_stat->stat_done = FALSE;
+    ri_stat->timer = 0;
+    g_object_ref(G_OBJECT(menu_item));
+    g_signal_connect(w, "destroy", G_CALLBACK(welcome_filename_destroy_cb), ri_stat);
+    g_free(str_escaped);
+
+#ifdef USE_THREADS
+    g_thread_create(get_recent_item_status, ri_stat, FALSE, NULL);
+    ri_stat->timer = g_timeout_add(200, update_recent_items, ri_stat);
+#else
+    get_recent_item_status(ri_stat);
+    update_recent_items(ri_stat);
+#endif
 
-       /* event box */
+    /* event box */
     eb = gtk_event_box_new();
+    gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
     gtk_container_add(GTK_CONTAINER(eb), w);
-    gtk_tooltips_set_tip(tooltips, eb, filename, "");
-    if(err != 0) {
-        gtk_widget_set_sensitive(w, FALSE);
-    }
+    gtk_widget_set_tooltip_text(eb, filename);
 
     g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), w);
     g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), w);
     g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_filename_link_press_cb), (gchar *) filename);
 
-    g_string_free(str, TRUE);
-
     return eb;
 }
 
@@ -453,160 +660,205 @@ main_welcome_reset_recent_capture_files(void)
 
 /* add a new file to the list of recent files */
 void
-main_welcome_add_recent_capture_files(const char *widget_cf_name)
+main_welcome_add_recent_capture_file(const char *widget_cf_name, GObject *menu_item)
 {
     GtkWidget *w;
     GtkWidget *child_box;
     GtkWidget *label;
 
 
-    w = welcome_filename_link_new(widget_cf_name, &label);
-    gtk_widget_modify_bg(w, GTK_STATE_NORMAL, &topic_item_idle_bg);
-    gtk_misc_set_alignment (GTK_MISC(label), 0.0, 0.0);
+    w = welcome_filename_link_new(widget_cf_name, &label, menu_item);
     child_box = scroll_box_dynamic_add(welcome_file_panel_vb);
     gtk_box_pack_start(GTK_BOX(child_box), w, FALSE, FALSE, 0);
     gtk_widget_show_all(w);
     gtk_widget_show_all(child_box);
 }
 
-
 #ifdef HAVE_LIBPCAP
-/* user clicked on an interface button */
-static gboolean
-welcome_if_press_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data)
+static gboolean select_current_ifaces(GtkTreeModel  *model,
+                                  GtkTreePath   *path _U_,
+                                  GtkTreeIter   *iter,
+                                  gpointer       userdata)
 {
-    g_free(global_capture_opts.iface);
-    g_free(global_capture_opts.iface_descr);
-
-    global_capture_opts.iface = g_strdup(data);
-    global_capture_opts.iface_descr = NULL;
-    /* XXX - fix this */
-    /*global_capture_opts.iface_descr = get_interface_descriptive_name(global_capture_opts.iface);*/
-
-    /* XXX - remove this? */
-    if (global_capture_opts.save_file) {
-        g_free(global_capture_opts.save_file);
-        global_capture_opts.save_file = NULL;
+    guint i;
+    gchar *if_name;
+    gboolean found = FALSE;
+
+    GtkTreeSelection *selection = (GtkTreeSelection *)userdata;
+    gtk_tree_model_get (model, iter, IFACE_NAME, &if_name, -1);
+    for (i = 0; i < global_capture_opts.ifaces->len; i++) {
+        if (strcmp(g_array_index(global_capture_opts.ifaces, interface_options, i).name, if_name) == 0) {
+            gtk_tree_selection_select_iter(selection, iter);
+            found = TRUE;
+            break;
+        }
+    }
+    if (!found) {
+        gtk_tree_selection_unselect_iter(selection, iter);
     }
-
-#ifdef HAVE_AIRPCAP
-    airpcap_if_active = get_airpcap_if_from_name(airpcap_if_list, global_capture_opts.iface);
-    airpcap_if_selected = airpcap_if_active;
-    airpcap_set_toolbar_start_capture(airpcap_if_active);
-#endif
-
-    capture_start_cb(NULL, NULL);
-
     return FALSE;
 }
 
-
-/* create a single interface entry */
-static GtkWidget *
-welcome_if_new(const if_info_t *if_info, const gchar *user_descr, GdkColor *topic_bg _U_, gpointer interf)
+gboolean on_selection_changed(GtkTreeSelection *selection _U_,
+                              GtkTreeModel *model,
+                              GtkTreePath *path,
+                              gboolean path_currently_selected,
+                              gpointer data _U_)
 {
-    GtkWidget *interface_hb;
-    GtkWidget *w;
-    GString   *message;
-    GtkWidget *eb;
-
-
-    /* event box */
-    eb = gtk_event_box_new();
-    gtk_widget_modify_bg(eb, GTK_STATE_NORMAL, &topic_item_idle_bg);
-
-    g_signal_connect(eb, "enter-notify-event", G_CALLBACK(welcome_item_enter_cb), NULL);
-    g_signal_connect(eb, "leave-notify-event", G_CALLBACK(welcome_item_leave_cb), NULL);
-    g_signal_connect(eb, "button-press-event", G_CALLBACK(welcome_if_press_cb), interf);
-
-    interface_hb = gtk_hbox_new(FALSE, 5);
-    gtk_container_add(GTK_CONTAINER(eb), interface_hb);
-
-    /* icon */
-    w = capture_get_if_icon(if_info);
-    gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 5);
-
-    if (user_descr != NULL)
-        message = g_string_new(user_descr);
-    else if (if_info->description != NULL)
-        message = g_string_new(if_info->description);
-    else
-        message = g_string_new(if_info->name);
-
-    /* truncate string if it's too long */
-    /* (the number of chars is a bit arbitrary, though) */
-    if(message->len > 48) {
-        g_string_truncate(message, 45);
-        g_string_append  (message, " ...");
+    GtkTreeIter  iter;
+    gchar *if_name;
+    interface_options interface_opts;
+    guint i;
+    cap_settings_t    cap_settings;
+    gboolean found = FALSE;
+    
+    gtk_tree_model_get_iter (model, &iter, path);
+    gtk_tree_model_get (model, &iter, IFACE_NAME, &if_name, -1);
+    for (i = 0; i < global_capture_opts.ifaces->len; i++) {
+        if (strcmp(g_array_index(global_capture_opts.ifaces, interface_options, i).name, if_name) == 0) {
+            found = TRUE;
+            if (path_currently_selected) {
+                interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, i);
+                global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, i);
+                g_free(interface_opts.name);
+                g_free(interface_opts.descr);
+                g_free(interface_opts.cfilter);
+#ifdef HAVE_PCAP_REMOTE
+                g_free(interface_opts.remote_host);
+                g_free(interface_opts.remote_port);
+                g_free(interface_opts.auth_username);
+                g_free(interface_opts.auth_password);
+#endif
+                break;
+            }
+        } 
+    } 
+    if (!found && !path_currently_selected) {
+        interface_opts.name = g_strdup(if_name);
+        interface_opts.descr = get_interface_descriptive_name(interface_opts.name);
+        interface_opts.linktype = capture_dev_user_linktype_find(interface_opts.name);
+        interface_opts.cfilter = g_strdup(global_capture_opts.default_options.cfilter);
+        interface_opts.has_snaplen = global_capture_opts.default_options.has_snaplen;
+        interface_opts.snaplen = global_capture_opts.default_options.snaplen;
+        cap_settings = capture_get_cap_settings (interface_opts.name);;
+        interface_opts.promisc_mode = global_capture_opts.default_options.promisc_mode;
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
+        interface_opts.buffer_size =  global_capture_opts.default_options.buffer_size;
+#endif
+        interface_opts.monitor_mode = cap_settings.monitor_mode;
+#ifdef HAVE_PCAP_REMOTE
+        interface_opts.src_type = global_capture_opts.default_options.src_type;
+        interface_opts.remote_host = g_strdup(global_capture_opts.default_options.remote_host);
+        interface_opts.remote_port = g_strdup(global_capture_opts.default_options.remote_port);
+        interface_opts.auth_type = global_capture_opts.default_options.auth_type;
+        interface_opts.auth_username = g_strdup(global_capture_opts.default_options.auth_username);
+        interface_opts.auth_password = g_strdup(global_capture_opts.default_options.auth_password);
+        interface_opts.datatx_udp = global_capture_opts.default_options.datatx_udp;
+        interface_opts.nocap_rpcap = global_capture_opts.default_options.nocap_rpcap;
+        interface_opts.nocap_local = global_capture_opts.default_options.nocap_local;
+#endif
+#ifdef HAVE_PCAP_SETSAMPLING
+        interface_opts.sampling_method = global_capture_opts.default_options.sampling_method;
+        interface_opts.sampling_param  = global_capture_opts.default_options.sampling_param;
+#endif
+        g_array_append_val(global_capture_opts.ifaces, interface_opts);
     }
-    g_string_prepend(message, "<span foreground='blue'>");
-    g_string_append (message, "</span>");
-    w = gtk_label_new(message->str);
-    gtk_label_set_markup(GTK_LABEL(w), message->str);
-    g_string_free(message, TRUE);
-
-    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
-    gtk_box_pack_start(GTK_BOX(interface_hb), w, FALSE, FALSE, 0);
-
-    return eb;
+    return TRUE;
 }
+#endif
 
-
-/* load the list of interfaces */
-static void
-welcome_if_panel_load(void)
+void
+select_ifaces(void)
 {
-  GtkWidget *child_box;
-  GtkWidget *interface_hb;
-
-  if_info_t     *if_info;
-  GList         *if_list;
-  int err;
-  gchar         *err_str;
-  int           ifs;
-  GList         *curr;
-  gchar         *user_descr;
-
-
-  /* LOAD THE INTERFACES */
-  if_list = capture_interface_list(&err, &err_str);
-  if_list = g_list_sort (if_list, if_list_comparator_alph);
-  if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
-    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
-    g_free(err_str);
-    return;
-  }
-
-  /* List the interfaces */
-  for(ifs = 0; (curr = g_list_nth(if_list, ifs)); ifs++) {
-      /*g_string_assign(if_tool_str, "");*/
-      if_info = curr->data;
+#ifdef HAVE_LIBPCAP
+    GtkWidget        *view;
+    GtkTreeModel     *model;
+    GtkTreeSelection *entry;
+
+    if (global_capture_opts.ifaces->len > 0) {
+        view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
+        model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
+        entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+        gtk_tree_model_foreach(GTK_TREE_MODEL(model), select_current_ifaces, (gpointer) entry);
+        gtk_widget_grab_focus(view);
+    }
+#endif
+}
 
-      /* Continue if capture device is hidden */
-      if (prefs_is_capture_device_hidden(if_info->name)) {
-          continue;
-      }
+/* list the interfaces */
+void
+welcome_if_tree_load(void)
+{
+#ifdef HAVE_LIBPCAP
+    if_info_t     *if_info;
+    GList         *if_list;
+    int err;
+    gchar         *err_str = NULL;
+    GList         *curr;
+    gchar         *user_descr;
+    GtkListStore  *store = NULL;
+    GtkTreeIter   iter;
+    GtkWidget     *icon, *view;
+    GtkTreeSelection *entry;
+
+    /* LOAD THE INTERFACES */
+    if_list = capture_interface_list(&err, &err_str);
+    if_list = g_list_sort (if_list, if_list_comparator_alph);
+    if (if_list == NULL && err == CANT_GET_INTERFACE_LIST) {
+        simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", err_str);
+        g_free(err_str);
+        return;
+    } else if (err_str) {
+        g_free(err_str);
+    }
+    if (g_list_length(if_list) > 0) {
+        view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
+        entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+        gtk_tree_selection_unselect_all(entry);
+        store = gtk_list_store_new(NUMCOLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING);
+        /* List the interfaces */
+        for (curr = g_list_first(if_list); curr; curr = g_list_next(curr)) {
+            if_info = curr->data;
+            /* Continue if capture device is hidden */
+            if (prefs_is_capture_device_hidden(if_info->name)) {
+                continue;
+            }
+            gtk_list_store_append (store, &iter);
 
-      user_descr = capture_dev_user_descr_find(if_info->name);
-      if (user_descr) {
+#ifdef HAVE_AIRPCAP
+            if (get_airpcap_if_from_name(airpcap_if_list,if_info->name) != NULL)
+                icon = xpm_to_widget(capture_airpcap_16_xpm);
+            else
+                icon = capture_get_if_icon(if_info);
+#else
+            icon = capture_get_if_icon(if_info);
+#endif
+            user_descr = capture_dev_user_descr_find(if_info->name);
+            if (user_descr) {
 #ifndef _WIN32
-        gchar *comment = user_descr;
-        user_descr = g_strdup_printf("%s (%s)", comment, if_info->name);
-        g_free (comment);
-#endif
-        interface_hb = welcome_if_new(if_info, user_descr, &topic_content_bg, g_strdup(if_info->name));
-        g_free (user_descr);
-      } else {
-        interface_hb = welcome_if_new(if_info, NULL, &topic_content_bg, g_strdup(if_info->name));
-      }
-
-      child_box = scroll_box_dynamic_add(welcome_if_panel_vb);
-      gtk_box_pack_start(GTK_BOX(child_box), interface_hb, FALSE, FALSE, 1);
-  }
-
-  free_interface_list(if_list);
-}
+                gchar *comment = user_descr;
+                user_descr = g_strdup_printf("%s (%s)", comment, if_info->name);
+                g_free (comment);
+#endif
+                gtk_list_store_set(store, &iter, ICON, gtk_image_get_pixbuf(GTK_IMAGE(icon)), IFACE_DESCR, user_descr, IFACE_NAME, if_info->name, -1);
+                g_free (user_descr);
+            } else if (if_info->description) {
+                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);
+            } else {
+                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);
+            }
+        }
+        gtk_tree_view_set_model(GTK_TREE_VIEW(if_view), GTK_TREE_MODEL (store));
+        if (global_capture_opts.ifaces->len > 0) {
+            gtk_tree_model_foreach(GTK_TREE_MODEL(store), select_current_ifaces, (gpointer) entry);
+            gtk_widget_grab_focus(view);
+        }
+        gtk_tree_selection_set_select_function(entry, on_selection_changed, NULL, NULL);
+    }
+    free_interface_list(if_list);
 #endif  /* HAVE_LIBPCAP */
+}
+
 
 /* reload the list of interfaces */
 void
@@ -629,89 +881,213 @@ welcome_if_panel_reload(void)
         }
 
         g_list_free(child_list);
-
-       welcome_if_panel_load();
-       gtk_widget_show_all(welcome_if_panel_vb);
+        welcome_if_tree_load();
+        gtk_widget_show_all(welcome_if_panel_vb);
     }
 #endif  /* HAVE_LIBPCAP */
 }
 
+#ifdef HAVE_LIBPCAP
+static void make_selections_array(GtkTreeModel  *model,
+                                  GtkTreePath   *path _U_,
+                                  GtkTreeIter   *iter,
+                                  gpointer       userdata _U_)
+{
+  gchar            *if_name;
+  interface_options interface_opts;
+  cap_settings_t    cap_settings;
+  GList            *if_list;
+  GList            *curr;
+  int               err;
+  if_info_t        *if_info;
+
+  gtk_tree_model_get (model, iter, IFACE_NAME, &if_name, -1);
+
+  if_list = capture_interface_list(&err, NULL);
+  if_list = g_list_sort (if_list, if_list_comparator_alph);
+  if (g_list_length(if_list) > 0) {
+      for (curr = g_list_first(if_list); curr; curr = g_list_next(curr)) {
+          if_info = curr->data;
+          /* Continue if capture device is hidden */
+          if (prefs_is_capture_device_hidden(if_info->name)) {
+              continue;
+          }
+          if (strcmp(if_info->name, if_name) == 0) {
+              interface_opts.name = g_strdup(if_name);
+              interface_opts.descr = get_interface_descriptive_name(interface_opts.name);
+              break;
+          }
+      }
+      free_interface_list(if_list);
+  } else {
+      free_interface_list(if_list);
+      return;
+  }
+
+  interface_opts.linktype = capture_dev_user_linktype_find(interface_opts.name);
+  interface_opts.cfilter = g_strdup(global_capture_opts.default_options.cfilter);
+  interface_opts.has_snaplen = global_capture_opts.default_options.has_snaplen;
+  interface_opts.snaplen = global_capture_opts.default_options.snaplen;
+  cap_settings = capture_get_cap_settings (interface_opts.name);;
+  interface_opts.promisc_mode = global_capture_opts.default_options.promisc_mode;
+#if defined(_WIN32) || defined(HAVE_PCAP_CREATE)
+  interface_opts.buffer_size =  global_capture_opts.default_options.buffer_size;
+#endif
+  interface_opts.monitor_mode = cap_settings.monitor_mode;
+#ifdef HAVE_PCAP_REMOTE
+  interface_opts.src_type = global_capture_opts.default_options.src_type;
+  interface_opts.remote_host = g_strdup(global_capture_opts.default_options.remote_host);
+  interface_opts.remote_port = g_strdup(global_capture_opts.default_options.remote_port);
+  interface_opts.auth_type = global_capture_opts.default_options.auth_type;
+  interface_opts.auth_username = g_strdup(global_capture_opts.default_options.auth_username);
+  interface_opts.auth_password = g_strdup(global_capture_opts.default_options.auth_password);
+  interface_opts.datatx_udp = global_capture_opts.default_options.datatx_udp;
+  interface_opts.nocap_rpcap = global_capture_opts.default_options.nocap_rpcap;
+  interface_opts.nocap_local = global_capture_opts.default_options.nocap_local;
+#endif
+#ifdef HAVE_PCAP_SETSAMPLING
+  interface_opts.sampling_method = global_capture_opts.default_options.sampling_method;
+  interface_opts.sampling_param  = global_capture_opts.default_options.sampling_param;
+#endif
+  g_array_append_val(global_capture_opts.ifaces, interface_opts);
+}
+
+static void capture_if_start(GtkWidget *w _U_, gpointer data _U_)
+{
+  GtkTreeSelection *entry;
+  GtkWidget*   view;
+  gint len;
+  interface_options  interface_opts;
+
+  view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
+  entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+  len = gtk_tree_selection_count_selected_rows(entry);
+  if (!entry || len == 0) {
+    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+      "You didn't specify an interface on which to capture packets.");
+    return;
+  }
+#ifndef USE_THREADS
+  if (len > 1) {
+    simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK,
+      "You specified multiple interfaces for capturing which this version of Wireshark doesn't support.");
+    return;
+  }
+#endif
+  while (global_capture_opts.ifaces->len > 0) {
+    interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, 0);
+    global_capture_opts.ifaces = g_array_remove_index(global_capture_opts.ifaces, 0);
+    g_free(interface_opts.name);
+    g_free(interface_opts.descr);
+    g_free(interface_opts.cfilter);
+#ifdef HAVE_PCAP_REMOTE
+    g_free(interface_opts.remote_host);
+    g_free(interface_opts.remote_port);
+    g_free(interface_opts.auth_username);
+    g_free(interface_opts.auth_password);
+#endif
+  }
+  gtk_tree_selection_selected_foreach(entry, make_selections_array, NULL);
+
+  /* XXX - remove this? */
+  if (global_capture_opts.save_file) {
+      g_free(global_capture_opts.save_file);
+      global_capture_opts.save_file = NULL;
+  }
+#ifdef HAVE_AIRPCAP
+  interface_opts = g_array_index(global_capture_opts.ifaces, interface_options, 0);
+  airpcap_if_active = get_airpcap_if_from_name(airpcap_if_list, interface_opts.name);
+  airpcap_if_selected = airpcap_if_active;
+  airpcap_set_toolbar_start_capture(airpcap_if_active);
+#endif
+  capture_start_cb(NULL, NULL);
+}
+
+void capture_if_cb_prep(GtkWidget *w _U_, gpointer d _U_)
+{
+  GtkTreeSelection *entry;
+  GtkWidget* view;
+
+  view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
+  entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+  if (entry) {
+   /* global_capture_opts.number_of_ifaces = gtk_tree_selection_count_selected_rows(entry);*/
+    gtk_tree_selection_selected_foreach(entry, make_selections_array, NULL);
+  }
+  capture_if_cb(NULL, NULL);
+}
+
+void capture_opts_cb_prep(GtkWidget *w _U_, gpointer d _U_)
+{
+  GtkTreeSelection *entry;
+  GtkWidget* view;
+
+  view = g_object_get_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES);
+  entry = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
+  if (entry) {
+    gtk_tree_selection_selected_foreach(entry, make_selections_array, NULL);
+  }
+  capture_prep_cb(NULL, NULL);
+}
+#endif
 
 /* create the welcome page */
 GtkWidget *
 welcome_new(void)
 {
     GtkWidget *welcome_scrollw;
+    GtkWidget *welcome_eb;
     GtkWidget *welcome_vb;
-    GtkWidget *welcome_hb;
     GtkWidget *column_vb;
     GtkWidget *item_hb;
     GtkWidget *w;
     GtkWidget *header;
     GtkWidget *topic_vb;
     GtkWidget *topic_to_fill;
-#ifdef HAVE_LIBPCAP
-    GtkWidget *if_child_box;
-#endif  /* HAVE_LIBPCAP */
     GtkWidget *file_child_box;
     gchar *label_text;
-
+#ifdef _WIN32
+    LONG reg_ret;
+    DWORD chimney_enabled = 0;
+    DWORD ce_size = sizeof(chimney_enabled);
+#endif
+#ifdef HAVE_LIBPCAP
+    GtkWidget *swindow;
+    GtkTreeSelection *selection;
+    GtkCellRenderer *renderer;
+    GtkTreeViewColumn *column;
+    GList     *if_list;
+    int err;
+    gchar *err_str = NULL;
+#endif
 
     /* prepare colors */
+
+    /* "page" background */
+    get_color(&welcome_bg);
+
     /* header bar background color */
-    header_bar_bg.pixel = 0;
-    header_bar_bg.red = 154 * 255;
-    header_bar_bg.green = 210 * 255;
-    header_bar_bg.blue = 229 * 255;
     get_color(&header_bar_bg);
 
     /* topic header background color */
-    topic_header_bg.pixel = 0;
-    topic_header_bg.red = 24 * 255;
-    topic_header_bg.green = 151 * 255;
-    topic_header_bg.blue = 192 * 255;
     get_color(&topic_header_bg);
 
     /* topic content background color */
-    topic_content_bg.pixel = 0;
-    topic_content_bg.red = 221 * 255;
-    topic_content_bg.green = 226 * 255;
-    topic_content_bg.blue = 228 * 255;
     get_color(&topic_content_bg);
 
-    /* topic item idle background color */
-    /*topic_item_idle_bg.pixel = 0;
-    topic_item_idle_bg.red = 216 * 255;
-    topic_item_idle_bg.green = 221 * 255;
-    topic_item_idle_bg.blue = 223 * 255;
-    get_color(&topic_item_idle_bg);*/
-
     topic_item_idle_bg = topic_content_bg;
 
     /* topic item entered color */
-    topic_item_entered_bg.pixel = 0;
-    topic_item_entered_bg.red = 211 * 255;
-    topic_item_entered_bg.green = 216 * 255;
-    topic_item_entered_bg.blue = 218 * 255;
     get_color(&topic_item_entered_bg);
 
-    /*topic_item_entered_bg.pixel = 0;
-    topic_item_entered_bg.red = 216 * 255;
-    topic_item_entered_bg.green = 221 * 255;
-    topic_item_entered_bg.blue = 223 * 255;
-    get_color(&topic_item_entered_bg);*/
-
-    /*topic_item_entered_bg.pixel = 0;
-    topic_item_entered_bg.red = 154 * 255;
-    topic_item_entered_bg.green = 210 * 255;
-    topic_item_entered_bg.blue = 229 * 255;
-    get_color(&topic_item_entered_bg);*/
-
-
     welcome_scrollw = scrolled_window_new(NULL, NULL);
 
     welcome_vb = gtk_vbox_new(FALSE, 0);
 
+    welcome_eb = gtk_event_box_new();
+    gtk_container_add(GTK_CONTAINER(welcome_eb), welcome_vb);
+    gtk_widget_modify_bg(welcome_eb, GTK_STATE_NORMAL, &welcome_bg);
+
     /* header */
     header = welcome_header_new();
     gtk_box_pack_start(GTK_BOX(welcome_vb), header, FALSE, FALSE, 0);
@@ -724,6 +1100,7 @@ welcome_new(void)
 
     /* column capture */
     column_vb = gtk_vbox_new(FALSE, 10);
+    gtk_widget_modify_bg(column_vb, GTK_STATE_NORMAL, &welcome_bg);
     gtk_box_pack_start(GTK_BOX(welcome_hb), column_vb, TRUE, TRUE, 0);
 
     /* capture topic */
@@ -731,57 +1108,119 @@ welcome_new(void)
     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
 
 #ifdef HAVE_LIBPCAP
-    item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_INTERFACES,
-        "Interface List",
-               "Live list of the capture interfaces (counts incoming packets)",
-        "Same as Capture/Interfaces menu or toolbar item",
-        GTK_SIGNAL_FUNC(capture_if_cb), NULL);
-    gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
-
-    label_text =  g_strdup("<span foreground=\"black\">Start capture on interface:</span>");
-    w = gtk_label_new(label_text);
-    gtk_label_set_markup(GTK_LABEL(w), label_text);
-    g_free (label_text);
-    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
-    gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
+    if_list = capture_interface_list(&err, &err_str);
+    if (g_list_length(if_list) > 0) {
+        item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_INTERFACES,
+            "Interface List",
+            "Live list of the capture interfaces\n(counts incoming packets)",
+            "Same as Capture/Interfaces menu or toolbar item",
+            welcome_button_callback_helper, capture_if_cb_prep);
+        gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
+
+        swindow = gtk_scrolled_window_new (NULL, NULL);
+        gtk_widget_set_size_request(swindow, FALSE, 100);
+        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(swindow), GTK_SHADOW_IN);
+        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+        if_view = gtk_tree_view_new ();
+        g_object_set(GTK_OBJECT(if_view), "headers-visible", FALSE, NULL);
+        g_object_set_data(G_OBJECT(welcome_hb), TREE_VIEW_INTERFACES, if_view);
+        renderer = gtk_cell_renderer_pixbuf_new();
+        column = gtk_tree_view_column_new_with_attributes ("",
+                                               GTK_CELL_RENDERER(renderer),
+                                               "pixbuf", ICON,
+                                               NULL);
+        gtk_tree_view_append_column(GTK_TREE_VIEW(if_view), column);
+        renderer = gtk_cell_renderer_text_new();
+        column = gtk_tree_view_column_new_with_attributes ("",
+                                               GTK_CELL_RENDERER(renderer),
+                                               "text", IFACE_DESCR,
+                                               NULL);
+        gtk_tree_view_append_column(GTK_TREE_VIEW(if_view), column);
+        gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(if_view), 0), TRUE);
+        renderer = gtk_cell_renderer_text_new();
+        column = gtk_tree_view_column_new_with_attributes ("",
+                                               GTK_CELL_RENDERER(renderer),
+                                               "text", IFACE_NAME,
+                                               NULL);
+        gtk_tree_view_append_column(GTK_TREE_VIEW(if_view), column);
+        gtk_tree_view_column_set_visible(column, FALSE);
+        selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(if_view));
+        gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
+#ifdef USE_THREADS
+        item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_START,
+            "Start",
+            "Choose one or more interfaces to capture from, then <b>Start</b>",
+            "Same as Capture/Interfaces with default options",
+            (welcome_button_callback_t)capture_if_start, (gpointer)if_view);
+#else
+        item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_START,
+            "Start",
+            "Choose exactly one interface to capture from, then <b>Start</b>",
+            "Same as Capture/Interfaces with default options",
+            (welcome_button_callback_t)capture_if_start, (gpointer)if_view);
+#endif
+        gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
+        welcome_if_tree_load();
+        gtk_container_add (GTK_CONTAINER (swindow), if_view);
+        gtk_container_add(GTK_CONTAINER(topic_to_fill), swindow);
+
+        item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_OPTIONS,
+                "Capture Options",
+                "Start a capture with detailed options",
+                "Same as Capture/Options menu or toolbar item",
+                welcome_button_callback_helper, capture_prep_cb);
+        gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
+#ifdef _WIN32
+        /* Check for chimney offloading */
+        reg_ret = RegQueryValueEx(HKEY_LOCAL_MACHINE,
+                                  _T("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\EnableTCPChimney"),
+                                  NULL, NULL, (LPBYTE) &chimney_enabled, &ce_size);
+        if (reg_ret == ERROR_SUCCESS && chimney_enabled) {
+            item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
+                    "Offloading Detected",
+                    "TCP Chimney offloading is enabled. You \nmight not capture much data.",
+                    topic_online_url(ONLINEPAGE_CHIMNEY),
+                    topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_CHIMNEY));
+            gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
+        }
+#endif /* _WIN32 */
+    } else {
+        label_text =  g_strdup("No interface can be used for capturing in\n"
+                               "this system with the current configuration.\n\n"
+                               "See Capture Help below for details.");
+        w = gtk_label_new(label_text);
+        gtk_label_set_markup(GTK_LABEL(w), label_text);
+        g_free (label_text);
+        gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
+        gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
+    }
 
-    if_child_box = gtk_vbox_new(FALSE, 0);
-    /* 8 capture interfaces or 150 pixels height is about the size */
-    /* that still fits on a screen of about 1000*700 */
-    welcome_if_panel_vb = scroll_box_dynamic_new(GTK_BOX(if_child_box), 8, 150);
-    gtk_box_pack_start(GTK_BOX(topic_to_fill), welcome_if_panel_vb, FALSE, FALSE, 0);
-    welcome_if_panel_load();
-
-    item_hb = welcome_button(WIRESHARK_STOCK_CAPTURE_OPTIONS,
-        "Capture Options",
-               "Start a capture with detailed options",
-        "Same as Capture/Options menu or toolbar item",
-        GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
-    gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
+    free_interface_list(if_list);
 
     /* capture help topic */
     topic_vb = welcome_topic_new("Capture Help", &topic_to_fill);
     gtk_box_pack_start(GTK_BOX(column_vb), topic_vb, TRUE, TRUE, 0);
 
     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
-               "How to Capture",
-               "Step by step to a successful capture setup",
+        "How to Capture",
+        "Step by step to a successful capture setup",
         topic_online_url(ONLINEPAGE_CAPTURE_SETUP),
-        GTK_SIGNAL_FUNC(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_CAPTURE_SETUP));
+        topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_CAPTURE_SETUP));
     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
 
     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
-               "Network Media",
-        "Specific information for capturing on: Ethernet, WLAN, ...",
+        "Network Media",
+        "Specific information for capturing on:\nEthernet, WLAN, ...",
         topic_online_url(ONLINEPAGE_NETWORK_MEDIA),
-        GTK_SIGNAL_FUNC(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_NETWORK_MEDIA));
+        topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_NETWORK_MEDIA));
     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
 #else
     label_text =  g_strdup("<span foreground=\"black\">Capturing is not compiled into this version of Wireshark!</span>");
     w = gtk_label_new(label_text);
     gtk_label_set_markup(GTK_LABEL(w), label_text);
     g_free (label_text);
-    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
+    gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
 #endif  /* HAVE_LIBPCAP */
 
@@ -796,9 +1235,9 @@ welcome_new(void)
 
     item_hb = welcome_button(GTK_STOCK_OPEN,
         "Open",
-               "Open a previously captured file",
+        "Open a previously captured file",
         "Same as File/Open menu or toolbar item",
-        GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
+        welcome_button_callback_helper, file_open_cmd_cb);
     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
 
     /* prepare list of recent files (will be filled in later) */
@@ -806,20 +1245,20 @@ welcome_new(void)
     w = gtk_label_new(label_text);
     gtk_label_set_markup(GTK_LABEL(w), label_text);
     g_free (label_text);
-    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
+    gtk_misc_set_alignment (GTK_MISC(w), 0.0f, 0.0f);
     gtk_box_pack_start(GTK_BOX(topic_to_fill), w, FALSE, FALSE, 5);
 
     file_child_box = gtk_vbox_new(FALSE, 1);
     /* 17 file items or 300 pixels height is about the size */
     /* that still fits on a screen of about 1000*700 */
-    welcome_file_panel_vb = scroll_box_dynamic_new(GTK_BOX(file_child_box), 17, 300);
+    welcome_file_panel_vb = scroll_box_dynamic_new(GTK_WIDGET(file_child_box), 17, 300);
     gtk_box_pack_start(GTK_BOX(topic_to_fill), welcome_file_panel_vb, FALSE, FALSE, 0);
 
     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
         "Sample Captures",
-               "A rich assortment of example capture files on the wiki",
+        "A rich assortment of example capture files on the wiki",
         topic_online_url(ONLINEPAGE_SAMPLE_CAPTURES),
-        GTK_SIGNAL_FUNC(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_SAMPLE_CAPTURES));
+        topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_SAMPLE_CAPTURES));
     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
 
     /* fill bottom space */
@@ -837,23 +1276,33 @@ welcome_new(void)
 
     item_hb = welcome_button(GTK_STOCK_HOME,
         "Website",
-               "Visit the project's website",
+        "Visit the project's website",
         topic_online_url(ONLINEPAGE_HOME),
-        GTK_SIGNAL_FUNC(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
+        topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_HOME));
     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
 
+#ifdef HHC_DIR
     item_hb = welcome_button(GTK_STOCK_HELP,
         "User's Guide",
-               "The User's Guide (local version, if installed)",
+        "The User's Guide "
+        "(local version, if installed)",
         "Locally installed (if installed) otherwise online version",
-        GTK_SIGNAL_FUNC(topic_menu_cb), GINT_TO_POINTER(HELP_CONTENT));
+        topic_menu_cb, GINT_TO_POINTER(HELP_CONTENT));
+#else
+    item_hb = welcome_button(GTK_STOCK_HELP,
+        "User's Guide",
+        "The User's Guide "
+        "(online version)",
+        topic_online_url(ONLINEPAGE_USERGUIDE),
+        topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_USERGUIDE));
+#endif
     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
 
     item_hb = welcome_button(WIRESHARK_STOCK_WIKI,
         "Security",
-               "Work with Wireshark as securely as possible",
+        "Work with Wireshark as securely as possible",
         topic_online_url(ONLINEPAGE_SECURITY),
-        GTK_SIGNAL_FUNC(topic_menu_cb), GINT_TO_POINTER(ONLINEPAGE_SECURITY));
+        topic_menu_cb, GINT_TO_POINTER(ONLINEPAGE_SECURITY));
     gtk_box_pack_start(GTK_BOX(topic_to_fill), item_hb, FALSE, FALSE, 5);
 
 #if 0
@@ -871,12 +1320,15 @@ welcome_new(void)
 
 
     /* the end */
-    gtk_widget_show_all(welcome_vb);
+    gtk_widget_show_all(welcome_eb);
 
     gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
-                                          welcome_vb);
+                                          welcome_eb);
     gtk_widget_show_all(welcome_scrollw);
 
+#ifdef USE_THREADS
+    recent_mtx = g_mutex_new();
+#endif
+
     return welcome_scrollw;
 }
-