diff options
-rw-r--r-- | file.c | 11 | ||||
-rw-r--r-- | gtk/main.c | 187 | ||||
-rw-r--r-- | gtk/main.h | 8 | ||||
-rw-r--r-- | gtk/menu.c | 137 | ||||
-rw-r--r-- | gtk/menu.h | 5 | ||||
-rw-r--r-- | menu.h | 7 |
6 files changed, 349 insertions, 6 deletions
@@ -1,7 +1,7 @@ /* file.c * File I/O routines * - * $Id: file.c,v 1.329 2003/12/09 22:41:06 ulfl Exp $ + * $Id: file.c,v 1.330 2003/12/13 18:01:29 ulfl Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -297,6 +297,12 @@ set_display_filename(capture_file *cf) gchar *win_name; 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->drops_known) { msg_len = strlen(name_ptr) + strlen(done_fmt_drops) + 64; done_msg = g_malloc(msg_len); @@ -640,6 +646,9 @@ cf_get_display_name(capture_file *cf) /* Get the last component of the file name, and use that. */ if (cf->filename){ displayname = get_basename(cf->filename); + + /* Add this filename to the list of recent files in the "Recent Files" submenu */ + add_menu_recent_capture_file(cf->filename); } else { displayname="<no file>"; } diff --git a/gtk/main.c b/gtk/main.c index b9aec0214c..1b00978696 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -1,6 +1,6 @@ /* main.c * - * $Id: main.c,v 1.340 2003/12/13 16:30:10 ulfl Exp $ + * $Id: main.c,v 1.341 2003/12/13 18:01:30 ulfl Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -111,6 +111,7 @@ #include "colors.h" #include <epan/strutil.h> #include "register.h" +#include <prefs-int.h> #include "ringbuffer.h" #include "ui_util.h" #include "toolbar.h" @@ -606,6 +607,177 @@ prepare_selected_cb_or_plist_not(GtkWidget *w _U_, gpointer data) get_text_from_packet_list(data)); } + +#define RECENT_FILE_NAME "recent" + + +/* Write out "recent" to the user's recent file, and return 0. + If we got an error, stuff a pointer to the path of the recent file + into "*pf_path_return", and return the errno. */ +int +write_recent(char **rf_path_return) +{ + char *rf_path; + FILE *rf; + + /* To do: + * - Split output lines longer than MAX_VAL_LEN + * - Create a function for the preference directory check/creation + * so that duplication can be avoided with filter.c + */ + + rf_path = get_persconffile_path(RECENT_FILE_NAME, TRUE); + if ((rf = fopen(rf_path, "w")) == NULL) { + *rf_path_return = rf_path; + return errno; + } + + fputs("# Recent settings file for Ethereal " VERSION ".\n" + "#\n" + "# This file is regenerated each time Ethereal is quit.\n" + "# So be careful, if you want to make manual changes here.\n" + "\n" + "######## Recent capture files (latest first) ########\n" + "\n", rf); + + menu_recent_file_write_all(rf); + + fputs("\n" + "######## Recent display filters (latest last) ########\n" + "\n", rf); + + dfilter_combo_write_all(rf); + + fclose(rf); + + /* XXX - catch I/O errors (e.g. "ran out of disk space") and return + an error indication, or maybe write to a new preferences file and + rename that file on top of the old one only if there are not I/O + errors. */ + return 0; +} + + +/* set one user's recent file key/value pair */ +static int +set_recent_pair(gchar *key, gchar *value) +{ + + + if (strcmp(key, RECENT_KEY_CAPTURE_FILE) == 0) { + add_menu_recent_capture_file(value); + } else if (strcmp(key, RECENT_KEY_DISPLAY_FILTER) == 0) { + dfilter_combo_add_recent(value); + } + + return PREFS_SET_OK; +} + + +/* opens the user's recent file and read it out */ +void +read_recent(char **rf_path_return, int *rf_errno_return) +{ + char *rf_path; + FILE *rf; + + + /* Construct the pathname of the user's recent file. */ + rf_path = get_persconffile_path(RECENT_FILE_NAME, FALSE); + + /* Read the user's recent file, if it exists. */ + *rf_path_return = NULL; + if ((rf = fopen(rf_path, "r")) != NULL) { + /* We succeeded in opening it; read it. */ + read_prefs_file(rf_path, rf, set_recent_pair); + /* set dfilter combobox to have one empty line at the current position */ + dfilter_combo_add_recent(""); + fclose(rf); + g_free(rf_path); + rf_path = NULL; + } else { + /* We failed to open it. If we failed for some reason other than + "it doesn't exist", return the errno and the pathname, so our + caller can report the error. */ + if (errno != ENOENT) { + *rf_errno_return = errno; + *rf_path_return = rf_path; + } + } +} + + + +static guint dfilter_combo_max_recent = 10; + +/* add a display filter to the combo box */ +/* Note: a new filter string will replace an old identical one */ +static gboolean +dfilter_combo_add(GtkWidget *filter_cm, char *s) { + GList *li; + GList *filter_list = gtk_object_get_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY); + + + /* GtkCombos don't let us get at their list contents easily, so we maintain + our own filter list, and feed it to gtk_combo_set_popdown_strings when + a new filter is added. */ + li = g_list_first(filter_list); + while (li) { + /* If the filter is already in the list, remove the old one and + * append the new one at the latest position (at g_list_append() below) */ + if (li->data && strcmp(s, li->data) == 0) { + filter_list = g_list_remove(filter_list, li->data); + break; + } + li = li->next; + } + + filter_list = g_list_append(filter_list, s); + gtk_object_set_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY, filter_list); + gtk_combo_set_popdown_strings(GTK_COMBO(filter_cm), filter_list); + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(filter_cm)->entry), g_list_last(filter_list)->data); + + return TRUE; +} + + +/* write all non empty display filters (until maximum count) + * of the combo box GList to the user's recent file */ +void +dfilter_combo_write_all(FILE *rf) { + GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY); + GList *filter_list = gtk_object_get_data(GTK_OBJECT(filter_cm), E_DFILTER_FL_KEY); + GList *li; + gint max_count = 0; + + + /* write all non empty display filter strings to the recent file (until max count) */ + li = g_list_first(filter_list); + while ( li && (max_count++ <= dfilter_combo_max_recent) ) { + if (strlen(li->data)) { + fprintf (rf, RECENT_KEY_DISPLAY_FILTER ": %s\n", li->data); + } + li = li->next; + } +} + + +/* add a display filter coming from the user's recent file to the dfilter combo box */ +gboolean +dfilter_combo_add_recent(gchar *s) { + GtkWidget *filter_cm = OBJECT_GET_DATA(top_level, E_DFILTER_CM_KEY); + char *dup; + + dup = g_strdup(s); + if (!dfilter_combo_add(filter_cm, dup)) { + g_free(dup); + return FALSE; + } + + return TRUE; +} + + /* Run the current display filter on the current packet set, and redisplay. */ static void @@ -1181,6 +1353,13 @@ statusbar_pop_field_msg(void) static gboolean do_quit(void) { + gchar *rec_path; + + + /* write user's recent file to disk + * It is no problem to write this file, even if we do not quit */ + write_recent(&rec_path); + /* XXX - should we check whether the capture file is an unsaved temporary file for a live capture and, if so, pop up a "do you want to exit without saving the capture @@ -1575,6 +1754,8 @@ main(int argc, char *argv[]) WSADATA wsaData; #endif /* WIN32 */ + char *rf_path; + int rf_open_errno; char *gpf_path, *pf_path; char *cf_path, *df_path, *dp_path; int gpf_open_errno, gpf_read_errno; @@ -2394,6 +2575,9 @@ main(int argc, char *argv[]) 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); + colors_init(); colfilter_init(); @@ -3000,6 +3184,7 @@ create_main_window (gint pl_size, gint tv_size, gint bv_size, e_prefs *prefs) main_display_filter_widget=filter_te; OBJECT_SET_DATA(filter_bt, E_FILT_TE_PTR_KEY, filter_te); OBJECT_SET_DATA(filter_te, E_DFILTER_CM_KEY, filter_cm); + OBJECT_SET_DATA(top_level, E_DFILTER_CM_KEY, filter_cm); gtk_box_pack_start(GTK_BOX(stat_hbox), filter_cm, TRUE, TRUE, 3); SIGNAL_CONNECT(filter_te, "activate", filter_activate_cb, filter_te); gtk_widget_show(filter_cm); diff --git a/gtk/main.h b/gtk/main.h index 5d20f1099a..8a96ecfe21 100644 --- a/gtk/main.h +++ b/gtk/main.h @@ -1,7 +1,7 @@ /* main.h * Global defines, etc. * - * $Id: main.h,v 1.33 2003/12/09 22:41:07 ulfl Exp $ + * $Id: main.h,v 1.34 2003/12/13 18:01:30 ulfl Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -100,6 +100,12 @@ void mark_all_frames_cb(GtkWidget *w, gpointer); void unmark_all_frames_cb(GtkWidget *w, gpointer); void update_marked_frames(void); +#define RECENT_KEY_CAPTURE_FILE "recent.capture_file" +#define RECENT_KEY_DISPLAY_FILTER "recent.display_filter" + +gboolean dfilter_combo_add_recent(gchar *s); +void dfilter_combo_write_all(FILE *rf); + char *boldify(const char *); #if GTK_MAJOR_VERSION < 2 void set_fonts(GdkFont *regular, GdkFont *bold); diff --git a/gtk/menu.c b/gtk/menu.c index 2e03715487..64c02f1ea8 100644 --- a/gtk/menu.c +++ b/gtk/menu.c @@ -1,7 +1,7 @@ /* menu.c * Menu routines * - * $Id: menu.c,v 1.123 2003/12/09 22:41:07 ulfl Exp $ + * $Id: menu.c,v 1.124 2003/12/13 18:01:30 ulfl Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -29,6 +29,7 @@ #include <gtk/gtk.h> #include <string.h> +#include <stdio.h> #include "main.h" #include "menu.h" @@ -106,6 +107,7 @@ static GtkItemFactoryEntry menu_items[] = ITEM_FACTORY_ENTRY("/_File", NULL, NULL, 0, "<Branch>", NULL), ITEM_FACTORY_STOCK_ENTRY("/File/_Open...", "<control>O", file_open_cmd_cb, 0, GTK_STOCK_OPEN), + ITEM_FACTORY_ENTRY("/File/Open _Recent", NULL, NULL, 0, "<Branch>", NULL), ITEM_FACTORY_STOCK_ENTRY("/File/_Close", "<control>W", file_close_cmd_cb, 0, GTK_STOCK_CLOSE), ITEM_FACTORY_ENTRY("/File/<separator>", NULL, NULL, 0, "<Separator>", NULL), @@ -659,6 +661,139 @@ set_menu_object_data (gchar *path, gchar *key, gpointer data) { } } + +/* Recently used capture files submenu: + * Submenu containing the recently used capture files. + * The capture filenames are always kept with the absolute path, to be independant + * of the current path. + * They are only stored inside the labels of the submenu (no separate list). */ + +/* the maximum number of entries in the recent capture files list */ +static guint recent_files_count_max = 10; + +#define MENU_RECENT_FILES_PATH "/File/Open Recent" + +/* callback, if the user pushed a recent file submenu item */ +void +menu_open_recent_file_cmd_cb(GtkWidget *w, gpointer data _U_) +{ + int err; + GtkWidget *menu_item_child; + gchar *cf_name; + + + /* get capture filename from the menu item label */ + menu_item_child = (GTK_BIN(w))->child; + gtk_label_get(GTK_LABEL(menu_item_child), &cf_name); + + /* open and read the capture file (this will close an existing file) */ + if ((err = cf_open(cf_name, FALSE, &cfile)) == 0) { + cf_read(&cfile, &err); + } +} + + +/* add the capture filename (with an absolute path) to the "Recent Files" menu */ +void +add_menu_recent_capture_file_absolute(gchar *cf_name) { + GtkWidget *submenu_recent_files; + GList *menu_item_list; + GList *li; + gchar *widget_cf_name; + GtkWidget *menu_item; + guint cnt; + + + /* get the submenu container item */ + submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH); + + /* convert container to a GList */ + menu_item_list = gtk_container_children(GTK_CONTAINER(submenu_recent_files)); + + /* iterate through list items of menu_item_list, + * removing a maybe duplicate entry and every item above count_max */ + li = g_list_first(menu_item_list); + for (cnt = 1; li; li = li->next, cnt++) { + /* get capture filename from the menu item label */ + menu_item = (GtkWidget *) li->data; + gtk_label_get(GTK_LABEL(GTK_BIN(menu_item)->child), &widget_cf_name); + + /* if this element string is already in the list, or + * this element is above maximum count (too old), remove it */ + if (strncmp(widget_cf_name, cf_name, 1000) == 0 || + cnt >= recent_files_count_max) { + /* XXX: is this all we need to do, to destroy the menu item and its label? */ + gtk_container_remove(GTK_CONTAINER(submenu_recent_files), li->data); + gtk_widget_destroy(li->data); + cnt--; + } + } + + g_list_free(menu_item_list); + + /* add new item at latest position */ + menu_item = gtk_menu_item_new_with_label(cf_name); + gtk_menu_prepend (GTK_MENU(submenu_recent_files), menu_item); + + gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate", + menu_open_recent_file_cmd_cb, (GtkObject *) menu_item); + gtk_widget_show (menu_item); +} + + +/* add the capture filename to the "Recent Files" menu */ +/* (will change nothing, if this filename is already in the menu) */ +void +add_menu_recent_capture_file(gchar *cf_name) { + gchar *curr; + gchar *absolute; + + + /* if this filename is an absolute path, we can use it directly */ + if (g_path_is_absolute(cf_name)) { + add_menu_recent_capture_file_absolute(cf_name); + return; + } + + /* this filename is not an absolute path, prepend the current dir */ + curr = g_get_current_dir(); + absolute = g_strdup_printf("%s%s%s", curr, G_DIR_SEPARATOR_S, cf_name); + add_menu_recent_capture_file_absolute(absolute); + g_free(curr); + g_free(absolute); +} + + + +/* write a single menu item widget label to the user's recent file */ +/* helper, for menu_recent_file_write_all() */ +void menu_recent_file_write(GtkWidget *widget, gpointer data) { + GtkWidget *menu_item_child; + gchar *cf_name; + FILE *rf = (FILE *) data; + + + /* get capture filename from the menu item label */ + menu_item_child = (GTK_BIN(widget))->child; + gtk_label_get(GTK_LABEL(menu_item_child), &cf_name); + + fprintf (rf, RECENT_KEY_CAPTURE_FILE ": %s\n", cf_name); +} + + +/* write all capture filenames of the menu to the user's recent file */ +void +menu_recent_file_write_all(FILE *rf) { + GtkWidget *submenu_recent_files; + + + submenu_recent_files = gtk_item_factory_get_widget(main_menu_factory, MENU_RECENT_FILES_PATH); + + gtk_container_foreach(GTK_CONTAINER(submenu_recent_files), + menu_recent_file_write, rf); +} + + gint popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data) { diff --git a/gtk/menu.h b/gtk/menu.h index 6bef198aa5..a215f9d9bc 100644 --- a/gtk/menu.h +++ b/gtk/menu.h @@ -1,7 +1,7 @@ /* menu.h * Menu definitions * - * $Id: menu.h,v 1.11 2003/09/24 02:36:35 guy Exp $ + * $Id: menu.h,v 1.12 2003/12/13 18:01:30 ulfl Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -29,6 +29,9 @@ extern "C" { #endif /* __cplusplus */ +/* Write all recent capture filenames to the user's recent file */ +void menu_recent_file_write_all(FILE *rf); + void get_main_menu (GtkWidget **, GtkAccelGroup **); void set_menu_object_data (gchar *path, gchar *key, gpointer data); gint popup_menu_handler(GtkWidget *widget, GdkEvent *event, gpointer data); @@ -2,7 +2,7 @@ * Definitions for menu routines with toolkit-independent APIs but * toolkit-dependent implementations. * - * $Id: menu.h,v 1.11 2003/09/24 02:36:33 guy Exp $ + * $Id: menu.h,v 1.12 2003/12/13 18:01:29 ulfl Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs <gerald@ethereal.com> @@ -30,6 +30,11 @@ extern "C" { #endif /* __cplusplus */ + +/* Add a new recent capture filename to the "Recent Files" submenu + (duplicates will be ignored) */ +void add_menu_recent_capture_file(gchar *file); + /* Routines to enable or disable sets of menu items. */ /* Enable or disable menu items based on whether you have a capture file |