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.
32 #include <epan/epan.h>
33 #include <epan/column.h>
34 #include <epan/column_info.h>
35 #include <epan/prefs.h>
36 #include <epan/timestamp.h>
38 #include "../globals.h"
40 #include "../color_filters.h"
41 #include "../ui_util.h"
42 #include "../progress_dlg.h"
44 #include "gtk/gtkglobals.h"
45 #include "gtk/gui_utils.h"
46 #include "gtk/colors.h"
47 #include "gtk/capture_file_dlg.h"
49 #include "gtk/font_utils.h"
50 #include "gtk/packet_history.h"
51 #include "gtk/recent.h"
53 #include "gtk/main_menu.h"
54 #include "gtk/main_packet_list.h"
55 #include "gtk/main_statusbar.h"
57 #include "image/clist_ascend.xpm"
58 #include "image/clist_descend.xpm"
60 #define N_PROGBAR_UPDATES 100
62 typedef struct column_arrows {
65 GtkWidget *descend_pm;
68 GtkWidget *packet_list;
69 static gboolean last_at_end = FALSE;
71 /* GtkClist compare routine, overrides default to allow numeric comparison */
73 #define COMPARE_FRAME_NUM() ((fdata1->num < fdata2->num) ? -1 : \
74 (fdata1->num > fdata2->num) ? 1 : \
77 #define COMPARE_NUM(f) ((fdata1->f < fdata2->f) ? -1 : \
78 (fdata1->f > fdata2->f) ? 1 : \
81 /* Compare time stamps.
82 A packet whose time is a reference time is considered to have
83 a lower time stamp than any frame with a non-reference time;
84 if both packets' times are reference times, we compare the
85 times of the packets. */
86 #define COMPARE_TS(ts) \
87 ((fdata1->flags.ref_time && !fdata2->flags.ref_time) ? -1 : \
88 (!fdata1->flags.ref_time && fdata2->flags.ref_time) ? 1 : \
89 (fdata1->ts.secs < fdata2->ts.secs) ? -1 : \
90 (fdata1->ts.secs > fdata2->ts.secs) ? 1 : \
91 (fdata1->ts.nsecs < fdata2->ts.nsecs) ? -1 :\
92 (fdata1->ts.nsecs > fdata2->ts.nsecs) ? 1 : \
95 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
97 /* Get row data structures */
98 const GtkCListRow *row1 = (const GtkCListRow *)ptr1;
99 const GtkCListRow *row2 = (const GtkCListRow *)ptr2;
101 /* Get the frame data structures for the rows */
102 const frame_data *fdata1 = row1->data;
103 const frame_data *fdata2 = row2->data;
105 /* Get row text strings */
106 const char *text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
107 const char *text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
109 /* Attempt to convert to numbers */
113 /* For checking custom column type */
114 header_field_info *hfi;
115 gboolean custom_numeric = FALSE;
119 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
124 return COMPARE_FRAME_NUM();
127 switch (timestamp_get_type()) {
130 case TS_ABSOLUTE_WITH_DATE:
132 return COMPARE_TS(abs_ts);
135 return COMPARE_TS(rel_ts);
138 return COMPARE_TS(del_cap_ts);
141 return COMPARE_TS(del_dis_ts);
149 case COL_ABS_DATE_TIME:
150 return COMPARE_TS(abs_ts);
153 return COMPARE_TS(rel_ts);
156 return COMPARE_TS(del_cap_ts);
158 case COL_DELTA_TIME_DIS:
159 return COMPARE_TS(del_dis_ts);
161 case COL_PACKET_LENGTH:
162 return COMPARE_NUM(pkt_len);
164 case COL_CUMULATIVE_BYTES:
165 return COMPARE_NUM(cum_bytes);
168 hfi = proto_registrar_get_byname(cfile.cinfo.col_custom_field[clist->sort_column]);
170 return COMPARE_FRAME_NUM();
171 } else if ((hfi->strings == NULL) &&
172 (((IS_FT_INT(hfi->type) || IS_FT_UINT(hfi->type)) &&
173 ((hfi->display == BASE_DEC) || (hfi->display == BASE_DEC_HEX) ||
174 (hfi->display == BASE_OCT))) ||
175 (hfi->type == FT_DOUBLE) || (hfi->type == FT_FLOAT) ||
176 (hfi->type == FT_BOOLEAN) || (hfi->type == FT_FRAMENUM) ||
177 (hfi->type == FT_RELATIVE_TIME))) {
179 /* Compare numeric column */
180 custom_numeric = TRUE;
186 if ((col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
188 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) ||
189 (col_fmt == COL_RES_SRC_PORT) ||
190 (col_fmt == COL_DEF_DST_PORT) ||
191 (col_fmt == COL_RES_DST_PORT)))) {
193 /* Compare numeric column */
197 else if (num1 > num2)
200 return COMPARE_FRAME_NUM();
205 /* Compare text column */
210 return COMPARE_FRAME_NUM();
216 ret = strcmp(text1, text2);
218 return COMPARE_FRAME_NUM();
225 /* What to do when a column is clicked */
227 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
229 column_arrows *col_arrows = (column_arrows *) data;
232 gtk_clist_freeze(clist);
234 for (i = 0; i < cfile.cinfo.num_cols; i++) {
235 gtk_widget_hide(col_arrows[i].ascend_pm);
236 gtk_widget_hide(col_arrows[i].descend_pm);
239 if (column == clist->sort_column) {
240 if (clist->sort_type == GTK_SORT_ASCENDING) {
241 clist->sort_type = GTK_SORT_DESCENDING;
242 gtk_widget_show(col_arrows[column].descend_pm);
244 clist->sort_type = GTK_SORT_ASCENDING;
245 gtk_widget_show(col_arrows[column].ascend_pm);
249 clist->sort_type = GTK_SORT_ASCENDING;
250 gtk_widget_show(col_arrows[column].ascend_pm);
251 gtk_clist_set_sort_column(clist, column);
253 gtk_clist_thaw(clist);
255 gtk_clist_sort(clist);
258 /* What to do when a list item is selected/unselected */
260 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, gpointer evt _U_) {
263 /* Remove the hex display tabbed pages */
264 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
265 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
267 cf_select_packet(&cfile, row);
268 gtk_widget_grab_focus(packet_list);
270 /* Lookup the frame number that corresponds to the list row number */
271 fdata = (frame_data *)packet_list_get_row_data(row);
273 packet_history_add(fdata->num);
278 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, gpointer evt _U_) {
280 cf_unselect_packet(&cfile);
285 set_frame_mark(gboolean set, frame_data *frame, gint row) {
291 cf_mark_frame(&cfile, frame);
292 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
293 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
294 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
295 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
297 color_filter_t *cfilter = frame->color_filter;
299 cf_unmark_frame(&cfile, frame);
300 /* Restore the color from the matching color filter if any */
301 if (cfilter) { /* The packet matches a color filter */
302 color_t_to_gdkcolor(&fg, &cfilter->fg_color);
303 color_t_to_gdkcolor(&bg, &cfilter->bg_color);
304 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
305 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
306 } else { /* No color filter match */
307 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, NULL);
308 gtk_clist_set_background(GTK_CLIST(packet_list), row, NULL);
313 /* call this after last set_frame_mark is done */
314 static void mark_frames_ready(void) {
315 file_save_update_dynamics();
316 packets_bar_update();
319 void packet_list_mark_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
320 if (cfile.current_frame) {
321 /* XXX hum, should better have a "cfile->current_row" here ... */
322 set_frame_mark(!cfile.current_frame->flags.marked,
324 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
325 cfile.current_frame));
330 static void mark_all_frames(gboolean set) {
333 /* XXX: we might need a progressbar here */
334 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
337 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
342 void packet_list_update_marked_frames(void) {
345 if (cfile.plist == NULL) return;
347 /* XXX: we might need a progressbar here */
348 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
349 if (fdata->flags.marked)
352 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
358 void packet_list_mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
359 mark_all_frames(TRUE);
362 void packet_list_unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
363 mark_all_frames(FALSE);
367 packet_list_get_event_row_column(GtkWidget *w, GdkEventButton *event_button,
368 gint *row, gint *column)
370 return gtk_clist_get_selection_info(GTK_CLIST(w),
371 (gint) event_button->x, (gint) event_button->y,
376 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
378 GdkEventButton *event_button = (GdkEventButton *)event;
381 if (w == NULL || event == NULL)
384 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
385 event_button->window == GTK_CLIST(w)->clist_window &&
386 gtk_clist_get_selection_info(GTK_CLIST(w), (gint) event_button->x,
387 (gint) event_button->y, &row, &column)) {
388 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(w),
390 set_frame_mark(!fdata->flags.marked, fdata, row);
397 /* Set the selection mode of the packet list window. */
399 packet_list_set_sel_browse(gboolean val, gboolean force_set)
401 GtkSelectionMode new_mode;
402 /* initialize with a mode we don't use, so that the mode == new_mode
403 * test will fail the first time */
404 static GtkSelectionMode mode = GTK_SELECTION_MULTIPLE;
406 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I
407 * think "browse" in Wireshark makes more sense than "SINGLE" in GTK+ */
408 new_mode = val ? GTK_SELECTION_SINGLE : GTK_SELECTION_BROWSE;
410 if ((mode == new_mode) && !force_set) {
412 * The mode isn't changing, so don't do anything.
413 * In particular, don't gratuitiously unselect the
416 * XXX - why do we have to unselect the current packet
417 * ourselves? The documentation for the GtkCList at
419 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
421 * says "Note that setting the widget's selection mode to
422 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
423 * cause all the items in the GtkCList to become deselected."
428 if (cfile.finfo_selected)
429 cf_unselect_field(&cfile);
432 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), mode);
435 /* Set the font of the packet list window. */
437 packet_list_set_font(PangoFontDescription *font, gboolean saved_column_width)
443 /* Manually set the font so it can be used right away in the
444 * pango_layout_get_pixel_size call below. The gtk_widget_modify_font
445 * function only takes effect after the widget is displayed. */
446 packet_list->style->font_desc = pango_font_description_copy(font);
448 gtk_widget_modify_font(packet_list, font);
450 /* Compute default column sizes. */
451 for (i = 0; i < cfile.cinfo.num_cols; i++) {
453 if (saved_column_width) {
454 col_width = recent_get_column_width(i);
456 if (col_width == -1) {
457 layout = gtk_widget_create_pango_layout(packet_list,
458 get_column_width_string(get_column_format(i), i));
459 pango_layout_get_pixel_size(layout, &col_width, NULL);
460 g_object_unref(G_OBJECT(layout));
462 gtk_clist_set_column_width(GTK_CLIST(packet_list), i,
468 packet_list_new(e_prefs *prefs)
470 GtkWidget *pkt_scrollw;
471 header_field_info *hfi;
472 gboolean custom_right_justify;
476 pkt_scrollw = scrolled_window_new(NULL, NULL);
477 /* The usual policy for scrolled windows is to set both scrollbars to automatic,
478 * meaning they'll only appear if the content doesn't fit into the window.
480 * As this doesn't seem to work in some cases for the vertical scrollbar
481 * (see http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=220),
482 * we show that scrollbar always. */
483 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pkt_scrollw),
484 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
485 /* the gtk_clist will have it's own GTK_SHADOW_IN, so don't use a shadow
486 * for both widgets */
487 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pkt_scrollw),
490 packet_list = gtk_clist_new(cfile.cinfo.num_cols);
491 /* Column titles are filled in below */
492 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
494 packet_list_set_sel_browse(prefs->gui_plist_sel_browse, FALSE);
495 packet_list_set_font(user_font_get_regular(), prefs->gui_geometry_save_column_width);
496 gtk_widget_set_name(packet_list, "packet list");
497 g_signal_connect(packet_list, "select-row", G_CALLBACK(packet_list_select_cb), NULL);
498 g_signal_connect(packet_list, "unselect-row", G_CALLBACK(packet_list_unselect_cb), NULL);
499 for (i = 0; i < cfile.cinfo.num_cols; i++) {
500 /* For performance reasons, columns do not automatically resize,
501 but are resizeable by the user. */
502 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
503 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
505 custom_right_justify = FALSE;
506 if (cfile.cinfo.col_fmt[i] == COL_CUSTOM) {
507 hfi = proto_registrar_get_byname(cfile.cinfo.col_custom_field[i]);
508 if ((hfi != NULL) && (hfi->strings == NULL) &&
509 ((hfi->type == FT_BOOLEAN) || (hfi->type == FT_FRAMENUM) ||
510 (((hfi->display == BASE_DEC) || (hfi->display == BASE_OCT)) &&
511 (IS_FT_INT(hfi->type) || IS_FT_UINT(hfi->type) ||
512 (hfi->type == FT_INT64) || (hfi->type == FT_UINT64))))) {
513 custom_right_justify = TRUE;
517 /* Right-justify some special columns. */
518 if (cfile.cinfo.col_fmt[i] == COL_NUMBER ||
519 cfile.cinfo.col_fmt[i] == COL_PACKET_LENGTH ||
520 cfile.cinfo.col_fmt[i] == COL_CUMULATIVE_BYTES ||
521 cfile.cinfo.col_fmt[i] == COL_DCE_CALL ||
522 cfile.cinfo.col_fmt[i] == COL_DCE_CTX ||
523 custom_right_justify)
524 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
527 g_signal_connect(packet_list, "button_press_event", G_CALLBACK(popup_menu_handler),
528 g_object_get_data(G_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
529 g_signal_connect(packet_list, "button_press_event",
530 G_CALLBACK(packet_list_button_pressed_cb), NULL);
531 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
532 gtk_widget_show(packet_list);
538 packet_list_recreate(void)
540 gtk_widget_destroy(pkt_scrollw);
542 prefs.num_cols = g_list_length(prefs.col_list);
544 build_column_format_array(&cfile.cinfo, FALSE);
546 pkt_scrollw = packet_list_new(&prefs);
547 gtk_widget_show(pkt_scrollw);
548 packet_list_set_column_titles();
549 packet_list_set_sel_browse(prefs.gui_plist_sel_browse, TRUE);
551 main_widgets_rearrange();
553 if(cfile.state != FILE_CLOSED)
554 cf_redissect_packets(&cfile);
558 packet_list_set_column_titles(void)
561 GdkPixmap *ascend_pm, *descend_pm;
562 GdkBitmap *ascend_bm, *descend_bm;
563 column_arrows *col_arrows;
565 GtkWidget *column_lb;
567 win_style = gtk_widget_get_style(top_level);
568 ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
569 &win_style->bg[GTK_STATE_NORMAL],
570 (gchar **) clist_ascend_xpm);
571 descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
572 &win_style->bg[GTK_STATE_NORMAL],
573 (gchar **) clist_descend_xpm);
575 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) *
576 cfile.cinfo.num_cols);
577 for (i = 0; i < cfile.cinfo.num_cols; i++) {
578 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
579 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
580 column_lb = gtk_label_new(cfile.cinfo.col_title[i]);
581 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2,
582 GTK_SHRINK, GTK_SHRINK, 0, 0);
583 gtk_widget_show(column_lb);
584 col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
585 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
586 col_arrows[i].ascend_pm,
587 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
589 gtk_widget_show(col_arrows[i].ascend_pm);
591 col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
592 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
593 col_arrows[i].descend_pm,
594 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
595 gtk_clist_set_column_widget(GTK_CLIST(packet_list), i,
596 col_arrows[i].table);
597 gtk_widget_show(col_arrows[i].table);
599 gtk_clist_column_titles_show(GTK_CLIST(packet_list));
600 g_signal_connect(packet_list, "click-column", G_CALLBACK(packet_list_click_column_cb),
605 packet_list_clear(void)
607 packet_history_clear();
609 gtk_clist_clear(GTK_CLIST(packet_list));
610 gtk_widget_queue_draw(packet_list);
614 packet_list_freeze(void)
616 gtk_clist_freeze(GTK_CLIST(packet_list));
620 packet_list_resize_columns(void) {
622 int progbar_nextstep;
624 gboolean progbar_stop_flag;
625 GTimeVal progbar_start_time;
627 progdlg_t *progbar = NULL;
628 gchar status_str[100];
630 /* Update the progress bar when it gets to this value. */
631 progbar_nextstep = 0;
632 /* When we reach the value that triggers a progress bar update,
633 bump that value by this amount. */
634 progbar_quantum = cfile.cinfo.num_cols/N_PROGBAR_UPDATES;
635 /* Progress so far. */
638 progbar_stop_flag = FALSE;
639 g_get_current_time(&progbar_start_time);
642 main_window_update();
644 for (i = 0; i < cfile.cinfo.num_cols; i++) {
645 /* Create the progress bar if necessary.
646 We check on every iteration of the loop, so that it takes no
647 longer than the standard time to create it (otherwise, for a
648 large file, we might take considerably longer than that standard
649 time in order to get to the next progress bar step). */
651 progbar = delayed_create_progress_dlg("Resizing", "Resize Columns",
652 TRUE, &progbar_stop_flag, &progbar_start_time, progbar_val);
654 if (i >= progbar_nextstep) {
655 /* let's not divide by zero. I should never be started
656 * with count == 0, so let's assert that
658 g_assert(cfile.cinfo.num_cols > 0);
660 progbar_val = (gfloat) i / cfile.cinfo.num_cols;
662 if (progbar != NULL) {
663 g_snprintf(status_str, sizeof(status_str),
664 "%u of %u columns (%s)", i+1, cfile.cinfo.num_cols, cfile.cinfo.col_title[i]);
665 update_progress_dlg(progbar, progbar_val, status_str);
668 progbar_nextstep += progbar_quantum;
671 if (progbar_stop_flag) {
672 /* Well, the user decided to abort the resizing... */
676 /* auto resize the current column */
677 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
679 /* the current column should be resizeable by the user again */
680 /* (will turn off auto resize again) */
681 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
684 /* We're done resizing the columns; destroy the progress bar if it
687 destroy_progress_dlg(progbar);
690 void packet_list_resize_columns_cb(GtkWidget *widget _U_, gpointer data _U_)
692 packet_list_resize_columns();
696 packet_list_thaw(void)
698 gtk_clist_thaw(GTK_CLIST(packet_list));
699 packets_bar_update();
700 /*packet_list_resize_columns();*/
704 packet_list_select_row(gint row)
706 g_signal_emit_by_name(G_OBJECT(packet_list), "select_row", row);
710 packet_list_next_prev(gboolean next)
712 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(top_level));
713 g_signal_emit_by_name(G_OBJECT(packet_list), "scroll_vertical",
714 next ? GTK_SCROLL_STEP_FORWARD : GTK_SCROLL_STEP_BACKWARD, 0.0);
715 /* Set the focus back where it was */
717 gtk_window_set_focus(GTK_WINDOW(top_level), focus);
721 packet_list_next(void)
723 packet_list_next_prev(TRUE);
727 packet_list_prev(void)
729 packet_list_next_prev(FALSE);
733 packet_list_moveto_end(void)
735 gtk_clist_moveto(GTK_CLIST(packet_list),
736 GTK_CLIST(packet_list)->rows - 1, -1, 1.0, 1.0);
740 packet_list_check_end(void)
742 gboolean at_end = FALSE;
745 g_return_val_if_fail (packet_list != NULL, FALSE);
746 adj = gtk_clist_get_vadjustment(GTK_CLIST(packet_list));
747 g_return_val_if_fail (adj != NULL, FALSE);
749 if (adj->value >= adj->upper - adj->page_size) {
753 if (adj->value > 0 && at_end != last_at_end && at_end != auto_scroll_live) {
754 menu_auto_scroll_live_changed(at_end);
757 last_at_end = at_end;
762 packet_list_append(const gchar *text[], gpointer data)
766 row = gtk_clist_append(GTK_CLIST(packet_list), (gchar **) text);
767 gtk_clist_set_row_data(GTK_CLIST(packet_list), row, data);
772 packet_list_set_colors(gint row, color_t *fg, color_t *bg)
774 GdkColor gdkfg, gdkbg;
778 color_t_to_gdkcolor(&gdkfg, fg);
779 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &gdkfg);
783 color_t_to_gdkcolor(&gdkbg, bg);
784 gtk_clist_set_background(GTK_CLIST(packet_list), row, &gdkbg);
789 packet_list_find_row_from_data(gpointer data)
791 return gtk_clist_find_row_from_data(GTK_CLIST(packet_list), data);
795 packet_list_set_text(gint row, gint column, const gchar *text)
797 gtk_clist_set_text(GTK_CLIST(packet_list), row, column, text);
800 /* Set the column widths of those columns that show the time in
801 * "command-line-specified" format. */
803 packet_list_set_cls_time_width(gint column)
808 if (prefs.gui_geometry_save_column_width) {
809 width = recent_get_column_width(column);
812 layout = gtk_widget_create_pango_layout(packet_list,
813 get_column_longest_string(COL_CLS_TIME));
814 pango_layout_get_pixel_size(layout, &width, NULL);
815 g_object_unref(G_OBJECT(layout));
817 gtk_clist_set_column_width(GTK_CLIST(packet_list), column, width);
821 packet_list_get_row_data(gint row)
823 return gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
827 /* get the first fully visible row number, given row MUST be visible */
829 packet_list_first_full_visible_row(gint row) {
831 g_assert(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) ==
832 GTK_VISIBILITY_FULL);
834 while(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) ==
835 GTK_VISIBILITY_FULL) {
842 /* get the last fully visible row number, given row MUST be visible */
844 packet_list_last_full_visible_row(gint row) {
846 g_assert(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) ==
847 GTK_VISIBILITY_FULL);
849 while(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) ==
850 GTK_VISIBILITY_FULL) {
857 /* Set the selected row and the focus row of the packet list to the specified
858 * row, and make it visible if it's not currently visible. */
860 packet_list_set_selected_row(gint row)
864 gboolean full_visible;
867 full_visible = gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) ==
870 /* XXX - why is there no "gtk_clist_set_focus_row()", so that we
871 * can make the row for the frame we found the focus row?
873 * See http://www.gnome.org/mailing-lists/archives/gtk-list/2000-January/0038.shtml
875 GTK_CLIST(packet_list)->focus_row = row;
877 gtk_clist_select_row(GTK_CLIST(packet_list), row, -1);
881 gtk_clist_freeze(GTK_CLIST(packet_list));
883 gtk_clist_moveto(GTK_CLIST(packet_list), row, -1, 0.0, 0.0);
885 /* even after move still invisible (happens with empty list) -> give up */
886 if(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) !=
887 GTK_VISIBILITY_FULL) {
888 gtk_clist_thaw(GTK_CLIST(packet_list));
892 /* The now selected row will be the first visible row in the list.
893 * This is inconvenient, as the user is usually interested in some
894 * packets *before* the currently selected one too.
896 * Try to adjust the visible rows, so the currently selected row will
897 * be shown around the first third of the list screen.
899 * (This won't even do any harm if the current row is the first or the
900 * last in the list) */
901 visible_rows = packet_list_last_full_visible_row(row) - packet_list_first_full_visible_row(row);
902 first_row = row - visible_rows / 3;
904 gtk_clist_moveto(GTK_CLIST(packet_list), first_row >= 0 ? first_row : 0, -1, 0.0, 0.0);
906 gtk_clist_thaw(GTK_CLIST(packet_list));
910 /* Return the column number that the clist is currently sorted by */
912 packet_list_get_sort_column(void)
914 return GTK_CLIST(packet_list)->sort_column;
917 void packet_list_copy_summary_cb(GtkWidget * w _U_, gpointer data _U_, copy_summary_type copy_type)
921 gchar* celltext = NULL;
924 if(CS_CSV == copy_type) {
925 text = g_string_new("\"");
927 text = g_string_new("");
930 if (cfile.current_frame) {
931 /* XXX hum, should better have a "cfile->current_row" here ... */
932 row = gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
933 cfile.current_frame);
934 for(col = 0; col < cfile.cinfo.num_cols; ++col) {
936 if(CS_CSV == copy_type) {
937 g_string_append(text,"\",\"");
939 g_string_append_c(text, '\t');
942 if(0 != gtk_clist_get_text(GTK_CLIST(packet_list),row,col,&celltext)) {
943 g_string_append(text,celltext);
946 if(CS_CSV == copy_type) {
947 g_string_append_c(text,'"');
949 copy_to_clipboard(text);
951 g_string_free(text,TRUE);
954 /* Re-sort the clist by the previously selected sort */
956 packet_list_set_sort_column(void)
958 packet_list_freeze();
960 gtk_clist_set_sort_column(GTK_CLIST(packet_list), packet_list_get_sort_column());
962 gtk_clist_sort(GTK_CLIST(packet_list));
968 packet_list_recent_write_all(FILE *rf)
972 fprintf (rf, "%s:", RECENT_KEY_COL_WIDTH);
973 for (col = 0; col < cfile.cinfo.num_cols; col++) {
974 if (cfile.cinfo.col_fmt[col] == COL_CUSTOM) {
975 fprintf (rf, " %%Cus:%s,", get_column_custom_field(col));
977 fprintf (rf, " %s,", col_format_to_string(cfile.cinfo.col_fmt[col]));
979 fprintf (rf, " %d", GTK_CLIST(packet_list)->column[col].width);
980 if (col != cfile.cinfo.num_cols-1) {