diff --git a/file.c b/file.c index 8f7d7ba1e4..4efffb2e14 100644 --- a/file.c +++ b/file.c @@ -73,15 +73,12 @@ #include "packet-range.h" #include "print.h" #include "file.h" -#include "main_window.h" -#include "menu.h" #include "util.h" #include "merge.h" #include "alert_box.h" #include "simple_dialog.h" #include "progress_dlg.h" #include "ui_util.h" -#include "statusbar.h" #include #include #include @@ -89,7 +86,6 @@ #include #include "tap_dfilter_dlg.h" #include -#include "capture_ui_utils.h" /* Win32 needs the O_BINARY flag for open() */ #ifndef O_BINARY @@ -144,6 +140,39 @@ static gboolean copy_binary_file(const char *from_filename, const char *to_fil #define FRAME_DATA_CHUNK_SIZE 1024 +typedef void (*cf_callback_t) (gint event, gpointer data, gpointer user_data); + +/* one callback for now, we could have a list later */ +cf_callback_t cf_cb = NULL; +gpointer cf_cb_user_data = NULL; + +void +cf_callback_invoke(int event, gpointer data) +{ + g_assert(cf_cb != NULL); + cf_cb(event, data, cf_cb_user_data); +} + + +void +cf_callback_add(cf_callback_t func, gpointer user_data) +{ + /* More than one callback listener is currently not implemented, + but should be easy to do. */ + g_assert(cf_cb == NULL); + cf_cb = func; + cf_cb_user_data = user_data; +} + +void +cf_callback_remove(cf_callback_t func) +{ + g_assert(cf_cb != NULL); + cf_cb = NULL; + cf_cb_user_data = NULL; +} + + cf_status_t cf_open(capture_file *cf, const char *fname, gboolean is_tempfile, int *err) { @@ -227,10 +256,6 @@ cf_close(capture_file *cf) /* Die if we're in the middle of reading a file. */ g_assert(cf->state != FILE_READ_IN_PROGRESS); - /* Destroy all windows, which refer to the - capture file we're closing. */ - destroy_cfile_wins(); - if (cf->wth) { wtap_close(cf->wth); cf->wth = NULL; @@ -274,24 +299,7 @@ cf_close(capture_file *cf) cf->esec = 0; cf->eusec = 0; - /* 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); + cf_callback_invoke(cf_cb_file_closed, cf); reset_tap_listeners(); @@ -299,52 +307,6 @@ cf_close(capture_file *cf) cf->state = FILE_CLOSED; } -/* 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); -} - cf_read_status_t cf_read(capture_file *cf) { @@ -373,14 +335,13 @@ cf_read(capture_file *cf) int progbar_quantum; cum_bytes=0; + reset_tap_listeners(); tap_dfilter_dlg_update(); + + cf_callback_invoke(cf_cb_file_read_start, cf); + 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); - load_msg = g_strdup_printf(load_fmt, name_ptr); /* Update the progress bar when it gets to this value. */ @@ -471,19 +432,7 @@ cf_read(capture_file *cf) cf->current_frame = cf->first_displayed; packet_list_thaw(); - 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); - - /* Set up main window for a capture file. */ - main_set_for_capture_file(TRUE); - - /* Enable menu items that make sense if you have some captured packets. */ - set_menus_for_captured_packets(TRUE); + cf_callback_invoke(cf_cb_file_read_finished, cf); /* If we have any displayed packets to select, select the first of those packets by making the first row the selected row. */ @@ -540,28 +489,11 @@ cf_read(capture_file *cf) cf_status_t cf_start_tail(capture_file *cf, const char *fname, const char *iface, gboolean is_tempfile, int *err) { - gchar *capture_msg; cf_status_t cf_status; cf_status = cf_open(cf, fname, is_tempfile, err); if (cf_status == CF_OK) { - /* 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); - - /* Set up main window for a capture file. */ - main_set_for_capture_file(TRUE); - - capture_msg = g_strdup_printf(" %s: ", get_interface_descriptive_name(iface)); - - statusbar_push_file_msg(capture_msg); - - g_free(capture_msg); - + cf_callback_invoke(cf_cb_live_capture_started, cf); } return cf_status; } @@ -669,22 +601,7 @@ cf_finish_tail(capture_file *cf, int *err) WTAP_ENCAP_PER_PACKET). */ cf->lnk_t = wtap_file_encap(cf->wth); - /* Pop the "" 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); + cf_callback_invoke(cf_cb_live_capture_finished, cf); if (*err != 0) { /* We got an error reading the capture file. @@ -706,9 +623,6 @@ 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)"; } @@ -2984,14 +2898,7 @@ cf_select_packet(capture_file *cf, int row) epan_dissect_run(cf->edt, &cf->pseudo_header, cf->pd, cf->current_frame, NULL); - /* 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); + cf_callback_invoke(cf_cb_packet_selected, cf); } /* Unselect the selected packet, if any. */ @@ -3004,12 +2911,10 @@ cf_unselect_packet(capture_file *cf) cf->edt = NULL; } - /* Clear out the display of that packet. */ - clear_tree_and_hex_views(); - /* No packet is selected. */ cf->current_frame = NULL; - set_menus_for_selected_packet(cf); + + cf_callback_invoke(cf_cb_packet_unselected, cf); /* No protocol tree means no selected field. */ cf_unselect_field(cf); @@ -3019,9 +2924,9 @@ cf_unselect_packet(capture_file *cf) void cf_unselect_field(capture_file *cf) { - statusbar_pop_field_msg(); cf->finfo_selected = NULL; - set_menus_for_selected_tree_row(cf); + + cf_callback_invoke(cf_cb_field_unselected, cf); } /* @@ -3090,21 +2995,13 @@ cf_status_t cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_format) { gchar *from_filename; - const gchar *name_ptr; - gchar *save_msg, *save_fmt = " Saving: %s..."; - size_t msg_len; int err; gboolean do_copy; wtap_dumper *pdh; struct stat infile, outfile; save_callback_args_t callback_args; - name_ptr = get_basename(fname); - msg_len = strlen(name_ptr) + strlen(save_fmt) + 2; - save_msg = g_malloc(msg_len); - snprintf(save_msg, msg_len, save_fmt, name_ptr); - statusbar_push_file_msg(save_msg); - g_free(save_msg); + cf_callback_invoke(cf_cb_file_safe_started, (gpointer) fname); /* * Check that the from file is not the same as to file @@ -3235,8 +3132,7 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f } } - /* Pop the "Saving:" message off the status bar. */ - statusbar_pop_file_msg(); + cf_callback_invoke(cf_cb_file_safe_finished, NULL); if (packet_range_process_all(range)) { /* We saved the entire capture, not just some packets from it. @@ -3270,14 +3166,13 @@ cf_save(capture_file *cf, const char *fname, packet_range_t *range, guint save_f correctly for the "no capture file open" state). */ break; } - set_menus_for_unsaved_capture_file(FALSE); + cf_callback_invoke(cf_cb_file_safe_reload_finished, NULL); } } return CF_OK; fail: - /* Pop the "Saving:" message off the status bar. */ - statusbar_pop_file_msg(); + cf_callback_invoke(cf_cb_file_safe_failed, NULL); return CF_ERROR; } diff --git a/file.h b/file.h index ee47fee173..a1f7a97069 100644 --- a/file.h +++ b/file.h @@ -55,6 +55,29 @@ typedef enum { CF_PRINT_WRITE_ERROR /**< print operation failed while writing to the printer */ } cf_print_status_t; +typedef enum { + cf_cb_file_closed, + cf_cb_file_read_start, + cf_cb_file_read_finished, + cf_cb_live_capture_started, + cf_cb_live_capture_finished, + cf_cb_packet_selected, + cf_cb_packet_unselected, + cf_cb_field_unselected, + cf_cb_file_safe_started, + cf_cb_file_safe_finished, + cf_cb_file_safe_reload_finished, + cf_cb_file_safe_failed +} cf_cbs; + +typedef void (*cf_callback_t) (gint event, gpointer data, gpointer user_data); + +extern void +cf_callback_add(cf_callback_t func, gpointer user_data); + +extern void +cf_callback_remove(cf_callback_t func); + /** * Open a capture file. * diff --git a/gtk/main.c b/gtk/main.c index 264dc2f892..995f17bf49 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -142,6 +142,7 @@ #include "webbrowser.h" #include "capture_dlg.h" #include "../image/eicon3d64.xpm" +#include "capture_ui_utils.h" @@ -1240,6 +1241,265 @@ 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); +} + + +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); +} + +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); +} + +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); +} + +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: ", 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); +} + +void +main_cf_cb_live_capture_finished(capture_file *cf) +{ + /* Pop the "" 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); +} + +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); +} + +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); +} + +void +main_cf_cb_field_unselected(capture_file *cf) +{ + statusbar_pop_field_msg(); + set_menus_for_selected_tree_row(cf); +} + +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); +} + +void +main_cf_cb_file_safe_finished(gpointer data _U_) +{ + /* Pop the "Saving:" message off the status bar. */ + statusbar_pop_file_msg(); +} + +void +main_cf_cb_file_safe_failed(gpointer data _U_) +{ + /* Pop the "Saving:" message off the status bar. */ + statusbar_pop_file_msg(); +} + +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; + 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; + 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 @@ -1317,6 +1577,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();