2 * packet list related functions 2002 Olivier Abad
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #ifndef NEW_PACKET_LIST
36 #include <epan/epan.h>
37 #include <epan/column.h>
38 #include <epan/column_info.h>
39 #include <epan/prefs.h>
40 #include <epan/timestamp.h>
42 #include "../globals.h"
44 #include "../color_filters.h"
45 #include "../ui_util.h"
46 #include "../progress_dlg.h"
48 #include "gtk/gtkglobals.h"
49 #include "gtk/gui_utils.h"
50 #include "gtk/color_utils.h"
51 #include "gtk/capture_file_dlg.h"
53 #include "gtk/font_utils.h"
54 #include "gtk/packet_history.h"
55 #include "gtk/recent.h"
57 #include "gtk/menus.h"
58 #include "gtk/main_packet_list.h"
59 #include "gtk/main_statusbar.h"
60 #include "gtk/packet_win.h"
61 #include "gtk/prefs_column.h"
62 #include "gtk/prefs_dlg.h"
63 #include "gtk/dlg_utils.h"
65 #include "image/clist_ascend.xpm"
66 #include "image/clist_descend.xpm"
68 #define N_PROGBAR_UPDATES 100
70 typedef struct column_arrows {
74 GtkWidget *descend_pm;
77 GtkWidget *packet_list;
78 static gboolean last_at_end = FALSE;
80 /* GtkClist compare routine, overrides default to allow numeric comparison */
83 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
85 /* Get row data structures */
86 const GtkCListRow *row1 = (const GtkCListRow *)ptr1;
87 const GtkCListRow *row2 = (const GtkCListRow *)ptr2;
89 /* Get the frame data structures for the rows */
90 const frame_data *fdata1 = row1->data;
91 const frame_data *fdata2 = row2->data;
93 /* Get row text strings */
94 const char *text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
95 const char *text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
97 /* Attempt to convert to numbers */
101 /* For checking custom column type */
102 header_field_info *hfi;
103 gboolean custom_numeric = FALSE;
107 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
114 case COL_ABS_DATE_TIME:
117 case COL_DELTA_TIME_DIS:
118 case COL_PACKET_LENGTH:
119 case COL_CUMULATIVE_BYTES:
120 return frame_data_compare(fdata1, fdata2, col_fmt);
123 hfi = proto_registrar_get_byname(cfile.cinfo.col_custom_field[clist->sort_column]);
125 return frame_data_compare(fdata1, fdata2, COL_NUMBER);
126 } else if ((hfi->strings == NULL) &&
127 (((IS_FT_INT(hfi->type) || IS_FT_UINT(hfi->type)) &&
128 ((hfi->display == BASE_DEC) || (hfi->display == BASE_DEC_HEX) ||
129 (hfi->display == BASE_OCT))) ||
130 (hfi->type == FT_DOUBLE) || (hfi->type == FT_FLOAT) ||
131 (hfi->type == FT_BOOLEAN) || (hfi->type == FT_FRAMENUM) ||
132 (hfi->type == FT_RELATIVE_TIME))) {
134 /* Compare numeric column */
135 custom_numeric = TRUE;
141 if ((col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
143 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) ||
144 (col_fmt == COL_RES_SRC_PORT) ||
145 (col_fmt == COL_DEF_DST_PORT) ||
146 (col_fmt == COL_RES_DST_PORT)))) {
148 /* Compare numeric column */
152 else if (num1 > num2)
155 return frame_data_compare(fdata1, fdata2, COL_NUMBER);
160 /* Compare text column */
165 return frame_data_compare(fdata1, fdata2, COL_NUMBER);
171 ret = strcmp(text1, text2);
173 return frame_data_compare(fdata1, fdata2, COL_NUMBER);
181 col_title_change_ok (GtkWidget *w, gpointer parent_w)
183 GtkWidget *column_lb = g_object_get_data (G_OBJECT(w), "column");
184 gint col_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(packet_list), E_MPACKET_LIST_COL_ID_KEY));
185 GtkWidget *entry = g_object_get_data (G_OBJECT(w), "entry");
186 const gchar *title = gtk_entry_get_text(GTK_ENTRY(entry));
188 gtk_label_set_text (GTK_LABEL(column_lb), title);
189 column_prefs_rename(col_id, title);
191 if (!prefs.gui_use_pref_save) {
195 window_destroy(GTK_WIDGET(parent_w));
199 col_title_change_cancel (GtkWidget *w _U_, gpointer parent_w)
201 window_destroy(GTK_WIDGET(parent_w));
205 col_title_edit_dlg (gint col_id, gpointer data)
207 column_arrows *col_arrows = (column_arrows *) data;
208 const gchar *value = gtk_label_get_text (GTK_LABEL(col_arrows[col_id].label));
210 GtkWidget *win, *main_tb, *main_vb, *bbox, *cancel_bt, *ok_bt;
211 GtkWidget *entry, *label;
213 win = dlg_window_new("Column Title");
215 gtk_window_set_resizable(GTK_WINDOW(win),FALSE);
216 gtk_window_resize(GTK_WINDOW(win), 400, 100);
218 main_vb = gtk_vbox_new(FALSE, 5);
219 gtk_container_add(GTK_CONTAINER(win), main_vb);
220 gtk_container_set_border_width(GTK_CONTAINER(main_vb), 6);
222 main_tb = gtk_table_new(2, 2, FALSE);
223 gtk_box_pack_start(GTK_BOX(main_vb), main_tb, FALSE, FALSE, 0);
224 gtk_table_set_col_spacings(GTK_TABLE(main_tb), 10);
226 label = gtk_label_new(ep_strdup_printf("Title:"));
227 gtk_table_attach_defaults(GTK_TABLE(main_tb), label, 0, 1, 1, 2);
228 gtk_misc_set_alignment(GTK_MISC(label), 1.0f, 0.5f);
230 entry = gtk_entry_new();
231 gtk_table_attach_defaults(GTK_TABLE(main_tb), entry, 1, 2, 1, 2);
232 gtk_entry_set_text(GTK_ENTRY(entry), value);
234 bbox = dlg_button_row_new(GTK_STOCK_CANCEL,GTK_STOCK_OK, NULL);
235 gtk_box_pack_end(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
237 ok_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_OK);
238 g_object_set_data (G_OBJECT(ok_bt), "column", col_arrows[col_id].label);
239 g_object_set_data (G_OBJECT(ok_bt), "entry", entry);
240 g_signal_connect(ok_bt, "clicked", G_CALLBACK(col_title_change_ok), win);
242 dlg_set_activate(entry, ok_bt);
244 cancel_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CANCEL);
245 g_signal_connect(cancel_bt, "clicked", G_CALLBACK(col_title_change_cancel), win);
246 window_set_cancel_button(win, cancel_bt, NULL);
248 gtk_widget_grab_default(ok_bt);
249 gtk_widget_show_all(win);
254 packet_list_resize_column (gint col_id)
256 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), col_id, TRUE);
257 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), col_id, TRUE);
262 packet_list_remove_column (gint col_id)
264 column_prefs_remove(col_id);
266 if (!prefs.gui_use_pref_save) {
270 packet_list_recreate();
273 /* What to do when a column is clicked */
275 packet_list_sort_column(gint column, gpointer data, GtkSortType order)
277 column_arrows *col_arrows = (column_arrows *) data;
278 GtkCList *clist = GTK_CLIST(packet_list);
281 gtk_clist_freeze(clist);
283 for (i = 0; i < cfile.cinfo.num_cols; i++) {
284 gtk_widget_hide(col_arrows[i].ascend_pm);
285 gtk_widget_hide(col_arrows[i].descend_pm);
288 clist->sort_type = order;
289 if (clist->sort_type == GTK_SORT_ASCENDING) {
290 gtk_widget_show(col_arrows[column].ascend_pm);
292 gtk_widget_show(col_arrows[column].descend_pm);
294 if (column != clist->sort_column) {
295 gtk_clist_set_sort_column(clist, column);
297 gtk_clist_thaw(clist);
299 gtk_clist_sort(clist);
304 packet_list_column_clicked (GtkWidget *w _U_, gpointer user_data _U_, COLUMN_SELECTED_E action)
306 gint col_id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(packet_list), E_MPACKET_LIST_COL_ID_KEY));
307 gpointer data = g_object_get_data (G_OBJECT(packet_list), E_MPACKET_LIST_COL_ARROWS_KEY);
310 case COLUMN_SELECTED_SORT_ASCENDING:
311 packet_list_sort_column (col_id, data, GTK_SORT_ASCENDING);
313 case COLUMN_SELECTED_SORT_DESCENDING:
314 packet_list_sort_column (col_id, data, GTK_SORT_DESCENDING);
316 case COLUMN_SELECTED_RESIZE:
317 packet_list_resize_column (col_id);
319 case COLUMN_SELECTED_RENAME:
320 col_title_edit_dlg (col_id, data);
322 case COLUMN_SELECTED_REMOVE:
323 packet_list_remove_column (col_id);
326 g_assert_not_reached();
332 packet_list_click_column_cb (GtkCList *clist, gint column, gpointer data)
336 menu = g_object_get_data (G_OBJECT(popup_menu_object), PM_PACKET_LIST_COL_KEY);
337 g_object_set_data(G_OBJECT(clist), E_MPACKET_LIST_COL_ID_KEY, GINT_TO_POINTER(column));
338 g_object_set_data(G_OBJECT(clist), E_MPACKET_LIST_COL_ARROWS_KEY, data);
339 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 1, gtk_get_current_event_time());
344 packet_list_resize_column_cb(GtkCList *clist _U_, gint column, gint width, gpointer data _U_)
346 recent_set_column_width (column, width);
349 /* What to do when a list item is selected/unselected */
351 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, GdkEventButton *event _U_, gpointer evt _U_)
355 /* Check if already selected */
356 if (cfile.current_frame && cfile.current_row == row)
359 /* Remove the hex display tabbed pages */
360 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
361 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
363 cf_select_packet(&cfile, row);
364 gtk_widget_grab_focus(packet_list);
366 /* Lookup the frame number that corresponds to the list row number */
367 fdata = (frame_data *)packet_list_get_row_data(row);
369 packet_history_add(fdata->num);
374 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, GdkEventButton *event _U_, gpointer evt _U_)
376 cf_unselect_packet(&cfile);
381 set_frame_mark(gboolean set, frame_data *frame, gint row)
388 cf_mark_frame(&cfile, frame);
389 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
390 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
391 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
392 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
394 const color_filter_t *cfilter = frame->color_filter;
396 cf_unmark_frame(&cfile, frame);
397 /* Restore the color from the matching color filter if any */
398 if (cfilter) { /* The packet matches a color filter */
399 color_t_to_gdkcolor(&fg, &cfilter->fg_color);
400 color_t_to_gdkcolor(&bg, &cfilter->bg_color);
401 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
402 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
403 } else { /* No color filter match */
404 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, NULL);
405 gtk_clist_set_background(GTK_CLIST(packet_list), row, NULL);
410 /* call this after last set_frame_mark is done */
411 static void mark_frames_ready(void)
413 file_save_update_dynamics();
414 packets_bar_update();
417 void packet_list_mark_frame_cb(GtkWidget *w _U_, gpointer data _U_)
419 if (cfile.current_frame) {
420 set_frame_mark(!cfile.current_frame->flags.marked,
421 cfile.current_frame, cfile.current_row);
426 static void mark_all_frames(gboolean set)
430 /* XXX: we might need a progressbar here */
431 for (fdata = cfile.plist_start; fdata != NULL; fdata = fdata->next) {
434 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
439 void packet_list_update_marked_frames(void)
443 if (cfile.plist_start == NULL) return;
445 /* XXX: we might need a progressbar here */
446 for (fdata = cfile.plist_start; fdata != NULL; fdata = fdata->next) {
447 if (fdata->flags.marked)
448 set_frame_mark(TRUE, fdata,
449 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
455 void packet_list_mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_)
457 mark_all_frames(TRUE);
460 void packet_list_unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_)
462 mark_all_frames(FALSE);
465 #ifndef NEW_PACKET_LIST
467 packet_list_get_event_row_column(GtkWidget *w, GdkEventButton *event_button,
468 gint *row, gint *column)
470 return gtk_clist_get_selection_info(GTK_CLIST(w),
471 (gint) event_button->x, (gint) event_button->y,
474 #endif /* NEW_PACKET_LIST */
477 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
479 GdkEventButton *event_button = (GdkEventButton *)event;
482 if (w == NULL || event == NULL)
485 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
486 event_button->window == GTK_CLIST(w)->clist_window &&
487 gtk_clist_get_selection_info(GTK_CLIST(w), (gint) event_button->x,
488 (gint) event_button->y, &row, &column)) {
489 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(w), row);
490 set_frame_mark(!fdata->flags.marked, fdata, row);
495 if (event->type == GDK_2BUTTON_PRESS && event_button->button == 1 &&
496 event_button->window == GTK_CLIST(w)->clist_window ) {
505 /* Set the selection mode of the packet list window. */
507 packet_list_set_sel_browse(gboolean val, gboolean force_set)
509 GtkSelectionMode new_mode;
510 /* initialize with a mode we don't use, so that the mode == new_mode
511 * test will fail the first time */
512 static GtkSelectionMode mode = GTK_SELECTION_MULTIPLE;
514 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I
515 * think "browse" in Wireshark makes more sense than "SINGLE" in GTK+ */
516 new_mode = val ? GTK_SELECTION_SINGLE : GTK_SELECTION_BROWSE;
518 if ((mode == new_mode) && !force_set) {
520 * The mode isn't changing, so don't do anything.
521 * In particular, don't gratuitiously unselect the
524 * XXX - why do we have to unselect the current packet
525 * ourselves? The documentation for the GtkCList at
527 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
529 * says "Note that setting the widget's selection mode to
530 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
531 * cause all the items in the GtkCList to become deselected."
536 if (cfile.finfo_selected)
537 cf_unselect_field(&cfile);
540 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), mode);
543 /* Set the font of the packet list window. */
545 packet_list_set_font(PangoFontDescription *font)
551 /* Manually set the font so it can be used right away in the
552 * pango_layout_get_pixel_size call below. The gtk_widget_modify_font
553 * function only takes effect after the widget is displayed. */
554 packet_list->style->font_desc = pango_font_description_copy(font);
556 gtk_widget_modify_font(packet_list, font);
558 /* Compute default column sizes. */
559 for (i = 0; i < cfile.cinfo.num_cols; i++) {
560 col_width = recent_get_column_width(i);
561 if (col_width == -1) {
562 layout = gtk_widget_create_pango_layout(packet_list, get_column_width_string(get_column_format(i), i));
563 pango_layout_get_pixel_size(layout, &col_width, NULL);
564 g_object_unref(G_OBJECT(layout));
566 gtk_clist_set_column_width(GTK_CLIST(packet_list), i, col_width);
571 packet_list_new(e_prefs *prefs)
573 GtkWidget *pkt_scrollw;
574 header_field_info *hfi;
575 gboolean custom_right_justify;
579 pkt_scrollw = scrolled_window_new(NULL, NULL);
580 /* The usual policy for scrolled windows is to set both scrollbars to automatic,
581 * meaning they'll only appear if the content doesn't fit into the window.
583 * As this doesn't seem to work in some cases for the vertical scrollbar
584 * (see http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=220),
585 * we show that scrollbar always. */
586 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pkt_scrollw),
587 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
588 /* the gtk_clist will have it's own GTK_SHADOW_IN, so don't use a shadow
589 * for both widgets */
590 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pkt_scrollw),
593 packet_list = gtk_clist_new(cfile.cinfo.num_cols);
594 /* Column titles are filled in below */
595 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
597 packet_list_set_sel_browse(prefs->gui_plist_sel_browse, FALSE);
598 packet_list_set_font(user_font_get_regular());
599 gtk_widget_set_name(packet_list, "packet list");
600 g_signal_connect(packet_list, "select-row", G_CALLBACK(packet_list_select_cb), NULL);
601 g_signal_connect(packet_list, "unselect-row", G_CALLBACK(packet_list_unselect_cb), NULL);
602 for (i = 0; i < cfile.cinfo.num_cols; i++) {
603 /* For performance reasons, columns do not automatically resize,
604 but are resizeable by the user. */
605 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
606 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
608 custom_right_justify = FALSE;
609 if (cfile.cinfo.col_fmt[i] == COL_CUSTOM) {
610 hfi = proto_registrar_get_byname(cfile.cinfo.col_custom_field[i]);
611 if ((hfi != NULL) && (hfi->strings == NULL) &&
612 ((hfi->type == FT_BOOLEAN) || (hfi->type == FT_FRAMENUM) ||
613 (((hfi->display == BASE_DEC) || (hfi->display == BASE_OCT)) &&
614 (IS_FT_INT(hfi->type) || IS_FT_UINT(hfi->type) ||
615 (hfi->type == FT_INT64) || (hfi->type == FT_UINT64))))) {
616 custom_right_justify = TRUE;
620 /* Right-justify some special columns. */
621 if (cfile.cinfo.col_fmt[i] == COL_NUMBER ||
622 cfile.cinfo.col_fmt[i] == COL_PACKET_LENGTH ||
623 cfile.cinfo.col_fmt[i] == COL_CUMULATIVE_BYTES ||
624 cfile.cinfo.col_fmt[i] == COL_DCE_CALL ||
625 custom_right_justify)
626 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
629 g_signal_connect(packet_list, "button_press_event", G_CALLBACK(popup_menu_handler),
630 g_object_get_data(G_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
631 g_signal_connect(packet_list, "button_press_event",
632 G_CALLBACK(packet_list_button_pressed_cb), NULL);
633 g_object_set_data(G_OBJECT(popup_menu_object), E_MPACKET_LIST_KEY, packet_list);
634 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
635 gtk_widget_show(packet_list);
641 packet_list_recreate(void)
643 gtk_widget_destroy(pkt_scrollw);
645 prefs.num_cols = g_list_length(prefs.col_list);
647 build_column_format_array(&cfile.cinfo, prefs.num_cols, FALSE);
649 pkt_scrollw = packet_list_new(&prefs);
650 gtk_widget_show(pkt_scrollw);
651 packet_list_set_column_titles();
652 packet_list_set_sel_browse(prefs.gui_plist_sel_browse, TRUE);
654 main_widgets_rearrange();
656 if(cfile.state != FILE_CLOSED)
661 packet_list_set_column_titles(void)
664 GdkPixmap *ascend_pm, *descend_pm;
665 GdkBitmap *ascend_bm, *descend_bm;
666 column_arrows *col_arrows;
669 win_style = gtk_widget_get_style(top_level);
670 ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
671 &win_style->bg[GTK_STATE_NORMAL],
672 (gchar **) clist_ascend_xpm);
673 descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
674 &win_style->bg[GTK_STATE_NORMAL],
675 (gchar **) clist_descend_xpm);
677 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) *
678 cfile.cinfo.num_cols);
679 for (i = 0; i < cfile.cinfo.num_cols; i++) {
680 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
681 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
682 col_arrows[i].label = gtk_label_new(cfile.cinfo.col_title[i]);
683 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].label, 0, 1, 0, 2,
684 GTK_SHRINK, GTK_SHRINK, 0, 0);
685 gtk_widget_show(col_arrows[i].label);
686 col_arrows[i].ascend_pm = gtk_image_new_from_pixmap(ascend_pm, ascend_bm);
687 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
688 col_arrows[i].ascend_pm,
689 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
691 gtk_widget_show(col_arrows[i].ascend_pm);
693 col_arrows[i].descend_pm = gtk_image_new_from_pixmap(descend_pm, descend_bm);
694 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
695 col_arrows[i].descend_pm,
696 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
697 gtk_clist_set_column_widget(GTK_CLIST(packet_list), i,
698 col_arrows[i].table);
699 gtk_widget_show(col_arrows[i].table);
701 gtk_clist_column_titles_show(GTK_CLIST(packet_list));
702 g_signal_connect(packet_list, "click-column", G_CALLBACK(packet_list_click_column_cb), col_arrows);
703 g_signal_connect(packet_list, "resize-column", G_CALLBACK(packet_list_resize_column_cb), NULL);
707 packet_list_clear(void)
709 packet_history_clear();
711 gtk_clist_clear(GTK_CLIST(packet_list));
712 gtk_widget_queue_draw(packet_list);
716 packet_list_freeze(void)
718 gtk_clist_freeze(GTK_CLIST(packet_list));
722 packet_list_resize_columns(void)
725 int progbar_nextstep;
727 gboolean progbar_stop_flag;
728 GTimeVal progbar_start_time;
730 progdlg_t *progbar = NULL;
731 gchar status_str[100];
733 /* Update the progress bar when it gets to this value. */
734 progbar_nextstep = 0;
735 /* When we reach the value that triggers a progress bar update,
736 bump that value by this amount. */
737 progbar_quantum = cfile.cinfo.num_cols/N_PROGBAR_UPDATES;
738 /* Progress so far. */
741 progbar_stop_flag = FALSE;
742 g_get_current_time(&progbar_start_time);
745 main_window_update();
747 for (i = 0; i < cfile.cinfo.num_cols; i++) {
748 /* Create the progress bar if necessary.
749 We check on every iteration of the loop, so that it takes no
750 longer than the standard time to create it (otherwise, for a
751 large file, we might take considerably longer than that standard
752 time in order to get to the next progress bar step). */
754 progbar = delayed_create_progress_dlg("Resizing", "Resize Columns",
755 TRUE, &progbar_stop_flag, &progbar_start_time, progbar_val);
757 if (i >= progbar_nextstep) {
758 /* let's not divide by zero. I should never be started
759 * with count == 0, so let's assert that
761 g_assert(cfile.cinfo.num_cols > 0);
763 progbar_val = (gfloat) i / cfile.cinfo.num_cols;
765 if (progbar != NULL) {
766 g_snprintf(status_str, sizeof(status_str),
767 "%u of %u columns (%s)", i+1, cfile.cinfo.num_cols, cfile.cinfo.col_title[i]);
768 update_progress_dlg(progbar, progbar_val, status_str);
771 progbar_nextstep += progbar_quantum;
774 if (progbar_stop_flag) {
775 /* Well, the user decided to abort the resizing... */
779 /* auto resize the current column */
780 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
782 /* the current column should be resizeable by the user again */
783 /* (will turn off auto resize again) */
784 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
787 /* We're done resizing the columns; destroy the progress bar if it
790 destroy_progress_dlg(progbar);
793 void packet_list_resize_columns_cb(GtkWidget *widget _U_, gpointer data _U_)
795 packet_list_resize_columns();
799 packet_list_thaw(void)
801 gtk_clist_thaw(GTK_CLIST(packet_list));
802 packets_bar_update();
803 /*packet_list_resize_columns();*/
807 packet_list_select_row(gint row)
809 g_signal_emit_by_name(G_OBJECT(packet_list), "select_row", row);
813 packet_list_next_prev(gboolean next)
815 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(top_level));
816 g_signal_emit_by_name(G_OBJECT(packet_list), "scroll_vertical",
817 next ? GTK_SCROLL_STEP_FORWARD : GTK_SCROLL_STEP_BACKWARD, 0.0);
818 /* Set the focus back where it was */
820 gtk_window_set_focus(GTK_WINDOW(top_level), focus);
824 packet_list_next(void)
826 packet_list_next_prev(TRUE);
830 packet_list_prev(void)
832 packet_list_next_prev(FALSE);
836 packet_list_moveto_end(void)
838 gtk_clist_moveto(GTK_CLIST(packet_list),
839 GTK_CLIST(packet_list)->rows - 1, -1, 1.0f, 1.0f);
843 packet_list_check_end(void)
845 gboolean at_end = FALSE;
848 g_return_val_if_fail (packet_list != NULL, FALSE);
849 adj = gtk_clist_get_vadjustment(GTK_CLIST(packet_list));
850 g_return_val_if_fail (adj != NULL, FALSE);
852 if (adj->value >= adj->upper - adj->page_size) {
856 if (adj->value > 0 && at_end != last_at_end && at_end != auto_scroll_live) {
857 menu_auto_scroll_live_changed(at_end);
860 last_at_end = at_end;
865 packet_list_append(const gchar *text[], gpointer data)
869 row = gtk_clist_append(GTK_CLIST(packet_list), (gchar **) text);
870 gtk_clist_set_row_data(GTK_CLIST(packet_list), row, data);
875 packet_list_set_colors(gint row, color_t *fg, color_t *bg)
877 GdkColor gdkfg, gdkbg;
881 color_t_to_gdkcolor(&gdkfg, fg);
882 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &gdkfg);
886 color_t_to_gdkcolor(&gdkbg, bg);
887 gtk_clist_set_background(GTK_CLIST(packet_list), row, &gdkbg);
892 packet_list_find_row_from_data(gpointer data)
894 return gtk_clist_find_row_from_data(GTK_CLIST(packet_list), data);
898 packet_list_set_text(gint row, gint column, const gchar *text)
900 gtk_clist_set_text(GTK_CLIST(packet_list), row, column, text);
903 /* Set the column widths of those columns that show the time in
904 * "command-line-specified" format. */
906 packet_list_set_time_width(gint col_fmt, gint column)
911 width = recent_get_column_width(column);
913 layout = gtk_widget_create_pango_layout(packet_list,
914 get_column_longest_string(col_fmt));
915 pango_layout_get_pixel_size(layout, &width, NULL);
916 g_object_unref(G_OBJECT(layout));
918 gtk_clist_set_column_width(GTK_CLIST(packet_list), column, width);
922 packet_list_get_row_data(gint row)
924 return gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
928 /* get the first fully visible row number, given row MUST be visible */
930 packet_list_first_full_visible_row(gint row)
932 g_assert(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL);
934 while(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL) {
941 /* get the last fully visible row number, given row MUST be visible */
943 packet_list_last_full_visible_row(gint row)
945 g_assert(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL);
947 while(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL) {
954 /* Set the selected row and the focus row of the packet list to the specified
955 * row, and make it visible if it's not currently visible. */
957 packet_list_set_selected_row(gint row)
961 gboolean full_visible;
963 full_visible = gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL;
965 /* XXX - why is there no "gtk_clist_set_focus_row()", so that we
966 * can make the row for the frame we found the focus row?
968 * See http://www.gnome.org/mailing-lists/archives/gtk-list/2000-January/0038.shtml
970 GTK_CLIST(packet_list)->focus_row = row;
972 gtk_clist_select_row(GTK_CLIST(packet_list), row, -1);
975 gtk_clist_freeze(GTK_CLIST(packet_list));
977 gtk_clist_moveto(GTK_CLIST(packet_list), row, -1, 0.0f, 0.0f);
979 /* even after move still invisible (happens with empty list) -> give up */
980 if(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) != GTK_VISIBILITY_FULL) {
981 gtk_clist_thaw(GTK_CLIST(packet_list));
985 /* The now selected row will be the first visible row in the list.
986 * This is inconvenient, as the user is usually interested in some
987 * packets *before* the currently selected one too.
989 * Try to adjust the visible rows, so the currently selected row will
990 * be shown around the first third of the list screen.
992 * (This won't even do any harm if the current row is the first or the
993 * last in the list) */
994 visible_rows = packet_list_last_full_visible_row(row) - packet_list_first_full_visible_row(row);
995 first_row = row - visible_rows / 3;
997 gtk_clist_moveto(GTK_CLIST(packet_list), first_row >= 0 ? first_row : 0, -1, 0.0f, 0.0f);
999 gtk_clist_thaw(GTK_CLIST(packet_list));
1003 /* Return the column number that the clist is currently sorted by */
1005 packet_list_get_sort_column(void)
1007 return GTK_CLIST(packet_list)->sort_column;
1010 void packet_list_copy_summary_cb(GtkWidget * w _U_, gpointer data _U_, copy_summary_type copy_type)
1013 gchar* celltext = NULL;
1016 if(CS_CSV == copy_type) {
1017 text = g_string_new("\"");
1019 text = g_string_new("");
1022 if (cfile.current_frame) {
1023 for(col = 0; col < cfile.cinfo.num_cols; ++col) {
1025 if(CS_CSV == copy_type) {
1026 g_string_append(text,"\",\"");
1028 g_string_append_c(text, '\t');
1031 if(0 != gtk_clist_get_text(GTK_CLIST(packet_list),cfile.current_row,col,&celltext)) {
1032 g_string_append(text,celltext);
1035 if(CS_CSV == copy_type) {
1036 g_string_append_c(text,'"');
1038 copy_to_clipboard(text);
1040 g_string_free(text,TRUE);
1043 /* Re-sort the clist by the previously selected sort */
1045 packet_list_set_sort_column(void)
1047 packet_list_freeze();
1049 gtk_clist_set_sort_column(GTK_CLIST(packet_list), packet_list_get_sort_column());
1051 gtk_clist_sort(GTK_CLIST(packet_list));
1057 packet_list_recent_write_all(FILE *rf)
1061 fprintf (rf, "%s:", RECENT_KEY_COL_WIDTH);
1062 for (col = 0; col < cfile.cinfo.num_cols; col++) {
1063 if (cfile.cinfo.col_fmt[col] == COL_CUSTOM) {
1064 fprintf (rf, " %%Cus:%s,", get_column_custom_field(col));
1066 fprintf (rf, " %s,", col_format_to_string(cfile.cinfo.col_fmt[col]));
1068 fprintf (rf, " %d", GTK_CLIST(packet_list)->column[col].width);
1069 if (col != cfile.cinfo.num_cols-1) {
1076 #endif /* NEW_PACKET_LIST */