In GTK+ 2.x, "gtk_entry_get_text()" returns a "const gchar *"; assign
[obnox/wireshark/wip.git] / gtk / main.c
index d9844742c7950116055345b2542e8b8e6c6380d6..8a80985697ec3d5733f086597245bc1f0b9bf5b2 100644 (file)
@@ -1,6 +1,6 @@
 /* main.c
  *
- * $Id: main.c,v 1.318 2003/09/24 02:36:34 guy Exp $
+ * $Id: main.c,v 1.336 2003/12/03 09:28:24 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 #include "register.h"
 #include "ringbuffer.h"
 #include "ui_util.h"
+#include "toolbar.h"
 #include "image/clist_ascend.xpm"
 #include "image/clist_descend.xpm"
 #include "../tap.h"
 #include "../util.h"
 #include "compat_macros.h"
+#include "find_dlg.h"
 
 #ifdef WIN32
 #include "capture-wpcap.h"
@@ -144,7 +146,9 @@ static guint    main_ctx, file_ctx, help_ctx;
 static GString *comp_info_str, *runtime_info_str;
 gchar       *ethereal_path = NULL;
 gchar       *last_open_dir = NULL;
-gint   root_x = G_MAXINT, root_y = G_MAXINT, top_width, top_height;
+static gboolean updated_last_open_dir = FALSE;
+static gint root_x = G_MAXINT, root_y = G_MAXINT, top_width, top_height;
+static gboolean updated_geometry = FALSE;
 
 ts_type timestamp_type = RELATIVE;
 
@@ -161,6 +165,8 @@ static void console_log_handler(const char *log_domain,
     GLogLevelFlags log_level, const char *message, gpointer user_data);
 #endif
 
+static gboolean list_link_layer_types;
+
 static void create_main_window(gint, gint, gint, e_prefs*);
 
 #define E_DFILTER_CM_KEY          "display_filter_combo"
@@ -228,6 +234,11 @@ about_ethereal( GtkWidget *w _U_, gpointer data _U_ ) {
   gtk_widget_grab_default(ok_btn);
   gtk_widget_show(ok_btn);
 
+  /* Catch the "key_press_event" signal in the window, so that we can catch
+     the ESC key being pressed and act as if the "Cancel" button had
+     been selected. */
+  dlg_set_cancel(win, ok_btn);
+
   gtk_widget_show(win);
 }
 
@@ -264,7 +275,7 @@ goto_framenum_cb(GtkWidget *w _U_, gpointer data _U_)
        hfinfo = cfile.finfo_selected->hfinfo;
        g_assert(hfinfo);
        if (hfinfo->type == FT_FRAMENUM) {
-           framenum = fvalue_get_integer(cfile.finfo_selected->value);
+           framenum = fvalue_get_integer(&cfile.finfo_selected->value);
            if (framenum != 0)
                goto_frame(&cfile, framenum);
        }
@@ -781,27 +792,43 @@ packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
     if (w == NULL || event == NULL)
         return FALSE;
 
-    if (event->type == GDK_BUTTON_PRESS &&
+    if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
+        event_button->window == GTK_CLIST(w)->clist_window &&
         gtk_clist_get_selection_info(GTK_CLIST(w), event_button->x,
                                      event_button->y, &row, &column)) {
-        if (event_button->button == 2)
-        {
-            frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(w), row);
-            set_frame_mark(!fdata->flags.marked, fdata, row);
-            return TRUE;
-        }
+        frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(w),
+                                                                 row);
+        set_frame_mark(!fdata->flags.marked, fdata, row);
+        return TRUE;
     }
     return FALSE;
 }
 #endif
 
-void reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
-  if (cfile.current_frame) {
-    /* XXX hum, should better have a "cfile->current_row" here ... */
-    set_frame_reftime(!cfile.current_frame->flags.ref_time,
-                  cfile.current_frame,
-                  gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
-                                               cfile.current_frame));
+/* 0: toggle ref time status for the selected frame 
+ * 1: find next ref time frame
+ * 2: find previous reftime frame
+ */
+void 
+reftime_frame_cb(GtkWidget *w _U_, gpointer data _U_, guint action)
+{
+
+  switch(action){
+  case 0: /* toggle ref frame */
+    if (cfile.current_frame) {
+      /* XXX hum, should better have a "cfile->current_row" here ... */
+      set_frame_reftime(!cfile.current_frame->flags.ref_time,
+                    cfile.current_frame,
+                    gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
+                                                 cfile.current_frame));
+    }
+    break;
+  case 1: /* find next ref frame */
+    find_previous_next_frame_with_filter("frame.ref_time", FALSE);
+    break;
+  case 2: /* find previous ref frame */
+    find_previous_next_frame_with_filter("frame.ref_time", TRUE);
+    break;
   }
 }
 
@@ -1216,12 +1243,35 @@ do_quit(void)
 
 static gboolean
 main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer data _U_)
+{
+       /* "do_quit()" indicates whether the main window should be deleted. */
+       return do_quit();
+}
+
+static gboolean
+main_window_configure_event_cb(GtkWidget *widget, GdkEvent *event _U_, gpointer data _U_)
 {
        gint desk_x, desk_y;
 
-       /* Try to grab our geometry */
-       gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
-       if (gdk_window_get_deskrelative_origin(top_level->window,
+       /* Try to grab our geometry.
+
+          GTK+ provides two routines to get a window's position relative
+          to the X root window.  If I understand the documentation correctly,
+          gdk_window_get_deskrelative_origin applies mainly to Enlightenment
+          and gdk_window_get_root_origin applies for all other WMs.
+
+          The code below tries both routines, and picks the one that returns
+          the upper-left-most coordinates.
+
+          More info at:
+
+       http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
+       http://www.gtk.org/faq/#AEN606
+
+          XXX - should we get this from the event itself? */
+
+       gdk_window_get_root_origin(widget->window, &root_x, &root_y);
+       if (gdk_window_get_deskrelative_origin(widget->window,
                                &desk_x, &desk_y)) {
                if (desk_x <= root_x && desk_y <= root_y) {
                        root_x = desk_x;
@@ -1230,10 +1280,11 @@ main_window_delete_event_cb(GtkWidget *widget _U_, GdkEvent *event _U_, gpointer
        }
 
        /* XXX - Is this the "approved" method? */
-       gdk_window_get_size(top_level->window, &top_width, &top_height);
+       gdk_window_get_size(widget->window, &top_width, &top_height);
 
-       /* "do_quit()" indicates whether the main window should be deleted. */
-       return do_quit();
+       updated_geometry = TRUE;
+
+       return FALSE;
 }
 
 void
@@ -1250,7 +1301,7 @@ print_usage(gboolean print_ver) {
          comp_info_str->str, runtime_info_str->str);
   }
 #ifdef HAVE_LIBPCAP
-  fprintf(stderr, "\n%s [ -vh ] [ -klnpQS ] [ -a <capture autostop condition> ] ...\n",
+  fprintf(stderr, "\n%s [ -vh ] [ -klLnpQS ] [ -a <capture autostop condition> ] ...\n",
          PACKAGE);
   fprintf(stderr, "\t[ -b <number of ringbuffer files>[:<duration>] ]\n");
   fprintf(stderr, "\t[ -B <byte view height> ] [ -c <count> ] [ -f <capture filter> ]\n");
@@ -1258,13 +1309,15 @@ print_usage(gboolean print_ver) {
   fprintf(stderr, "\t[ -o <preference setting> ] ... [ -P <packet list height> ]\n");
   fprintf(stderr, "\t[ -r <infile> ] [ -R <read filter> ] [ -s <snaplen> ] \n");
   fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
-  fprintf(stderr, "\t[ -w <savefile> ] [ <infile> ]\n");
+  fprintf(stderr, "\t[ -w <savefile> ] [ -y <link type> ] [ -z <statistics string> ]\n");
+  fprintf(stderr, "\t[ <infile> ]\n");
 #else
   fprintf(stderr, "\n%s [ -vh ] [ -n ] [ -B <byte view height> ] [ -m <medium font> ]\n",
          PACKAGE);
   fprintf(stderr, "\t[ -N <resolving> ] [ -o <preference setting> ...\n");
   fprintf(stderr, "\t[ -P <packet list height> ] [ -r <infile> ] [ -R <read filter> ]\n");
-  fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ] [ <infile> ]\n");
+  fprintf(stderr, "\t[ -t <time stamp format> ] [ -T <tree view height> ]\n");
+  fprintf(stderr, "\t[ -z <statistics string> ] [ <infile> ]\n");
 #endif
 }
 
@@ -1528,6 +1581,8 @@ main(int argc, char *argv[])
   gchar               *save_file = NULL;
   GList               *if_list;
   if_info_t           *if_info;
+  GList               *lt_list, *lt_entry;
+  data_link_info_t    *data_link_info;
   gchar                err_str[PCAP_ERRBUF_SIZE];
   gboolean             stats_known;
   struct pcap_stat     stats;
@@ -1543,12 +1598,11 @@ main(int argc, char *argv[])
 #if GTK_MAJOR_VERSION < 2
   char                *bold_font_name;
 #endif
-  gint                 desk_x, desk_y;
   gboolean             prefs_write_needed = FALSE;
   ethereal_tap_list   *tli = NULL;
   gchar               *tap_opt = NULL;
 
-#define OPTSTRING_INIT "a:b:B:c:f:hi:klm:nN:o:pP:Qr:R:Ss:t:T:w:vz:"
+#define OPTSTRING_INIT "a:b:B:c:f:hi:klLm:nN:o:pP:Qr:R:Ss:t:T:w:vy:z:"
 
 #ifdef HAVE_LIBPCAP
 #ifdef WIN32
@@ -1692,6 +1746,7 @@ main(int argc, char *argv[])
   capture_opts.ringbuffer_num_files = RINGBUFFER_MIN_NUM_FILES;
   capture_opts.has_ring_duration = FALSE;
   capture_opts.ringbuffer_duration = 1;
+  capture_opts.linktype = -1;
 
   /* If this is a capture child process, it should pay no attention
      to the "prefs.capture_prom_mode" setting in the preferences file;
@@ -1827,6 +1882,15 @@ main(int argc, char *argv[])
 #else
         capture_option_specified = TRUE;
         arg_error = TRUE;
+#endif
+        break;
+      case 'L':        /* Print list of link-layer types and exit */
+#ifdef HAVE_LIBPCAP
+        list_link_layer_types = TRUE;
+        break;
+#else
+        capture_option_specified = TRUE;
+        arg_error = TRUE;
 #endif
         break;
       case 'm':        /* Fixed-width font for the display */
@@ -1945,6 +2009,24 @@ main(int argc, char *argv[])
         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\" is not 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.
@@ -2023,59 +2105,71 @@ main(int argc, char *argv[])
     fprintf(stderr, "Invalid argument: %s\n", argv[0]);
     arg_error = TRUE;
   }
+
+#ifndef HAVE_LIBPCAP
+  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);
   }
 
 #ifdef HAVE_LIBPCAP
-  if (capture_opts.ringbuffer_on) {
-    /* Ring buffer works only under certain conditions:
-       a) ring buffer does not work with temporary files;
-       b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
-          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) {
-      fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
-      capture_opts.ringbuffer_on = FALSE;
-    }
-    if (capture_opts.sync_mode) {
-      fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
-      capture_opts.ringbuffer_on = FALSE;
-    }
-    if (!capture_opts.has_autostop_filesize) {
-      fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
-      capture_opts.ringbuffer_on = FALSE;
-    }
-  }
-#endif
-
-  /* Notify all registered modules that have had any of their preferences
-     changed either from one of the preferences file or from the command
-     line that their preferences have changed. */
-  prefs_apply_all();
-
-  /* disabled protocols as per configuration file */
-  if (dp_path == NULL) {
-    set_disabled_protos_list();
+  if (start_capture && list_link_layer_types) {
+    /* Specifying *both* is bogus. */
+    fprintf(stderr, "ethereal: You cannot specify both -L and a live capture.\n");
+    exit(1);
   }
 
-#ifndef HAVE_LIBPCAP
-  if (capture_option_specified)
-    fprintf(stderr, "This version of Ethereal was not built with support for capturing packets.\n");
-#endif
-#ifdef HAVE_LIBPCAP
-  if (start_capture) {
+  if (list_link_layer_types) {
+    /* We're supposed to list the link-layer types for an interface;
+       did the user also specify a capture file to be read? */
+    if (cf_name) {
+      /* Yes - that's bogus. */
+      fprintf(stderr, "ethereal: You cannot specify -L and a capture file to be read.\n");
+      exit(1);
+    }
+    /* No - did they specify a ring buffer option? */
+    if (capture_opts.ringbuffer_on) {
+      fprintf(stderr, "ethereal: Ring buffer requested, but a capture is not being done.\n");
+      exit(1);
+    }
+  } else {
     /* We're supposed to do a live capture; did the user also specify
        a capture file to be read? */
-    if (cf_name) {
+    if (start_capture && cf_name) {
       /* Yes - that's bogus. */
       fprintf(stderr, "ethereal: You cannot specify both a live capture and a capture file to be read.\n");
-      exit(2);
+      exit(1);
     }
-       
-    /* No - did the user specify an interface to use? */
+
+    /* No - was the ring buffer option specified and, if so, does it make
+       sense? */
+    if (capture_opts.ringbuffer_on) {
+      /* Ring buffer works only under certain conditions:
+        a) ring buffer does not work with temporary files;
+        b) sync_mode and capture_opts.ringbuffer_on are mutually exclusive -
+           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) {
+       fprintf(stderr, "ethereal: Ring buffer requested, but capture isn't being saved to a permanent file.\n");
+       capture_opts.ringbuffer_on = FALSE;
+      }
+      if (capture_opts.sync_mode) {
+       fprintf(stderr, "ethereal: Ring buffer requested, but an \"Update list of packets in real time\" capture is being done.\n");
+       capture_opts.ringbuffer_on = FALSE;
+      }
+      if (!capture_opts.has_autostop_filesize) {
+       fprintf(stderr, "ethereal: Ring buffer requested, but no maximum capture file size was specified.\n");
+       capture_opts.ringbuffer_on = FALSE;
+      }
+    }
+  }
+
+  if (start_capture || list_link_layer_types) {
+    /* Did the user specify an interface to use? */
     if (cfile.iface == NULL) {
       /* No - is a default specified in the preferences file? */
       if (prefs->capture_device != NULL) {
@@ -2104,16 +2198,55 @@ main(int argc, char *argv[])
       }
     }
   }
+
   if (capture_child) {
     if (cfile.save_file_fd == -1) {
       /* XXX - send this to the standard output as something our parent
-         should put in an error message box? */
+        should put in an error message box? */
       fprintf(stderr, "%s: \"-W\" flag not specified\n", CHILD_NAME);
       exit(1);
     }
   }
+
+  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);
+    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"
+         "Please check to make sure you have sufficient permissions, and that\n"
+         "you have the proper interface or pipe specified.\n", err_str);
+      } else
+       fprintf(stderr, "ethereal: The capture device has no data link types.\n");
+      exit(2);
+    }
+    fprintf(stderr, "Data link types (use option -y to set):\n");
+    for (lt_entry = lt_list; lt_entry != NULL;
+         lt_entry = g_list_next(lt_entry)) {
+      data_link_info = lt_entry->data;
+      fprintf(stderr, "  %s", data_link_info->name);
+      if (data_link_info->description != NULL)
+       fprintf(stderr, " (%s)", data_link_info->description);
+      else
+       fprintf(stderr, " (not supported)");
+      putchar('\n');
+    }
+    free_pcap_linktype_list(lt_list);
+    exit(0);
+  }
+
 #endif
 
+  /* Notify all registered modules that have had any of their preferences
+     changed either from one of the preferences file or from the command
+     line that their preferences have changed. */
+  prefs_apply_all();
+
+  /* disabled protocols as per configuration file */
+  if (dp_path == NULL) {
+    set_disabled_protos_list();
+  }
+
   /* Build the column format array */
   col_setup(&cfile.cinfo, prefs->num_cols);
   for (i = 0; i < cfile.cinfo.num_cols; i++) {
@@ -2132,6 +2265,19 @@ main(int argc, char *argv[])
     cfile.cinfo.col_expr_val[i] = (gchar *) g_malloc(sizeof(gchar) * COL_MAX_LEN);
   }
 
+  for (i = 0; i < cfile.cinfo.num_cols; i++) {
+      int j;
+
+      for (j = 0; j < NUM_COL_FMTS; j++) {
+         if (!cfile.cinfo.fmt_matx[i][j])
+             continue;
+         
+         if (cfile.cinfo.col_first[j] == -1)
+             cfile.cinfo.col_first[j] = i;
+         cfile.cinfo.col_last[j] = i;
+      }
+  }
+
 #ifdef HAVE_LIBPCAP
   if (capture_opts.has_snaplen) {
     if (capture_opts.snaplen < 1)
@@ -2238,13 +2384,9 @@ main(int argc, char *argv[])
      to a file that our parent will read? */
   if (!capture_child) {
 #endif
-    /* No.  Pop up the main window, register menus for taps (which we
-       must do after creating the main window, so that we can add
-       menu items to the main menu), and read in a capture file if
+    /* 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);
-    register_all_tap_menus();
-    set_menus_for_capture_file(FALSE);
 
     colors_init();
     colfilter_init();
@@ -2425,70 +2567,93 @@ main(int argc, char *argv[])
   set_menus_for_capture_in_progress(FALSE);
 #endif
 
+  if (!start_capture && (cfile.cfilter == NULL || strlen(cfile.cfilter) == 0)) {
+    if (cfile.cfilter) {
+      g_free(cfile.cfilter);
+    }
+    cfile.cfilter = g_strdup(get_conn_cfilter());
+  }
   gtk_main();
 
-  /* Try to save our geometry.  GTK+ provides two routines to get a
-     window's position relative to the X root window.  If I understand the
-     documentation correctly, gdk_window_get_deskrelative_origin applies
-     mainly to Enlightenment and gdk_window_get_root_origin applies for
-     all other WMs.
-
-     The code below tries both routines, and picks the one that returns
-     the upper-left-most coordinates.
-
-     More info at:
-
-       http://mail.gnome.org/archives/gtk-devel-list/2001-March/msg00289.html
-       http://www.gtk.org/faq/#AEN600 */
-
-  /* Re-read our saved preferences. */
-  /* XXX - Move all of this into a separate function? */
-  prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
-                    &pf_open_errno, &pf_read_errno, &pf_path);
-
-  if (pf_path == NULL) {
-    if (prefs->gui_geometry_save_position) {
-      if (top_level->window != NULL) {
-       gdk_window_get_root_origin(top_level->window, &root_x, &root_y);
-       if (gdk_window_get_deskrelative_origin(top_level->window,
-                                              &desk_x, &desk_y)) {
-         if (desk_x <= root_x && desk_y <= root_y) {
-           root_x = desk_x;
-           root_y = desk_y;
+  /* If the last opened directory, or our geometry, has changed, save
+     whatever we're supposed to save. */
+  if (updated_last_open_dir || updated_geometry) {
+    /* Re-read our saved preferences. */
+    prefs = read_prefs(&gpf_open_errno, &gpf_read_errno, &gpf_path,
+                      &pf_open_errno, &pf_read_errno, &pf_path);
+    if (pf_path == NULL) {
+      /* We succeeded in reading the preferences. */
+
+      if (updated_last_open_dir) {
+       /* The pathname of the last directory in which we've opened
+          a file has changed.  If it changed from what's in the
+          preferences file, and we're supposed to save it, update
+          the preference value and note that we will have to write
+          the preferences out. */
+       if (prefs->gui_fileopen_style == FO_STYLE_LAST_OPENED) {
+         /* Yes, we're supposed to save it.
+            Has a file been opened since Ethereal was started? */
+         if (last_open_dir != NULL) {
+           /* Yes.  Is the most recently navigated-to directory
+              different from the saved directory? */
+           if (prefs->gui_fileopen_remembered_dir == NULL ||
+               strcmp(prefs->gui_fileopen_remembered_dir, last_open_dir) != 0) {
+             /* Yes. */
+             prefs->gui_fileopen_remembered_dir = last_open_dir;
+             prefs_write_needed = TRUE;
+           }
          }
        }
       }
-      if (prefs->gui_geometry_main_x != root_x) {
-       prefs->gui_geometry_main_x = root_x;
-       prefs_write_needed = TRUE;
-      }
-      if (prefs->gui_geometry_main_y != root_y) {
-       prefs->gui_geometry_main_y = root_y;
-       prefs_write_needed = TRUE;
-      }
-    }
 
-    if (prefs->gui_geometry_save_size) {
-      if (top_level->window != NULL) {
-       /* XXX - Is this the "approved" method? */
-       gdk_window_get_size(top_level->window, &top_width, &top_height);
-      }
-      if (prefs->gui_geometry_main_width != top_width) {
-       prefs->gui_geometry_main_width = top_width;
-       prefs_write_needed = TRUE;
+      if (updated_geometry) {
+        /* We got a geometry update, in the form of a configure_notify
+           event, so the geometry has changed.  If it changed from
+           what's in the preferences file, and we're supposed to save
+          the current values of the changed geometry item (position or
+          size), update the preference value and note that we will have
+          to write the preferences out.
+
+          XXX - should GUI stuff such as this be in a separate file? */
+       if (prefs->gui_geometry_save_position) {
+         if (prefs->gui_geometry_main_x != root_x) {
+           prefs->gui_geometry_main_x = root_x;
+           prefs_write_needed = TRUE;
+         }
+         if (prefs->gui_geometry_main_y != root_y) {
+           prefs->gui_geometry_main_y = root_y;
+           prefs_write_needed = TRUE;
+         }
+       }
+
+       if (prefs->gui_geometry_save_size) {
+         if (prefs->gui_geometry_main_width != top_width) {
+           prefs->gui_geometry_main_width = top_width;
+           prefs_write_needed = TRUE;
+         }
+         if (prefs->gui_geometry_main_height != top_height) {
+           prefs->gui_geometry_main_height = top_height;
+           prefs_write_needed = TRUE;
+         }
+       }
       }
-      if (prefs->gui_geometry_main_height != top_height) {
-       prefs->gui_geometry_main_height = top_height;
-       prefs_write_needed = TRUE;
+    
+      /* Save the preferences if we need to do so.
+
+         XXX - this doesn't save the preferences if you don't have a
+         preferences file.  Forcibly writing a preferences file would
+         save the current settings even if you haven't changed them,
+         meaning that if the defaults change it won't affect you.
+         Perhaps we need to keep track of what the *user* has changed,
+         and only write out *those* preferences. */
+      if (prefs_write_needed) {
+       write_prefs(&pf_path);
       }
+    } else {
+      /* We failed to read the preferences - silently ignore the
+         error. */
+      g_free(pf_path);
     }
-
-    if (prefs_write_needed) {
-      write_prefs(&pf_path);
-    }
-  } else {
-    /* Ignore errors silently */
-    g_free(pf_path);
   }
 
   epan_cleanup();
@@ -2715,8 +2880,10 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
         WIDGET_SET_SIZE(top_level, DEF_WIDTH, -1);
     }
     gtk_window_set_policy(GTK_WINDOW(top_level), TRUE, TRUE, FALSE);
+    SIGNAL_CONNECT(top_level, "configure_event", main_window_configure_event_cb,
+                   NULL);
 
-    /* Container for menu bar, paned windows and progress/info box */
+    /* Container for menu bar, toolbar(s), paned windows and progress/info box */
     main_vbox = gtk_vbox_new(FALSE, 1);
     gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
     gtk_container_add(GTK_CONTAINER(top_level), main_vbox);
@@ -2728,6 +2895,9 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
     gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
     gtk_widget_show(menubar);
 
+    /* Main Toolbar */
+    create_toolbar(main_vbox);
+
     /* Panes for the packet list, tree, and byte view */
     u_pane = gtk_vpaned_new();
     gtk_paned_gutter_size(GTK_PANED(u_pane), (GTK_PANED(u_pane))->handle_size);
@@ -2850,7 +3020,6 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
      * of any widget that ends up calling a callback which needs
      * that text entry pointer */
     set_menu_object_data("/File/Open...", E_DFILTER_TE_KEY, filter_te);
-    set_menu_object_data("/File/Reload", E_DFILTER_TE_KEY, filter_te);
     set_menu_object_data("/Edit/Filters...", E_FILT_TE_PTR_KEY, filter_te);
     set_menu_object_data("/Tools/Follow TCP Stream", E_DFILTER_TE_KEY,
                          filter_te);
@@ -2878,6 +3047,7 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs)
                          filter_te);
     set_menu_object_data("/Display/Prepare/Or Not Selected", E_DFILTER_TE_KEY,
                          filter_te);
+    set_toolbar_object_data(E_DFILTER_TE_KEY, filter_te);
     OBJECT_SET_DATA(popup_menu_object, E_DFILTER_TE_KEY, filter_te);
     OBJECT_SET_DATA(popup_menu_object, E_MPACKET_LIST_KEY, packet_list);
 
@@ -2930,22 +3100,30 @@ void
 set_last_open_dir(char *dirname)
 {
        int len;
-
-       if (last_open_dir) {
-               g_free(last_open_dir);
-       }
+       gchar *new_last_open_dir;
 
        if (dirname) {
                len = strlen(dirname);
                if (dirname[len-1] == G_DIR_SEPARATOR) {
-                       last_open_dir = g_strconcat(dirname, NULL);
+                       new_last_open_dir = g_strconcat(dirname, NULL);
                }
                else {
-                       last_open_dir = g_strconcat(dirname, G_DIR_SEPARATOR_S,
-                               NULL);
+                       new_last_open_dir = g_strconcat(dirname,
+                               G_DIR_SEPARATOR_S, NULL);
                }
+
+               if (last_open_dir == NULL ||
+                   strcmp(last_open_dir, new_last_open_dir) != 0)
+                       updated_last_open_dir = TRUE;
        }
        else {
-               last_open_dir = NULL;
+               new_last_open_dir = NULL;
+               if (last_open_dir != NULL)
+                       updated_last_open_dir = TRUE;
+       }
+
+       if (last_open_dir) {
+               g_free(last_open_dir);
        }
+       last_open_dir = new_last_open_dir;
 }