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/color_utils.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/menus.h"
54 #include "gtk/main_packet_list.h"
55 #include "gtk/main_statusbar.h"
56 #include "gtk/packet_win.h"
58 #include "image/clist_ascend.xpm"
59 #include "image/clist_descend.xpm"
61 #define N_PROGBAR_UPDATES 100
63 typedef struct column_arrows {
66 GtkWidget *descend_pm;
69 GtkWidget *packet_list;
70 static gboolean last_at_end = FALSE;
72 /* GtkClist compare routine, overrides default to allow numeric comparison */
74 #define COMPARE_FRAME_NUM() ((fdata1->num < fdata2->num) ? -1 : \
75 (fdata1->num > fdata2->num) ? 1 : \
78 #define COMPARE_NUM(f) ((fdata1->f < fdata2->f) ? -1 : \
79 (fdata1->f > fdata2->f) ? 1 : \
82 /* Compare time stamps.
83 A packet whose time is a reference time is considered to have
84 a lower time stamp than any frame with a non-reference time;
85 if both packets' times are reference times, we compare the
86 times of the packets. */
87 #define COMPARE_TS(ts) \
88 ((fdata1->flags.ref_time && !fdata2->flags.ref_time) ? -1 : \
89 (!fdata1->flags.ref_time && fdata2->flags.ref_time) ? 1 : \
90 (fdata1->ts.secs < fdata2->ts.secs) ? -1 : \
91 (fdata1->ts.secs > fdata2->ts.secs) ? 1 : \
92 (fdata1->ts.nsecs < fdata2->ts.nsecs) ? -1 :\
93 (fdata1->ts.nsecs > fdata2->ts.nsecs) ? 1 : \
96 packet_list_compare(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
98 /* Get row data structures */
99 const GtkCListRow *row1 = (const GtkCListRow *)ptr1;
100 const GtkCListRow *row2 = (const GtkCListRow *)ptr2;
102 /* Get the frame data structures for the rows */
103 const frame_data *fdata1 = row1->data;
104 const frame_data *fdata2 = row2->data;
106 /* Get row text strings */
107 const char *text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
108 const char *text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
110 /* Attempt to convert to numbers */
114 /* For checking custom column type */
115 header_field_info *hfi;
116 gboolean custom_numeric = FALSE;
120 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
125 return COMPARE_FRAME_NUM();
128 switch (timestamp_get_type()) {
131 case TS_ABSOLUTE_WITH_DATE:
133 return COMPARE_TS(abs_ts);
136 return COMPARE_TS(rel_ts);
139 return COMPARE_TS(del_cap_ts);
142 return COMPARE_TS(del_dis_ts);
150 case COL_ABS_DATE_TIME:
151 return COMPARE_TS(abs_ts);
154 return COMPARE_TS(rel_ts);
157 return COMPARE_TS(del_cap_ts);
159 case COL_DELTA_TIME_DIS:
160 return COMPARE_TS(del_dis_ts);
162 case COL_PACKET_LENGTH:
163 return COMPARE_NUM(pkt_len);
165 case COL_CUMULATIVE_BYTES:
166 return COMPARE_NUM(cum_bytes);
169 hfi = proto_registrar_get_byname(cfile.cinfo.col_custom_field[clist->sort_column]);
171 return COMPARE_FRAME_NUM();
172 } else if ((hfi->strings == NULL) &&
173 (((IS_FT_INT(hfi->type) || IS_FT_UINT(hfi->type)) &&
174 ((hfi->display == BASE_DEC) || (hfi->display == BASE_DEC_HEX) ||
175 (hfi->display == BASE_OCT))) ||
176 (hfi->type == FT_DOUBLE) || (hfi->type == FT_FLOAT) ||
177 (hfi->type == FT_BOOLEAN) || (hfi->type == FT_FRAMENUM) ||
178 (hfi->type == FT_RELATIVE_TIME))) {
180 /* Compare numeric column */
181 custom_numeric = TRUE;
187 if ((col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
189 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) ||
190 (col_fmt == COL_RES_SRC_PORT) ||
191 (col_fmt == COL_DEF_DST_PORT) ||
192 (col_fmt == COL_RES_DST_PORT)))) {
194 /* Compare numeric column */
198 else if (num1 > num2)
201 return COMPARE_FRAME_NUM();
206 /* Compare text column */
211 return COMPARE_FRAME_NUM();
217 ret = strcmp(text1, text2);
219 return COMPARE_FRAME_NUM();
226 /* What to do when a column is clicked */
228 packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
230 column_arrows *col_arrows = (column_arrows *) data;
233 gtk_clist_freeze(clist);
235 for (i = 0; i < cfile.cinfo.num_cols; i++) {
236 gtk_widget_hide(col_arrows[i].ascend_pm);
237 gtk_widget_hide(col_arrows[i].descend_pm);
240 if (column == clist->sort_column) {
241 if (clist->sort_type == GTK_SORT_ASCENDING) {
242 clist->sort_type = GTK_SORT_DESCENDING;
243 gtk_widget_show(col_arrows[column].descend_pm);
245 clist->sort_type = GTK_SORT_ASCENDING;
246 gtk_widget_show(col_arrows[column].ascend_pm);
250 clist->sort_type = GTK_SORT_ASCENDING;
251 gtk_widget_show(col_arrows[column].ascend_pm);
252 gtk_clist_set_sort_column(clist, column);
254 gtk_clist_thaw(clist);
256 gtk_clist_sort(clist);
260 packet_list_resize_column_cb(GtkCList *clist _U_, gint column, gint width, gpointer data _U_)
262 recent_set_column_width (column, width);
265 /* What to do when a list item is selected/unselected */
267 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, GdkEventButton *event _U_, gpointer evt _U_)
271 /* Check if already selected */
272 if (cfile.current_frame && cfile.current_row == row)
275 /* Remove the hex display tabbed pages */
276 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
277 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
279 cf_select_packet(&cfile, row);
280 gtk_widget_grab_focus(packet_list);
282 /* Lookup the frame number that corresponds to the list row number */
283 fdata = (frame_data *)packet_list_get_row_data(row);
285 packet_history_add(fdata->num);
290 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, GdkEventButton *event _U_, gpointer evt _U_)
292 cf_unselect_packet(&cfile);
297 set_frame_mark(gboolean set, frame_data *frame, gint row)
304 cf_mark_frame(&cfile, frame);
305 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
306 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
307 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
308 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
310 color_filter_t *cfilter = frame->color_filter;
312 cf_unmark_frame(&cfile, frame);
313 /* Restore the color from the matching color filter if any */
314 if (cfilter) { /* The packet matches a color filter */
315 color_t_to_gdkcolor(&fg, &cfilter->fg_color);
316 color_t_to_gdkcolor(&bg, &cfilter->bg_color);
317 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &fg);
318 gtk_clist_set_background(GTK_CLIST(packet_list), row, &bg);
319 } else { /* No color filter match */
320 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, NULL);
321 gtk_clist_set_background(GTK_CLIST(packet_list), row, NULL);
326 /* call this after last set_frame_mark is done */
327 static void mark_frames_ready(void)
329 file_save_update_dynamics();
330 packets_bar_update();
333 void packet_list_mark_frame_cb(GtkWidget *w _U_, gpointer data _U_)
335 if (cfile.current_frame) {
336 set_frame_mark(!cfile.current_frame->flags.marked,
337 cfile.current_frame, cfile.current_row);
342 static void mark_all_frames(gboolean set)
346 /* XXX: we might need a progressbar here */
347 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
350 gtk_clist_find_row_from_data(GTK_CLIST(packet_list), fdata));
355 void packet_list_update_marked_frames(void)
359 if (cfile.plist == NULL) return;
361 /* XXX: we might need a progressbar here */
362 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
363 if (fdata->flags.marked)
364 set_frame_mark(TRUE, fdata,
365 gtk_clist_find_row_from_data(GTK_CLIST(packet_list),
371 void packet_list_mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_)
373 mark_all_frames(TRUE);
376 void packet_list_unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_)
378 mark_all_frames(FALSE);
382 packet_list_get_event_row_column(GtkWidget *w, GdkEventButton *event_button,
383 gint *row, gint *column)
385 return gtk_clist_get_selection_info(GTK_CLIST(w),
386 (gint) event_button->x, (gint) event_button->y,
391 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
393 GdkEventButton *event_button = (GdkEventButton *)event;
396 if (w == NULL || event == NULL)
399 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
400 event_button->window == GTK_CLIST(w)->clist_window &&
401 gtk_clist_get_selection_info(GTK_CLIST(w), (gint) event_button->x,
402 (gint) event_button->y, &row, &column)) {
403 frame_data *fdata = (frame_data *)gtk_clist_get_row_data(GTK_CLIST(w), row);
404 set_frame_mark(!fdata->flags.marked, fdata, row);
409 if (event->type == GDK_2BUTTON_PRESS && event_button->button == 1 &&
410 event_button->window == GTK_CLIST(w)->clist_window ) {
419 /* Set the selection mode of the packet list window. */
421 packet_list_set_sel_browse(gboolean val, gboolean force_set)
423 GtkSelectionMode new_mode;
424 /* initialize with a mode we don't use, so that the mode == new_mode
425 * test will fail the first time */
426 static GtkSelectionMode mode = GTK_SELECTION_MULTIPLE;
428 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I
429 * think "browse" in Wireshark makes more sense than "SINGLE" in GTK+ */
430 new_mode = val ? GTK_SELECTION_SINGLE : GTK_SELECTION_BROWSE;
432 if ((mode == new_mode) && !force_set) {
434 * The mode isn't changing, so don't do anything.
435 * In particular, don't gratuitiously unselect the
438 * XXX - why do we have to unselect the current packet
439 * ourselves? The documentation for the GtkCList at
441 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
443 * says "Note that setting the widget's selection mode to
444 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
445 * cause all the items in the GtkCList to become deselected."
450 if (cfile.finfo_selected)
451 cf_unselect_field(&cfile);
454 gtk_clist_set_selection_mode(GTK_CLIST(packet_list), mode);
457 /* Set the font of the packet list window. */
459 packet_list_set_font(PangoFontDescription *font)
465 /* Manually set the font so it can be used right away in the
466 * pango_layout_get_pixel_size call below. The gtk_widget_modify_font
467 * function only takes effect after the widget is displayed. */
468 packet_list->style->font_desc = pango_font_description_copy(font);
470 gtk_widget_modify_font(packet_list, font);
472 /* Compute default column sizes. */
473 for (i = 0; i < cfile.cinfo.num_cols; i++) {
474 col_width = recent_get_column_width(i);
475 if (col_width == -1) {
476 layout = gtk_widget_create_pango_layout(packet_list, get_column_width_string(get_column_format(i), i));
477 pango_layout_get_pixel_size(layout, &col_width, NULL);
478 g_object_unref(G_OBJECT(layout));
480 gtk_clist_set_column_width(GTK_CLIST(packet_list), i, col_width);
485 packet_list_new(e_prefs *prefs)
487 GtkWidget *pkt_scrollw;
488 header_field_info *hfi;
489 gboolean custom_right_justify;
493 pkt_scrollw = scrolled_window_new(NULL, NULL);
494 /* The usual policy for scrolled windows is to set both scrollbars to automatic,
495 * meaning they'll only appear if the content doesn't fit into the window.
497 * As this doesn't seem to work in some cases for the vertical scrollbar
498 * (see http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=220),
499 * we show that scrollbar always. */
500 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pkt_scrollw),
501 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
502 /* the gtk_clist will have it's own GTK_SHADOW_IN, so don't use a shadow
503 * for both widgets */
504 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pkt_scrollw),
507 packet_list = gtk_clist_new(cfile.cinfo.num_cols);
508 /* Column titles are filled in below */
509 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
511 packet_list_set_sel_browse(prefs->gui_plist_sel_browse, FALSE);
512 packet_list_set_font(user_font_get_regular());
513 gtk_widget_set_name(packet_list, "packet list");
514 g_signal_connect(packet_list, "select-row", G_CALLBACK(packet_list_select_cb), NULL);
515 g_signal_connect(packet_list, "unselect-row", G_CALLBACK(packet_list_unselect_cb), NULL);
516 for (i = 0; i < cfile.cinfo.num_cols; i++) {
517 /* For performance reasons, columns do not automatically resize,
518 but are resizeable by the user. */
519 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, FALSE);
520 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
522 custom_right_justify = FALSE;
523 if (cfile.cinfo.col_fmt[i] == COL_CUSTOM) {
524 hfi = proto_registrar_get_byname(cfile.cinfo.col_custom_field[i]);
525 if ((hfi != NULL) && (hfi->strings == NULL) &&
526 ((hfi->type == FT_BOOLEAN) || (hfi->type == FT_FRAMENUM) ||
527 (((hfi->display == BASE_DEC) || (hfi->display == BASE_OCT)) &&
528 (IS_FT_INT(hfi->type) || IS_FT_UINT(hfi->type) ||
529 (hfi->type == FT_INT64) || (hfi->type == FT_UINT64))))) {
530 custom_right_justify = TRUE;
534 /* Right-justify some special columns. */
535 if (cfile.cinfo.col_fmt[i] == COL_NUMBER ||
536 cfile.cinfo.col_fmt[i] == COL_PACKET_LENGTH ||
537 cfile.cinfo.col_fmt[i] == COL_CUMULATIVE_BYTES ||
538 cfile.cinfo.col_fmt[i] == COL_DCE_CALL ||
539 cfile.cinfo.col_fmt[i] == COL_DCE_CTX ||
540 custom_right_justify)
541 gtk_clist_set_column_justification(GTK_CLIST(packet_list), i,
544 g_signal_connect(packet_list, "button_press_event", G_CALLBACK(popup_menu_handler),
545 g_object_get_data(G_OBJECT(popup_menu_object), PM_PACKET_LIST_KEY));
546 g_signal_connect(packet_list, "button_press_event",
547 G_CALLBACK(packet_list_button_pressed_cb), NULL);
548 g_object_set_data(G_OBJECT(popup_menu_object), E_MPACKET_LIST_KEY, packet_list);
549 gtk_clist_set_compare_func(GTK_CLIST(packet_list), packet_list_compare);
550 gtk_widget_show(packet_list);
556 packet_list_recreate(void)
558 gtk_widget_destroy(pkt_scrollw);
560 prefs.num_cols = g_list_length(prefs.col_list);
562 build_column_format_array(&cfile.cinfo, FALSE);
564 pkt_scrollw = packet_list_new(&prefs);
565 gtk_widget_show(pkt_scrollw);
566 packet_list_set_column_titles();
567 packet_list_set_sel_browse(prefs.gui_plist_sel_browse, TRUE);
569 main_widgets_rearrange();
571 if(cfile.state != FILE_CLOSED)
576 packet_list_set_column_titles(void)
579 GdkPixmap *ascend_pm, *descend_pm;
580 GdkBitmap *ascend_bm, *descend_bm;
581 column_arrows *col_arrows;
583 GtkWidget *column_lb;
585 win_style = gtk_widget_get_style(top_level);
586 ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
587 &win_style->bg[GTK_STATE_NORMAL],
588 (gchar **) clist_ascend_xpm);
589 descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
590 &win_style->bg[GTK_STATE_NORMAL],
591 (gchar **) clist_descend_xpm);
593 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) *
594 cfile.cinfo.num_cols);
595 for (i = 0; i < cfile.cinfo.num_cols; i++) {
596 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
597 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
598 column_lb = gtk_label_new(cfile.cinfo.col_title[i]);
599 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2,
600 GTK_SHRINK, GTK_SHRINK, 0, 0);
601 gtk_widget_show(column_lb);
602 col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
603 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
604 col_arrows[i].ascend_pm,
605 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
607 gtk_widget_show(col_arrows[i].ascend_pm);
609 col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
610 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
611 col_arrows[i].descend_pm,
612 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
613 gtk_clist_set_column_widget(GTK_CLIST(packet_list), i,
614 col_arrows[i].table);
615 gtk_widget_show(col_arrows[i].table);
617 gtk_clist_column_titles_show(GTK_CLIST(packet_list));
618 g_signal_connect(packet_list, "click-column", G_CALLBACK(packet_list_click_column_cb), col_arrows);
619 g_signal_connect(packet_list, "resize-column", G_CALLBACK(packet_list_resize_column_cb), NULL);
623 packet_list_clear(void)
625 packet_history_clear();
627 gtk_clist_clear(GTK_CLIST(packet_list));
628 gtk_widget_queue_draw(packet_list);
632 packet_list_freeze(void)
634 gtk_clist_freeze(GTK_CLIST(packet_list));
638 packet_list_resize_columns(void)
641 int progbar_nextstep;
643 gboolean progbar_stop_flag;
644 GTimeVal progbar_start_time;
646 progdlg_t *progbar = NULL;
647 gchar status_str[100];
649 /* Update the progress bar when it gets to this value. */
650 progbar_nextstep = 0;
651 /* When we reach the value that triggers a progress bar update,
652 bump that value by this amount. */
653 progbar_quantum = cfile.cinfo.num_cols/N_PROGBAR_UPDATES;
654 /* Progress so far. */
657 progbar_stop_flag = FALSE;
658 g_get_current_time(&progbar_start_time);
661 main_window_update();
663 for (i = 0; i < cfile.cinfo.num_cols; i++) {
664 /* Create the progress bar if necessary.
665 We check on every iteration of the loop, so that it takes no
666 longer than the standard time to create it (otherwise, for a
667 large file, we might take considerably longer than that standard
668 time in order to get to the next progress bar step). */
670 progbar = delayed_create_progress_dlg("Resizing", "Resize Columns",
671 TRUE, &progbar_stop_flag, &progbar_start_time, progbar_val);
673 if (i >= progbar_nextstep) {
674 /* let's not divide by zero. I should never be started
675 * with count == 0, so let's assert that
677 g_assert(cfile.cinfo.num_cols > 0);
679 progbar_val = (gfloat) i / cfile.cinfo.num_cols;
681 if (progbar != NULL) {
682 g_snprintf(status_str, sizeof(status_str),
683 "%u of %u columns (%s)", i+1, cfile.cinfo.num_cols, cfile.cinfo.col_title[i]);
684 update_progress_dlg(progbar, progbar_val, status_str);
687 progbar_nextstep += progbar_quantum;
690 if (progbar_stop_flag) {
691 /* Well, the user decided to abort the resizing... */
695 /* auto resize the current column */
696 gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
698 /* the current column should be resizeable by the user again */
699 /* (will turn off auto resize again) */
700 gtk_clist_set_column_resizeable(GTK_CLIST(packet_list), i, TRUE);
703 /* We're done resizing the columns; destroy the progress bar if it
706 destroy_progress_dlg(progbar);
709 void packet_list_resize_columns_cb(GtkWidget *widget _U_, gpointer data _U_)
711 packet_list_resize_columns();
715 packet_list_thaw(void)
717 gtk_clist_thaw(GTK_CLIST(packet_list));
718 packets_bar_update();
719 /*packet_list_resize_columns();*/
723 packet_list_select_row(gint row)
725 g_signal_emit_by_name(G_OBJECT(packet_list), "select_row", row);
729 packet_list_next_prev(gboolean next)
731 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(top_level));
732 g_signal_emit_by_name(G_OBJECT(packet_list), "scroll_vertical",
733 next ? GTK_SCROLL_STEP_FORWARD : GTK_SCROLL_STEP_BACKWARD, 0.0);
734 /* Set the focus back where it was */
736 gtk_window_set_focus(GTK_WINDOW(top_level), focus);
740 packet_list_next(void)
742 packet_list_next_prev(TRUE);
746 packet_list_prev(void)
748 packet_list_next_prev(FALSE);
752 packet_list_moveto_end(void)
754 gtk_clist_moveto(GTK_CLIST(packet_list),
755 GTK_CLIST(packet_list)->rows - 1, -1, 1.0f, 1.0f);
759 packet_list_check_end(void)
761 gboolean at_end = FALSE;
764 g_return_val_if_fail (packet_list != NULL, FALSE);
765 adj = gtk_clist_get_vadjustment(GTK_CLIST(packet_list));
766 g_return_val_if_fail (adj != NULL, FALSE);
768 if (adj->value >= adj->upper - adj->page_size) {
772 if (adj->value > 0 && at_end != last_at_end && at_end != auto_scroll_live) {
773 menu_auto_scroll_live_changed(at_end);
776 last_at_end = at_end;
781 packet_list_append(const gchar *text[], gpointer data)
785 row = gtk_clist_append(GTK_CLIST(packet_list), (gchar **) text);
786 gtk_clist_set_row_data(GTK_CLIST(packet_list), row, data);
791 packet_list_set_colors(gint row, color_t *fg, color_t *bg)
793 GdkColor gdkfg, gdkbg;
797 color_t_to_gdkcolor(&gdkfg, fg);
798 gtk_clist_set_foreground(GTK_CLIST(packet_list), row, &gdkfg);
802 color_t_to_gdkcolor(&gdkbg, bg);
803 gtk_clist_set_background(GTK_CLIST(packet_list), row, &gdkbg);
808 packet_list_find_row_from_data(gpointer data)
810 return gtk_clist_find_row_from_data(GTK_CLIST(packet_list), data);
814 packet_list_set_text(gint row, gint column, const gchar *text)
816 gtk_clist_set_text(GTK_CLIST(packet_list), row, column, text);
819 /* Set the column widths of those columns that show the time in
820 * "command-line-specified" format. */
822 packet_list_set_time_width(gint col_fmt, gint column)
827 width = recent_get_column_width(column);
829 layout = gtk_widget_create_pango_layout(packet_list,
830 get_column_longest_string(col_fmt));
831 pango_layout_get_pixel_size(layout, &width, NULL);
832 g_object_unref(G_OBJECT(layout));
834 gtk_clist_set_column_width(GTK_CLIST(packet_list), column, width);
838 packet_list_get_row_data(gint row)
840 return gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
844 /* get the first fully visible row number, given row MUST be visible */
846 packet_list_first_full_visible_row(gint row)
848 g_assert(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL);
850 while(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL) {
857 /* get the last fully visible row number, given row MUST be visible */
859 packet_list_last_full_visible_row(gint row)
861 g_assert(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL);
863 while(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL) {
870 /* Set the selected row and the focus row of the packet list to the specified
871 * row, and make it visible if it's not currently visible. */
873 packet_list_set_selected_row(gint row)
877 gboolean full_visible;
879 full_visible = gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) == GTK_VISIBILITY_FULL;
881 /* XXX - why is there no "gtk_clist_set_focus_row()", so that we
882 * can make the row for the frame we found the focus row?
884 * See http://www.gnome.org/mailing-lists/archives/gtk-list/2000-January/0038.shtml
886 GTK_CLIST(packet_list)->focus_row = row;
888 gtk_clist_select_row(GTK_CLIST(packet_list), row, -1);
891 gtk_clist_freeze(GTK_CLIST(packet_list));
893 gtk_clist_moveto(GTK_CLIST(packet_list), row, -1, 0.0f, 0.0f);
895 /* even after move still invisible (happens with empty list) -> give up */
896 if(gtk_clist_row_is_visible(GTK_CLIST(packet_list), row) != GTK_VISIBILITY_FULL) {
897 gtk_clist_thaw(GTK_CLIST(packet_list));
901 /* The now selected row will be the first visible row in the list.
902 * This is inconvenient, as the user is usually interested in some
903 * packets *before* the currently selected one too.
905 * Try to adjust the visible rows, so the currently selected row will
906 * be shown around the first third of the list screen.
908 * (This won't even do any harm if the current row is the first or the
909 * last in the list) */
910 visible_rows = packet_list_last_full_visible_row(row) - packet_list_first_full_visible_row(row);
911 first_row = row - visible_rows / 3;
913 gtk_clist_moveto(GTK_CLIST(packet_list), first_row >= 0 ? first_row : 0, -1, 0.0f, 0.0f);
915 gtk_clist_thaw(GTK_CLIST(packet_list));
919 /* Return the column number that the clist is currently sorted by */
921 packet_list_get_sort_column(void)
923 return GTK_CLIST(packet_list)->sort_column;
926 void packet_list_copy_summary_cb(GtkWidget * w _U_, gpointer data _U_, copy_summary_type copy_type)
929 gchar* celltext = NULL;
932 if(CS_CSV == copy_type) {
933 text = g_string_new("\"");
935 text = g_string_new("");
938 if (cfile.current_frame) {
939 for(col = 0; col < cfile.cinfo.num_cols; ++col) {
941 if(CS_CSV == copy_type) {
942 g_string_append(text,"\",\"");
944 g_string_append_c(text, '\t');
947 if(0 != gtk_clist_get_text(GTK_CLIST(packet_list),cfile.current_row,col,&celltext)) {
948 g_string_append(text,celltext);
951 if(CS_CSV == copy_type) {
952 g_string_append_c(text,'"');
954 copy_to_clipboard(text);
956 g_string_free(text,TRUE);
959 /* Re-sort the clist by the previously selected sort */
961 packet_list_set_sort_column(void)
963 packet_list_freeze();
965 gtk_clist_set_sort_column(GTK_CLIST(packet_list), packet_list_get_sort_column());
967 gtk_clist_sort(GTK_CLIST(packet_list));
973 packet_list_recent_write_all(FILE *rf)
977 fprintf (rf, "%s:", RECENT_KEY_COL_WIDTH);
978 for (col = 0; col < cfile.cinfo.num_cols; col++) {
979 if (cfile.cinfo.col_fmt[col] == COL_CUSTOM) {
980 fprintf (rf, " %%Cus:%s,", get_column_custom_field(col));
982 fprintf (rf, " %s,", col_format_to_string(cfile.cinfo.col_fmt[col]));
984 fprintf (rf, " %d", GTK_CLIST(packet_list)->column[col].width);
985 if (col != cfile.cinfo.num_cols-1) {