Don't include "../image/eicon3d64.xpm", as we're not using it for now.
[obnox/wireshark/wip.git] / gtk / main.c
index c9a3f039bab45b95a2ca738b027c3a6747caef85..e99c98f57e92fc0fcc0bff573c2d3dde433696f1 100644 (file)
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- *
- *
- * To do:
- * - Graphs
- * - Playback window
- * - Multiple window support
- * - Add cut/copy/paste
- * - Create header parsing routines
- * - Make byte view selections more fancy?
  */
 
 #ifdef HAVE_CONFIG_H
 
 #include "main.h"
 #include "menu.h"
+#include "../main_window.h"
 #include "../menu.h"
 #include "file_dlg.h"
 #include <epan/column.h>
 #include "help_dlg.h"
 #include "decode_as_dlg.h"
 #include "webbrowser.h"
+#include "capture_dlg.h"
+#if 0
+#include "../image/eicon3d64.xpm"
+#endif
+#include "capture_ui_utils.h"
+
 
 
 /*
@@ -162,6 +160,7 @@ static GtkWidget   *status_pane;
 static GtkWidget   *menubar, *main_vbox, *main_tb, *pkt_scrollw, *stat_hbox, *filter_tb;
 static GtkWidget       *info_bar;
 static GtkWidget    *packets_bar = NULL;
+static GtkWidget    *welcome_pane;
 static guint    main_ctx, file_ctx, help_ctx;
 static guint        packets_ctx;
 static gchar        *packets_str = NULL;
@@ -185,7 +184,8 @@ capture_options *capture_opts = &global_capture_opts;
 
 
 static void create_main_window(gint, gint, gint, e_prefs*);
-static void file_quit_answered_cb(gpointer dialog _U_, gint btn, gpointer data _U_);
+static void show_main_window(gboolean);
+static void file_quit_answered_cb(gpointer dialog, gint btn, gpointer data);
 static void main_save_window_geometry(GtkWidget *widget);
 
 #define E_DFILTER_CM_KEY          "display_filter_combo"
@@ -1154,104 +1154,6 @@ get_positive_int(const char *string, const char *name)
   return number;
 }
 
-#ifdef HAVE_LIBPCAP
-/*
- * Given a string of the form "<autostop criterion>:<value>", as might appear
- * as an argument to a "-a" option, parse it and set the criterion in
- * question.  Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-set_autostop_criterion(const char *autostoparg)
-{
-  gchar *p, *colonp;
-
-  colonp = strchr(autostoparg, ':');
-  if (colonp == NULL)
-    return FALSE;
-
-  p = colonp;
-  *p++ = '\0';
-
-  /*
-   * Skip over any white space (there probably won't be any, but
-   * as we allow it in the preferences file, we might as well
-   * allow it here).
-   */
-  while (isspace((guchar)*p))
-    p++;
-  if (*p == '\0') {
-    /*
-     * Put the colon back, so if our caller uses, in an
-     * error message, the string they passed us, the message
-     * looks correct.
-     */
-    *colonp = ':';
-    return FALSE;
-  }
-  if (strcmp(autostoparg,"duration") == 0) {
-    capture_opts->has_autostop_duration = TRUE;
-    capture_opts->autostop_duration = get_positive_int(p,"autostop duration");
-  } else if (strcmp(autostoparg,"filesize") == 0) {
-    capture_opts->has_autostop_filesize = TRUE;
-    capture_opts->autostop_filesize = get_positive_int(p,"autostop filesize");
-  } else {
-    return FALSE;
-  }
-  *colonp = ':'; /* put the colon back */
-  return TRUE;
-}
-
-/*
- * Given a string of the form "<ring buffer file>:<duration>", as might appear
- * as an argument to a "-b" option, parse it and set the arguments in
- * question.  Return an indication of whether it succeeded or failed
- * in some fashion.
- */
-static gboolean
-get_ring_arguments(const char *arg)
-{
-  gchar *p = NULL, *colonp;
-
-  colonp = strchr(arg, ':');
-
-  if (colonp != NULL) {
-    p = colonp;
-    *p++ = '\0';
-  }
-
-  capture_opts->ring_num_files = 
-    get_natural_int(arg, "number of ring buffer files");
-
-  if (colonp == NULL)
-    return TRUE;
-
-  /*
-   * Skip over any white space (there probably won't be any, but
-   * as we allow it in the preferences file, we might as well
-   * allow it here).
-   */
-  while (isspace((guchar)*p))
-    p++;
-  if (*p == '\0') {
-    /*
-     * Put the colon back, so if our caller uses, in an
-     * error message, the string they passed us, the message
-     * looks correct.
-     */
-    *colonp = ':';
-    return FALSE;
-  }
-
-  capture_opts->has_file_duration = TRUE;
-  capture_opts->file_duration = get_positive_int(p,
-                                                     "ring buffer duration");
-
-  *colonp = ':';       /* put the colon back */
-  return TRUE;
-}
-#endif
-
 #if defined(_WIN32) || GTK_MAJOR_VERSION < 2 || ! defined USE_THREADS
 /* 
    Once every 3 seconds we get a callback here which we use to update
@@ -1333,6 +1235,284 @@ register_ethereal_tap(char *cmd, void (*func)(char *arg))
 
 }
 
+/* Set the file name in the status line, in the name for the main window,
+   and in the name for the main window's icon. */
+static void
+set_display_filename(capture_file *cf)
+{
+  const gchar *name_ptr;
+  size_t       msg_len;
+  static const gchar done_fmt_nodrops[] = " File: %s %s %02u:%02u:%02u";
+  static const gchar done_fmt_drops[] = " File: %s %s %02u:%02u:%02u Drops: %u";
+  gchar       *done_msg;
+  gchar       *win_name_fmt = "%s - Ethereal";
+  gchar       *win_name;
+  gchar       *size_str;
+
+  name_ptr = cf_get_display_name(cf);
+       
+  if (!cf->is_tempfile) {
+    /* Add this filename to the list of recent files in the "Recent Files" submenu */
+    add_menu_recent_capture_file(cf->filename);
+  }
+
+  if (cf->f_len/1024/1024 > 10) {
+    size_str = g_strdup_printf("%ld MB", cf->f_len/1024/1024);
+  } else if (cf->f_len/1024 > 10) {
+    size_str = g_strdup_printf("%ld KB", cf->f_len/1024);
+  } else {
+    size_str = g_strdup_printf("%ld bytes", cf->f_len);
+  }
+
+  if (cf->drops_known) {
+    done_msg = g_strdup_printf(done_fmt_drops, name_ptr, size_str, 
+        cf->esec/3600, cf->esec%3600/60, cf->esec%60, cf->drops);
+  } else {
+    done_msg = g_strdup_printf(done_fmt_nodrops, name_ptr, size_str,
+        cf->esec/3600, cf->esec%3600/60, cf->esec%60);
+  }
+  statusbar_push_file_msg(done_msg);
+  g_free(done_msg);
+
+  msg_len = strlen(name_ptr) + strlen(win_name_fmt) + 1;
+  win_name = g_malloc(msg_len);
+  snprintf(win_name, msg_len, win_name_fmt, name_ptr);
+  set_main_window_name(win_name);
+  g_free(win_name);
+}
+
+
+static void
+main_cf_cb_file_closed(capture_file *cf)
+{
+    /* Destroy all windows, which refer to the
+       capture file we're closing. */
+    destroy_cfile_wins();
+
+    /* Clear any file-related status bar messages.
+       XXX - should be "clear *ALL* file-related status bar messages;
+       will there ever be more than one on the stack? */
+    statusbar_pop_file_msg();
+
+    /* Restore the standard title bar message. */
+    set_main_window_name("The Ethereal Network Analyzer");
+
+    /* Disable all menu items that make sense only if you have a capture. */
+    set_menus_for_capture_file(FALSE);
+    set_menus_for_unsaved_capture_file(FALSE);
+    set_menus_for_captured_packets(FALSE);
+    set_menus_for_selected_packet(cf);
+    set_menus_for_capture_in_progress(FALSE);
+    set_menus_for_selected_tree_row(cf);
+
+    /* Set up main window for no capture file. */
+    main_set_for_capture_file(FALSE);
+}
+
+static void
+main_cf_cb_file_read_start(capture_file *cf)
+{
+  const gchar *name_ptr;
+  gchar       *load_msg;
+
+  name_ptr = get_basename(cf->filename);
+
+  load_msg = g_strdup_printf(" Loading: %s", name_ptr);
+  statusbar_push_file_msg(load_msg);
+  g_free(load_msg);
+}
+
+static void
+main_cf_cb_file_read_finished(capture_file *cf)
+{
+    statusbar_pop_file_msg();
+    set_display_filename(cf);
+
+    /* Enable menu items that make sense if you have a capture file you've
+     finished reading. */
+    set_menus_for_capture_file(TRUE);
+    set_menus_for_unsaved_capture_file(!cf->user_saved);
+
+    /* Enable menu items that make sense if you have some captured packets. */
+    set_menus_for_captured_packets(TRUE);
+
+    /* Set up main window for a capture file. */
+    main_set_for_capture_file(TRUE);
+}
+
+#ifdef HAVE_LIBPCAP
+static void
+main_cf_cb_live_capture_prepare(capture_options *capture_opts)
+{
+    gchar *title;
+
+
+    title = g_strdup_printf("%s: Capturing - Ethereal",
+                            get_interface_descriptive_name(capture_opts->iface));
+    set_main_window_name(title);
+    g_free(title);
+}
+
+static void
+main_cf_cb_live_capture_started(capture_options *capture_opts)
+{
+    gchar *capture_msg;
+
+    /* Disable menu items that make no sense if you're currently running
+       a capture. */
+    set_menus_for_capture_in_progress(TRUE);
+
+    /* Enable menu items that make sense if you have some captured
+       packets (yes, I know, we don't have any *yet*). */
+    set_menus_for_captured_packets(TRUE);
+
+    capture_msg = g_strdup_printf(" %s: <live capture in progress>", get_interface_descriptive_name(capture_opts->iface));
+
+    statusbar_push_file_msg(capture_msg);
+
+    g_free(capture_msg);
+
+    /* Set up main window for a capture file. */
+    main_set_for_capture_file(TRUE);
+}
+
+static void
+main_cf_cb_live_capture_finished(capture_file *cf)
+{
+    /* Pop the "<live capture in progress>" message off the status bar. */
+    statusbar_pop_file_msg();
+
+    set_display_filename(cf);
+
+    /* Enable menu items that make sense if you're not currently running
+     a capture. */
+    set_menus_for_capture_in_progress(FALSE);
+
+    /* Enable menu items that make sense if you have a capture file
+     you've finished reading. */
+    set_menus_for_capture_file(TRUE);
+    set_menus_for_unsaved_capture_file(!cf->user_saved);
+
+    /* Set up main window for a capture file. */
+    main_set_for_capture_file(TRUE);
+}
+#endif
+
+static void
+main_cf_cb_packet_selected(gpointer data)
+{
+    capture_file *cf = data;
+
+    /* Display the GUI protocol tree and hex dump.
+      XXX - why do we dump core if we call "proto_tree_draw()"
+      before calling "add_byte_views()"? */
+    add_main_byte_views(cf->edt);
+    main_proto_tree_draw(cf->edt->tree);
+
+    /* A packet is selected. */
+    set_menus_for_selected_packet(cf);
+}
+
+static void
+main_cf_cb_packet_unselected(capture_file *cf)
+{
+    /* Clear out the display of that packet. */
+    clear_tree_and_hex_views();
+
+    /* No packet is selected. */
+    set_menus_for_selected_packet(cf);
+}
+
+static void
+main_cf_cb_field_unselected(capture_file *cf)
+{
+    statusbar_pop_field_msg();
+    set_menus_for_selected_tree_row(cf);
+}
+
+static void
+main_cf_cb_file_safe_started(gchar * filename)
+{
+    const gchar  *name_ptr;
+    gchar        *save_msg;
+
+    name_ptr = get_basename(filename);
+
+    save_msg = g_strdup_printf(" Saving: %s...", name_ptr);
+
+    statusbar_push_file_msg(save_msg);
+    g_free(save_msg);
+}
+
+static void
+main_cf_cb_file_safe_finished(gpointer data _U_)
+{
+    /* Pop the "Saving:" message off the status bar. */
+    statusbar_pop_file_msg();
+}
+
+static void
+main_cf_cb_file_safe_failed(gpointer data _U_)
+{
+    /* Pop the "Saving:" message off the status bar. */
+    statusbar_pop_file_msg();
+}
+
+static void
+main_cf_cb_file_safe_reload_finished(gpointer data _U_)
+{
+    set_menus_for_unsaved_capture_file(FALSE);
+}
+
+void main_cf_callback(gint event, gpointer data, gpointer user_data _U_)
+{
+    switch(event) {
+    case(cf_cb_file_closed):
+        main_cf_cb_file_closed(data);
+        break;
+    case(cf_cb_file_read_start):
+        main_cf_cb_file_read_start(data);
+        break;
+    case(cf_cb_file_read_finished):
+        main_cf_cb_file_read_finished(data);
+        break;
+#ifdef HAVE_LIBPCAP
+    case(cf_cb_live_capture_prepare):
+        main_cf_cb_live_capture_prepare(data);
+        break;
+    case(cf_cb_live_capture_started):
+        main_cf_cb_live_capture_started(data);
+        break;
+    case(cf_cb_live_capture_finished):
+        main_cf_cb_live_capture_finished(data);
+        break;
+#endif
+    case(cf_cb_packet_selected):
+        main_cf_cb_packet_selected(data);
+        break;
+    case(cf_cb_packet_unselected):
+        main_cf_cb_packet_unselected(data);
+        break;
+    case(cf_cb_field_unselected):
+        main_cf_cb_field_unselected(data);
+        break;
+    case(cf_cb_file_safe_started):
+        main_cf_cb_file_safe_started(data);
+        break;
+    case(cf_cb_file_safe_finished):
+        main_cf_cb_file_safe_finished(data);
+        break;
+    case(cf_cb_file_safe_reload_finished):
+        main_cf_cb_file_safe_reload_finished(data);
+        break;
+    case(cf_cb_file_safe_failed):
+        main_cf_cb_file_safe_failed(data);
+        break;
+    default:
+        g_warning("main_cf_callback: event %u unknown", event);
+        g_assert_not_reached();
+    }
+}
 
 /* And now our feature presentation... [ fade to music ] */
 int
@@ -1364,7 +1544,6 @@ main(int argc, char *argv[])
   int                  err;
 #ifdef HAVE_LIBPCAP
   gboolean             start_capture = FALSE;
-  gchar               *save_file = NULL;
   GList               *if_list;
   if_info_t           *if_info;
   GList               *lt_list, *lt_entry;
@@ -1411,6 +1590,8 @@ main(int argc, char *argv[])
   /* Let GTK get its args */
   gtk_init (&argc, &argv);
 
+  cf_callback_add(main_cf_callback, NULL);
+
 #if GTK_MAJOR_VERSION < 2 && GTK_MINOR_VERSION < 3
   /* initialize our GTK eth_clist_type */
   init_eth_clist_type();
@@ -1437,16 +1618,23 @@ main(int argc, char *argv[])
 #endif
 
 #ifdef HAVE_LIBPCAP
+  /* Set the initial values in the capture_opts. This might be overwritten 
+     by preference settings and then again by the command line parameters. */
+  capture_opts_init(capture_opts, &cfile);
+
+  capture_opts->snaplen             = MIN_PACKET_SIZE;
+  capture_opts->has_ring_num_files  = TRUE;
+
   command_name = get_basename(ethereal_path);
   /* Set "capture_child" to indicate whether this is going to be a child
      process for a "-S" capture. */
   capture_opts->capture_child = (strcmp(command_name, CHILD_NAME) == 0);
-  /* We want a splash screen only if we're not a child process */
   if (capture_opts->capture_child) {
     strcat(optstring, OPTSTRING_CHILD);
-  } else
+  }
 #endif
-  {
+
+  /* We want a splash screen only if we're not a child process */
     /* We also want it only if we're not being run with "-G".
        XXX - we also don't want it if we're being run with
        "-h" or "-v", as those are options to run Ethereal and just
@@ -1458,9 +1646,12 @@ main(int argc, char *argv[])
        that means we'd have to queue up, for example, "-o" options,
        so that we apply them *after* reading the preferences, as
        they're supposed to override saved preferences. */
-    if (argc < 2 || strcmp(argv[1], "-G") != 0) {
-      splash_win = splash_new("Loading Ethereal ...");
-    }
+  if ((argc < 2 || strcmp(argv[1], "-G") != 0)
+#ifdef HAVE_LIBPCAP
+      && !capture_opts->capture_child
+#endif
+      ) {
+    splash_win = splash_new("Loading Ethereal ...");
   }
 
   splash_update(splash_win, "Registering dissectors ...");
@@ -1561,37 +1752,13 @@ main(int argc, char *argv[])
   }
 
 #ifdef _WIN32
+  /* if the user wants a console to be always there, well, we should open one for him */
   if (prefs->gui_console_open == console_open_always) {
     create_console();
   }
 #endif
 
-  capture_opts->cf = &cfile;
 #ifdef HAVE_LIBPCAP
-  capture_opts->has_snaplen = FALSE;
-  capture_opts->snaplen = MIN_PACKET_SIZE;
-  capture_opts->linktype = -1;
-#ifdef _WIN32
-  capture_opts->buffer_size = 1;
-#endif
-  capture_opts->save_file_fd = -1;
-  capture_opts->quit_after_cap  = FALSE;
-
-  capture_opts->has_autostop_packets = FALSE;
-  capture_opts->autostop_packets = 1;
-  capture_opts->has_autostop_duration = FALSE;
-  capture_opts->autostop_duration = 60 /* 1 min */;
-  capture_opts->has_autostop_filesize = FALSE;
-  capture_opts->autostop_filesize = 1024 * 1024 /* 1 MB */;
-  capture_opts->has_autostop_files = FALSE;
-  capture_opts->autostop_files = 1;
-
-  capture_opts->multi_files_on = FALSE;
-  capture_opts->has_ring_num_files = TRUE;
-  capture_opts->ring_num_files = 2;
-  capture_opts->has_file_duration = FALSE;
-  capture_opts->file_duration = 60 /* 1 min */;
-
   /* If this is a capture child process, it should pay no attention
      to the "prefs.capture_prom_mode" setting in the preferences file;
      it should do what the parent process tells it to do, and if
@@ -1601,16 +1768,12 @@ main(int argc, char *argv[])
      Otherwise, set promiscuous mode from the preferences setting. */
   /* the same applies to other preferences settings as well. */
   if (capture_opts->capture_child) {
-    capture_opts->promisc_mode   = TRUE;     /* maybe changed by command line below */
-    capture_opts->show_info      = TRUE;     /* maybe changed by command line below */
-    capture_opts->sync_mode      = TRUE;     /* always true in child process */
-    auto_scroll_live            = FALSE;    /* doesn't matter in child process */
-
+    auto_scroll_live             = FALSE;
   } else {
     capture_opts->promisc_mode   = prefs->capture_prom_mode;
     capture_opts->show_info      = prefs->capture_show_info;
     capture_opts->sync_mode      = prefs->capture_real_time;
-    auto_scroll_live            = prefs->capture_auto_scroll;
+    auto_scroll_live             = prefs->capture_auto_scroll;
   }
 
 #endif /* HAVE_LIBPCAP */
@@ -1697,86 +1860,54 @@ main(int argc, char *argv[])
   /* Now get our args */
   while ((opt = getopt(argc, argv, optstring)) != -1) {
     switch (opt) {
+      /*** capture option specific ***/
       case 'a':        /* autostop criteria */
+      case 'b':        /* Ringbuffer option */
+      case 'c':        /* Capture xxx packets */
+      case 'f':        /* capture filter */
+      case 'k':        /* Start capture immediately */
+      case 'H':        /* Hide capture info dialog box */
+      case 'i':        /* Use interface xxx */
+      case 'p':        /* Don't capture in promiscuous mode */
+      case 'Q':        /* Quit after capture (just capture to file) */
+      case 's':        /* Set the snapshot (capture) length */
+      case 'S':        /* "Sync" mode: used for following file ala tail -f */
+      case 'w':        /* Write to capture file xxx */
+      case 'y':        /* Set the pcap data link type */
+#ifdef _WIN32
+      /* Hidden option supporting Sync mode */
+      case 'Z':        /* Write to pipe FD XXX */
+#endif /* _WIN32 */
 #ifdef HAVE_LIBPCAP
-        if (set_autostop_criterion(optarg) == FALSE) {
-          fprintf(stderr, "ethereal: Invalid or unknown -a flag \"%s\"\n", optarg);
-          exit(1);
-        }
+        capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
 #endif
         break;
-      case 'b':        /* Ringbuffer option */
 #ifdef HAVE_LIBPCAP
-        capture_opts->multi_files_on = TRUE;
-        capture_opts->has_ring_num_files = TRUE;
-       if (get_ring_arguments(optarg) == FALSE) {
-          fprintf(stderr, "ethereal: Invalid or unknown -b arg \"%s\"\n", optarg);
-          exit(1);
-       }
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
+      /* This is a hidden option supporting Sync mode, so we don't set
+       * the error flags for the user in the non-libpcap case.
+       */
+      case 'W':        /* Write to capture file FD xxx */
+        capture_opts_add_opt(capture_opts, "ethereal", opt, optarg, &start_capture);
+       break;
 #endif
-        break;
+
+      /*** all non capture option specific ***/
       case 'B':        /* Byte view pane height */
         bv_size = get_positive_int(optarg, "byte view pane height");
         break;
-      case 'c':        /* Capture xxx packets */
-#ifdef HAVE_LIBPCAP
-        capture_opts->has_autostop_packets = TRUE;
-        capture_opts->autostop_packets = get_positive_int(optarg, "packet count");
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
-      case 'f':
-#ifdef HAVE_LIBPCAP
-       if (cfile.cfilter)
-               g_free(cfile.cfilter);
-       cfile.cfilter = g_strdup(optarg);
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-       break;
       case 'h':        /* Print help and exit */
        print_usage(TRUE);
        exit(0);
         break;
-      case 'i':        /* Use interface xxx */
-#ifdef HAVE_LIBPCAP
-        cfile.iface = g_strdup(optarg);
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
-      case 'k':        /* Start capture immediately */
-#ifdef HAVE_LIBPCAP
-        start_capture = TRUE;
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'l':        /* Automatic scrolling in live capture mode */
 #ifdef HAVE_LIBPCAP
         auto_scroll_live = TRUE;
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
-#endif
-        break;
-      case 'H':        /* Hide capture info dialog box */
-#ifdef HAVE_LIBPCAP
-        capture_opts->show_info = FALSE;
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
 #endif
         break;
       case 'L':        /* Print list of link-layer types and exit */
@@ -1821,26 +1952,9 @@ main(int argc, char *argv[])
           break;
         }
         break;
-      case 'p':        /* Don't capture in promiscuous mode */
-#ifdef HAVE_LIBPCAP
-       capture_opts->promisc_mode = FALSE;
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-       break;
       case 'P':        /* Packet list pane height */
         pl_size = get_positive_int(optarg, "packet list pane height");
         break;
-      case 'Q':        /* Quit after capture (just capture to file) */
-#ifdef HAVE_LIBPCAP
-        capture_opts->quit_after_cap  = TRUE;
-        start_capture   = TRUE;  /*** -Q implies -k !! ***/
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 'r':        /* Read capture file xxx */
        /* We may set "last_open_dir" to "cf_name", and if we change
           "last_open_dir" later, we free the old value, so we have to
@@ -1850,23 +1964,6 @@ main(int argc, char *argv[])
       case 'R':        /* Read file filter */
         rfilter = optarg;
         break;
-      case 's':        /* Set the snapshot (capture) length */
-#ifdef HAVE_LIBPCAP
-        capture_opts->has_snaplen = TRUE;
-        capture_opts->snaplen = get_positive_int(optarg, "snapshot length");
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
-      case 'S':        /* "Sync" mode: used for following file ala tail -f */
-#ifdef HAVE_LIBPCAP
-        capture_opts->sync_mode = TRUE;
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-        break;
       case 't':        /* Time stamp type */
         if (strcmp(optarg, "r") == 0)
           set_timestamp_setting(TS_RELATIVE);
@@ -1894,40 +1991,6 @@ main(int argc, char *argv[])
 #endif
         exit(0);
         break;
-      case 'w':        /* Write to capture file xxx */
-#ifdef HAVE_LIBPCAP
-        save_file = g_strdup(optarg);
-#else
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif
-       break;
-      case 'y':        /* Set the pcap data link type */
-#ifdef HAVE_LIBPCAP
-#ifdef HAVE_PCAP_DATALINK_NAME_TO_VAL
-        capture_opts->linktype = pcap_datalink_name_to_val(optarg);
-        if (capture_opts->linktype == -1) {
-          fprintf(stderr, "ethereal: The specified data link type \"%s\" isn't valid\n",
-                  optarg);
-          exit(1);
-        }
-#else /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
-        /* XXX - just treat it as a number */
-        capture_opts->linktype = get_natural_int(optarg, "data link type");
-#endif /* HAVE_PCAP_DATALINK_NAME_TO_VAL */
-#else /* HAVE_LIBPCAP */
-        capture_option_specified = TRUE;
-        arg_error = TRUE;
-#endif /* HAVE_LIBPCAP */
-        break;
-#ifdef HAVE_LIBPCAP
-      /* This is a hidden option supporting Sync mode, so we don't set
-       * the error flags for the user in the non-libpcap case.
-       */
-      case 'W':        /* Write to capture file FD xxx */
-        capture_opts->save_file_fd = atoi(optarg);
-       break;
-#endif
       case 'z':
         for(tli=tap_list;tli;tli=tli->next){
           if(!strncmp(tli->cmd,optarg,strlen(tli->cmd))){
@@ -1944,21 +2007,6 @@ main(int argc, char *argv[])
           exit(1);
         }
         break;
-
-#ifdef _WIN32
-#ifdef HAVE_LIBPCAP
-      /* Hidden option supporting Sync mode */
-      case 'Z':        /* Write to pipe FD XXX */
-        /* associate stdout with pipe */
-        i = atoi(optarg);
-        if (dup2(i, 1) < 0) {
-          fprintf(stderr, "Unable to dup pipe handle\n");
-          exit(1);
-        }
-        break;
-#endif /* HAVE_LIBPCAP */
-#endif /* _WIN32 */
-
       default:
       case '?':        /* Bad flag - print usage message */
         arg_error = TRUE;
@@ -1991,6 +2039,8 @@ main(int argc, char *argv[])
     argv++;
   }
 
+
+
   if (argc != 0) {
     /*
      * Extra command line arguments were specified; complain.
@@ -1999,11 +2049,12 @@ main(int argc, char *argv[])
     arg_error = TRUE;
   }
 
+  if (arg_error) {
 #ifndef HAVE_LIBPCAP
-  if (capture_option_specified)
-    fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
+    if (capture_option_specified) {
+      fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
+    }
 #endif
-  if (arg_error) {
     print_usage(FALSE);
     exit(1);
   }
@@ -2046,7 +2097,7 @@ main(int argc, char *argv[])
            sync_mode takes precedence;
         c) it makes no sense to enable the ring buffer if the maximum
            file size is set to "infinite". */
-      if (save_file == NULL) {
+      if (capture_opts->save_file == NULL) {
        fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
        capture_opts->multi_files_on = FALSE;
       }
@@ -2063,11 +2114,11 @@ main(int argc, char *argv[])
 
   if (start_capture || list_link_layer_types) {
     /* Did the user specify an interface to use? */
-    if (cfile.iface == NULL) {
+    if (capture_opts->iface == NULL) {
       /* No - is a default specified in the preferences file? */
       if (prefs->capture_device != NULL) {
           /* Yes - use it. */
-          cfile.iface = g_strdup(prefs->capture_device);
+          capture_opts->iface = g_strdup(prefs->capture_device);
       } else {
         /* No - pick the first one from the list of interfaces. */
         if_list = get_interface_list(&err, err_str);
@@ -2087,7 +2138,7 @@ main(int argc, char *argv[])
           exit(2);
         }
         if_info = if_list->data;       /* first interface */
-        cfile.iface = g_strdup(if_info->name);
+        capture_opts->iface = g_strdup(if_info->name);
         free_interface_list(if_list);
       }
     }
@@ -2104,7 +2155,7 @@ main(int argc, char *argv[])
 
   if (list_link_layer_types) {
     /* Get the list of link-layer types for the capture device. */
-    lt_list = get_pcap_linktype_list(cfile.iface, err_str);
+    lt_list = get_pcap_linktype_list(capture_opts->iface, err_str);
     if (lt_list == NULL) {
       if (err_str[0] != '\0') {
        fprintf(stderr, "ethereal: The list of data link types for the capture device could not be obtained (%s).\n"
@@ -2129,7 +2180,21 @@ main(int argc, char *argv[])
     exit(0);
   }
 
+  if (capture_opts->has_snaplen) {
+    if (capture_opts->snaplen < 1)
+      capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
+    else if (capture_opts->snaplen < MIN_PACKET_SIZE)
+      capture_opts->snaplen = MIN_PACKET_SIZE;
+  }
+
+  /* Check the value range of the ringbuffer_num_files parameter */
+  if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
+    capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
+#if RINGBUFFER_MIN_NUM_FILES > 0
+  else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
+    capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
 #endif
+#endif /* HAVE_LIBPCAP */
 
   /* Notify all registered modules that have had any of their preferences
      changed either from one of the preferences file or from the command
@@ -2172,23 +2237,6 @@ main(int argc, char *argv[])
       }
   }
 
-#ifdef HAVE_LIBPCAP
-  if (capture_opts->has_snaplen) {
-    if (capture_opts->snaplen < 1)
-      capture_opts->snaplen = WTAP_MAX_PACKET_SIZE;
-    else if (capture_opts->snaplen < MIN_PACKET_SIZE)
-      capture_opts->snaplen = MIN_PACKET_SIZE;
-  }
-
-  /* Check the value range of the ringbuffer_num_files parameter */
-  if (capture_opts->ring_num_files > RINGBUFFER_MAX_NUM_FILES)
-    capture_opts->ring_num_files = RINGBUFFER_MAX_NUM_FILES;
-#if RINGBUFFER_MIN_NUM_FILES > 0
-  else if (capture_opts->num_files < RINGBUFFER_MIN_NUM_FILES)
-    capture_opts->ring_num_files = RINGBUFFER_MIN_NUM_FILES;
-#endif
-#endif
-
   /* read in rc file from global and personal configuration paths. */
   /* XXX - is this a good idea? */
   gtk_rc_parse(RC_FILE);
@@ -2204,134 +2252,151 @@ main(int argc, char *argv[])
   /* close the splash screen, as we are going to open the main window now */
   splash_destroy(splash_win);
 
+
 #ifdef HAVE_LIBPCAP
   /* Is this a "child" ethereal, which is only supposed to pop up a
      capture box to let us stop the capture, and run a capture
      to a file that our parent will read? */
-  if (!capture_opts->capture_child) {
-#endif
-    /* No.  Pop up the main window, and read in a capture file if
-       we were told to. */
-    create_main_window(pl_size, tv_size, bv_size, prefs);
-
-    /* Read the recent file, as we have the gui now ready for it. */
-    read_recent(&rf_path, &rf_open_errno);
+  if (capture_opts->capture_child) {
+    /* This is the child process for a sync mode or fork mode capture,
+       so just do the low-level work of a capture - don't create
+       a temporary file and fork off *another* child process (so don't
+       call "do_capture()"). */
 
-    /* rearrange all the widgets as we now have the recent settings for this */
-    main_widgets_rearrange();
+    /* Pop up any queued-up alert boxes. */
+    display_queued_messages();
 
-    /* Fill in column titles.  This must be done after the top level window
-       is displayed.
+    /* XXX - hand these stats to the parent process */
+    capture_start(capture_opts, &stats_known, &stats);
 
-       XXX - is that still true, with fixed-width columns? */
-    packet_list_set_column_titles();
+    /* The capture is done; there's nothing more for us to do. */
+    gtk_exit(0);
+  }
+#endif
 
-    menu_recent_read_finished();
+  /***********************************************************************/
+  /* Everything is prepared now, preferences and command line was read in,
+       we are NOT a child window for a synced capture. */
+
+  /* Pop up the main window, and read in a capture file if
+     we were told to. */
+  create_main_window(pl_size, tv_size, bv_size, prefs);
+
+  /* Read the recent file, as we have the gui now ready for it. */
+  read_recent(&rf_path, &rf_open_errno);
+
+  /* rearrange all the widgets as we now have the recent settings for this */
+  main_widgets_rearrange();
+
+  /* Fill in column titles.  This must be done after the top level window
+     is displayed.
+
+     XXX - is that still true, with fixed-width columns? */
+  packet_list_set_column_titles();
+
+  menu_recent_read_finished();
+
+  switch (user_font_apply()) {
+  case FA_SUCCESS:
+      break;
+  case FA_FONT_NOT_RESIZEABLE:
+      /* "user_font_apply()" popped up an alert box. */
+      /* turn off zooming - font can't be resized */
+  case FA_FONT_NOT_AVAILABLE:
+      /* XXX - did we successfully load the un-zoomed version earlier?
+      If so, this *probably* means the font is available, but not at
+      this particular zoom level, but perhaps some other failure
+      occurred; I'm not sure you can determine which is the case,
+      however. */
+      /* turn off zooming - zoom level is unavailable */
+  default:
+      /* in any other case than FA_SUCCESS, turn off zooming */
+      recent.gui_zoom_level = 0;       
+      /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
+  }
 
-    switch (user_font_apply()) {
-    case FA_SUCCESS:
-        break;
-    case FA_FONT_NOT_RESIZEABLE:
-        /* "user_font_apply()" popped up an alert box. */
-        /* turn off zooming - font can't be resized */
-    case FA_FONT_NOT_AVAILABLE:
-        /* XXX - did we successfully load the un-zoomed version earlier?
-        If so, this *probably* means the font is available, but not at
-        this particular zoom level, but perhaps some other failure
-        occurred; I'm not sure you can determine which is the case,
-        however. */
-        /* turn off zooming - zoom level is unavailable */
-    default:
-        /* in any other case than FA_SUCCESS, turn off zooming */
-        recent.gui_zoom_level = 0;     
-        /* XXX: would it be a good idea to disable zooming (insensitive GUI)? */
+  dnd_init(top_level);
+
+  colors_init();
+  colfilter_init();
+  decode_as_init();
+
+  /* the window can be sized only, if it's not already shown, so do it now! */
+  main_load_window_geometry(top_level);
+
+  /* If we were given the name of a capture file, read it in now;
+     we defer it until now, so that, if we can't open it, and pop
+     up an alert box, the alert box is more likely to come up on
+     top of the main window - but before the preference-file-error
+     alert box, so, if we get one of those, it's more likely to come
+     up on top of us. */
+  if (cf_name) {
+    show_main_window(TRUE);
+    if (rfilter != NULL) {
+      if (!dfilter_compile(rfilter, &rfcode)) {
+        bad_dfilter_alert_box(rfilter);
+        rfilter_parse_failed = TRUE;
+      }
     }
-
-    dnd_init(top_level);
-
-    colors_init();
-    colfilter_init();
-    decode_as_init();
-
-    /* the window can be sized only, if it's not already shown, so do it now! */
-    main_load_window_geometry(top_level);
-
-    /*** we have finished all init things, show the main window ***/
-    gtk_widget_show(top_level);
-
-    /* the window can be maximized only, if it's visible, so do it after show! */
-    main_load_window_geometry(top_level);
-
-    /* process all pending GUI events before continue */
-    while (gtk_events_pending()) gtk_main_iteration();
-
-    /* Pop up any queued-up alert boxes. */
-    display_queued_messages();
-
-    /* If we were given the name of a capture file, read it in now;
-       we defer it until now, so that, if we can't open it, and pop
-       up an alert box, the alert box is more likely to come up on
-       top of the main window - but before the preference-file-error
-       alert box, so, if we get one of those, it's more likely to come
-       up on top of us. */
-    if (cf_name) {
-      if (rfilter != NULL) {
-        if (!dfilter_compile(rfilter, &rfcode)) {
-          bad_dfilter_alert_box(rfilter);
-          rfilter_parse_failed = TRUE;
+    if (!rfilter_parse_failed) {
+      if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
+        /* "cf_open()" succeeded, so it closed the previous
+           capture file, and thus destroyed any previous read filter
+           attached to "cf". */
+
+        cfile.rfcode = rfcode;
+        /* Open tap windows; we do so after creating the main window,
+           to avoid GTK warnings, and after successfully opening the
+           capture file, so we know we have something to tap. */
+        if (tap_opt && tli) {
+          (*tli->func)(tap_opt);
+          g_free(tap_opt);
         }
-      }
-      if (!rfilter_parse_failed) {
-        if (cf_open(&cfile, cf_name, FALSE, &err) == CF_OK) {
-          /* "cf_open()" succeeded, so it closed the previous
-            capture file, and thus destroyed any previous read filter
-            attached to "cf". */
-          cfile.rfcode = rfcode;
-
-          /* Open tap windows; we do so after creating the main window,
-             to avoid GTK warnings, and after successfully opening the
-             capture file, so we know we have something to tap. */
-          if (tap_opt && tli) {
-            (*tli->func)(tap_opt);
-            g_free(tap_opt);
-          }
 
-          /* Read the capture file. */
-          switch (cf_read(&cfile)) {
+        /* Read the capture file. */
+        switch (cf_read(&cfile)) {
 
-          case CF_READ_OK:
-          case CF_READ_ERROR:
-            /* Just because we got an error, that doesn't mean we were unable
-               to read any of the file; we handle what we could get from the
-               file. */
-            break;
+        case CF_READ_OK:
+        case CF_READ_ERROR:
+          /* Just because we got an error, that doesn't mean we were unable
+             to read any of the file; we handle what we could get from the
+             file. */
+          break;
 
-          case CF_READ_ABORTED:
-            /* Exit now. */
-            gtk_exit(0);
-            break;
-          }
-          /* Save the name of the containing directory specified in the
-            path name, if any; we can write over cf_name, which is a
-             good thing, given that "get_dirname()" does write over its
-             argument. */
-          s = get_dirname(cf_name);
-          /* we might already set this from the recent file, don't overwrite this */
-          if(get_last_open_dir() == NULL) 
-            set_last_open_dir(s);
-          g_free(cf_name);
-          cf_name = NULL;
-        } else {
-          if (rfcode != NULL)
-            dfilter_free(rfcode);
-          cfile.rfcode = NULL;
+        case CF_READ_ABORTED:
+          /* Exit now. */
+          gtk_exit(0);
+          break;
         }
+        /* Save the name of the containing directory specified in the
+           path name, if any; we can write over cf_name, which is a
+           good thing, given that "get_dirname()" does write over its
+           argument. */
+        s = get_dirname(cf_name);
+        /* we might already set this from the recent file, don't overwrite this */
+        if(get_last_open_dir() == NULL) 
+          set_last_open_dir(s);
+        g_free(cf_name);
+        cf_name = NULL;
+      } else {
+        if (rfcode != NULL)
+          dfilter_free(rfcode);
+        cfile.rfcode = NULL;
       }
     }
+  } else {
 #ifdef HAVE_LIBPCAP
     if (start_capture) {
+      if (capture_opts->save_file != NULL) {
+        /* Save the directory name for future file dialogs. */
+        /* (get_dirname overwrites filename) */
+        s = get_dirname(g_strdup(capture_opts->save_file));  
+        set_last_open_dir(s);
+        g_free(s);
+      }
       /* "-k" was specified; start a capture. */
-      if (do_capture(capture_opts, save_file)) {
+      show_main_window(TRUE);
+      if (do_capture(capture_opts)) {
         /* The capture started.  Open tap windows; we do so after creating
            the main window, to avoid GTK warnings, and after starting the
            capture, so we know we have something to tap. */
@@ -2340,41 +2405,24 @@ main(int argc, char *argv[])
           g_free(tap_opt);
         }
       }
-      if (save_file != NULL) {
-        /* Save the directory name for future file dialogs. */
-        s = get_dirname(save_file);  /* Overwrites save_file */
-        set_last_open_dir(s);
-        g_free(save_file);
-        save_file = NULL;
-      }
     }
     else {
+      show_main_window(FALSE);
       set_menus_for_capture_in_progress(FALSE);
     }
-  } else {
-    /* This is the child process for a sync mode or fork mode capture,
-       so just do the low-level work of a capture - don't create
-       a temporary file and fork off *another* child process (so don't
-       call "do_capture()"). */
 
-    /* Pop up any queued-up alert boxes. */
-    display_queued_messages();
-
-    /* XXX - hand these stats to the parent process */
-    capture_start(capture_opts, &stats_known, &stats);
-
-    /* The capture is done; there's nothing more for us to do. */
-    gtk_exit(0);
-  }
-  if (!start_capture && (cfile.cfilter == NULL || strlen(cfile.cfilter) == 0)) {
-    if (cfile.cfilter) {
-      g_free(cfile.cfilter);
+    /* if the user didn't supplied a capture filter, use the one to filter out remote connections like SSH */
+    if (!start_capture && (capture_opts->cfilter == NULL || strlen(capture_opts->cfilter) == 0)) {
+      if (capture_opts->cfilter) {
+        g_free(capture_opts->cfilter);
+      }
+      capture_opts->cfilter = g_strdup(get_conn_cfilter());
     }
-    cfile.cfilter = g_strdup(get_conn_cfilter());
-  }
 #else /* HAVE_LIBPCAP */
-  set_menus_for_capture_in_progress(FALSE);
+    show_main_window(FALSE);
+    set_menus_for_capture_in_progress(FALSE);
 #endif /* HAVE_LIBPCAP */
+  }
 
   gtk_main();
 
@@ -2566,6 +2614,7 @@ void main_widgets_rearrange(void) {
     gtk_widget_ref(main_pane_v2);
     gtk_widget_ref(main_pane_h1);
     gtk_widget_ref(main_pane_h2);
+    gtk_widget_ref(welcome_pane);
 
     /* empty all containers participating */
     gtk_container_foreach(GTK_CONTAINER(main_vbox),     foreach_remove_a_child, main_vbox);
@@ -2647,6 +2696,9 @@ void main_widgets_rearrange(void) {
 
     gtk_container_add(GTK_CONTAINER(main_vbox), main_first_pane);
 
+    /* welcome pane */
+    gtk_box_pack_start(GTK_BOX(main_vbox), welcome_pane, TRUE, TRUE, 0);
+
     /* statusbar hbox */
     gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0);
 
@@ -2677,6 +2729,135 @@ is_widget_visible(GtkWidget *widget, gpointer data)
     }
 }
 
+
+#if 0
+/* XXX - There seems to be some disagreement about if and how this feature should be implemented.
+   As I currently don't have the time to continue this, it's temporarily disabled. - ULFL */
+GtkWidget *
+welcome_item(gchar *stock_item, gchar * label, gchar * message, GtkSignalFunc callback, void *callback_data)
+{
+    GtkWidget *w, *item_hb;
+#if GTK_MAJOR_VERSION >= 2
+    gchar *formatted_message;
+#endif
+
+
+    item_hb = gtk_hbox_new(FALSE, 1);
+
+    w = BUTTON_NEW_FROM_STOCK(stock_item);
+    WIDGET_SET_SIZE(w, 60, 60);
+#if GTK_MAJOR_VERSION >= 2
+    gtk_button_set_label(GTK_BUTTON(w), label);
+#endif
+    gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 0);
+    SIGNAL_CONNECT(w, "clicked", callback, callback_data);
+
+    w = gtk_label_new(message);
+       gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
+#if GTK_MAJOR_VERSION >= 2
+    formatted_message = g_strdup_printf("<span weight=\"bold\" size=\"x-large\">%s</span>", message);
+    gtk_label_set_markup(GTK_LABEL(w), formatted_message);
+    g_free(formatted_message);
+#endif
+
+    gtk_box_pack_start(GTK_BOX(item_hb), w, FALSE, FALSE, 10);
+
+    return item_hb;
+}
+
+
+/* XXX - the layout has to be improved */
+GtkWidget *
+welcome_new(void)
+{
+    GtkWidget *welcome_scrollw, *welcome_hb, *welcome_vb, *item_hb;
+    GtkWidget *w, *icon;
+    gchar * message;
+
+
+    welcome_scrollw = scrolled_window_new(NULL, NULL);
+
+    welcome_hb = gtk_hbox_new(FALSE, 1);
+       /*gtk_container_border_width(GTK_CONTAINER(welcome_hb), 20);*/
+
+    welcome_vb = gtk_vbox_new(FALSE, 1);
+
+    item_hb = gtk_hbox_new(FALSE, 1);
+
+    icon = xpm_to_widget_from_parent(top_level, eicon3d64_xpm);
+    gtk_box_pack_start(GTK_BOX(item_hb), icon, FALSE, FALSE, 5);
+
+#if GTK_MAJOR_VERSION < 2
+    message = "Welcome to Ethereal!";
+#else
+    message = "<span weight=\"bold\" size=\"25000\">" "Welcome to Ethereal!" "</span>";
+#endif
+    w = gtk_label_new(message);
+#if GTK_MAJOR_VERSION >= 2
+    gtk_label_set_markup(GTK_LABEL(w), message);
+#endif
+    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.5);
+    gtk_box_pack_start(GTK_BOX(item_hb), w, TRUE, TRUE, 5);
+
+    gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
+
+    w = gtk_label_new("What would you like to do?");
+    gtk_box_pack_start(GTK_BOX(welcome_vb), w, FALSE, FALSE, 10);
+    gtk_misc_set_alignment (GTK_MISC(w), 0.0, 0.0);
+
+#ifdef HAVE_LIBPCAP
+    item_hb = welcome_item(ETHEREAL_STOCK_CAPTURE_START, 
+        "Capture",
+        "Capture live data from your network", 
+        GTK_SIGNAL_FUNC(capture_prep_cb), NULL);
+    gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
+#endif
+
+    item_hb = welcome_item(GTK_STOCK_OPEN, 
+        "Open",
+        "Open a previously captured file",
+        GTK_SIGNAL_FUNC(file_open_cmd_cb), NULL);
+    gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
+
+#if (GLIB_MAJOR_VERSION >= 2)
+    item_hb = welcome_item(GTK_STOCK_HOME, 
+        "Home",
+        "Visit the Ethereal homepage",
+        GTK_SIGNAL_FUNC(topic_cb), GINT_TO_POINTER(ONLINEPAGE_HOME));
+    gtk_box_pack_start(GTK_BOX(welcome_vb), item_hb, TRUE, FALSE, 5);
+#endif
+
+    /* the end */
+    w = gtk_label_new("");
+    gtk_box_pack_start(GTK_BOX(welcome_vb), w, TRUE, TRUE, 0);
+
+    w = gtk_label_new("");
+    gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
+
+    gtk_box_pack_start(GTK_BOX(welcome_hb), welcome_vb, TRUE, TRUE, 0);
+
+    w = gtk_label_new("");
+    gtk_box_pack_start(GTK_BOX(welcome_hb), w, TRUE, TRUE, 0);
+
+    gtk_widget_show_all(welcome_hb);
+
+    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(welcome_scrollw),
+                                          welcome_hb);
+    gtk_widget_show_all(welcome_scrollw);
+
+    return welcome_scrollw;
+}
+#endif /* 0 */
+
+GtkWidget *
+welcome_new(void)
+{
+    /* this is just a dummy to fill up window space, simply showing nothing */
+    return scrolled_window_new(NULL, NULL);
+}
+
+
+
 /*
  * XXX - this doesn't appear to work with the paned widgets in
  * GTK+ 1.2[.x]; if you hide one of the panes, the splitter remains
@@ -2741,6 +2922,12 @@ main_widgets_show_or_hide(void)
         gtk_widget_hide(byte_nb_ptr);
     }
 
+    if (have_capture_file) {
+        gtk_widget_show(main_first_pane);
+    } else {
+        gtk_widget_hide(main_first_pane);
+    }
+
     /*
      * Is anything in "main_second_pane" visible?
      * If so, show it, otherwise hide it.
@@ -2753,6 +2940,14 @@ main_widgets_show_or_hide(void)
     } else {
         gtk_widget_hide(main_second_pane);
     }
+
+    if (!have_capture_file) {
+        if(welcome_pane) {
+            gtk_widget_show(welcome_pane);
+        }
+    } else {
+        gtk_widget_hide(welcome_pane);
+    }
 }
 
 
@@ -3000,5 +3195,26 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
     /* Pane for the statusbar */
     status_pane = gtk_hpaned_new();
     gtk_widget_show(status_pane);
+
+    /* Pane for the welcome screen */
+    welcome_pane = welcome_new();
+    gtk_widget_show(welcome_pane);
 }
 
+static void
+show_main_window(gboolean doing_work)
+{
+  main_set_for_capture_file(doing_work);
+
+  /*** we have finished all init things, show the main window ***/
+  gtk_widget_show(top_level);
+
+  /* the window can be maximized only, if it's visible, so do it after show! */
+  main_load_window_geometry(top_level);
+
+  /* process all pending GUI events before continue */
+  while (gtk_events_pending()) gtk_main_iteration();
+
+  /* Pop up any queued-up alert boxes. */
+  display_queued_messages();
+}