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.
33 #include "gtkglobals.h"
34 #include "epan/epan.h"
36 #include "color_filters.h"
37 #include "../ui_util.h"
38 #include "gui_utils.h"
42 #include <epan/column.h>
43 #include "epan/column_info.h"
44 #include "compat_macros.h"
45 #include <epan/prefs.h>
46 #include "capture_file_dlg.h"
47 #include "packet_list.h"
49 #include "font_utils.h"
50 #include "packet_history.h"
52 #include <epan/timestamp.h>
54 #include "image/clist_ascend.xpm"
55 #include "image/clist_descend.xpm"
57 #include "progress_dlg.h"
59 #define N_PROGBAR_UPDATES 100
64 * This lets us use GtkCList in GTK+ 1.3[.x] and later, and EthCList on
65 * GTK+ 1.2[.x], at least until we either use GTK+ 2.x's native widgets
66 * or make EthCList work on 1.3[.x] and 2.x.
68 #if GTK_MAJOR_VERSION >= 2 || GTK_MINOR_VERSION >= 3
69 #define EthCList GtkCList
70 #define EthCListRow GtkCListRow
71 #define eth_clist_append gtk_clist_append
72 #define eth_clist_clear gtk_clist_clear
73 #define eth_clist_column_titles_show gtk_clist_column_titles_show
74 #define eth_clist_find_row_from_data gtk_clist_find_row_from_data
75 #define eth_clist_freeze gtk_clist_freeze
76 #define eth_clist_get_row_data gtk_clist_get_row_data
77 #define eth_clist_get_selection_info gtk_clist_get_selection_info
78 #define eth_clist_moveto gtk_clist_moveto
79 #define eth_clist_new gtk_clist_new
80 #define eth_clist_row_is_visible gtk_clist_row_is_visible
81 #define eth_clist_select_row gtk_clist_select_row
82 #define eth_clist_set_background gtk_clist_set_background
83 #define eth_clist_set_column_auto_resize gtk_clist_set_column_auto_resize
84 #define eth_clist_set_column_justification gtk_clist_set_column_justification
85 #define eth_clist_set_column_resizeable gtk_clist_set_column_resizeable
86 #define eth_clist_set_column_width gtk_clist_set_column_width
87 #define eth_clist_set_column_widget gtk_clist_set_column_widget
88 #define eth_clist_set_compare_func gtk_clist_set_compare_func
89 #define eth_clist_set_foreground gtk_clist_set_foreground
90 #define eth_clist_set_row_data gtk_clist_set_row_data
91 #define eth_clist_set_selection_mode gtk_clist_set_selection_mode
92 #define eth_clist_set_sort_column gtk_clist_set_sort_column
93 #define eth_clist_set_text gtk_clist_set_text
94 #define eth_clist_sort gtk_clist_sort
95 #define eth_clist_thaw gtk_clist_thaw
96 #define ETH_CLIST GTK_CLIST
101 typedef struct column_arrows {
103 GtkWidget *ascend_pm;
104 GtkWidget *descend_pm;
107 GtkWidget *packet_list;
109 /* EthClist compare routine, overrides default to allow numeric comparison */
111 #define COMPARE_FRAME_NUM() ((fdata1->num < fdata2->num) ? -1 : \
112 (fdata1->num > fdata2->num) ? 1 : \
115 #define COMPARE_NUM(f) ((fdata1->f < fdata2->f) ? -1 : \
116 (fdata1->f > fdata2->f) ? 1 : \
119 /* Compare time stamps.
120 A packet whose time is a reference time is considered to have
121 a lower time stamp than any frame with a non-reference time;
122 if both packets' times are reference times, we compare the
123 times of the packets. */
124 #define COMPARE_TS(ts) \
125 ((fdata1->flags.ref_time && !fdata2->flags.ref_time) ? -1 : \
126 (!fdata1->flags.ref_time && fdata2->flags.ref_time) ? 1 : \
127 (fdata1->ts.secs < fdata2->ts.secs) ? -1 : \
128 (fdata1->ts.secs > fdata2->ts.secs) ? 1 : \
129 (fdata1->ts.nsecs < fdata2->ts.nsecs) ? -1 :\
130 (fdata1->ts.nsecs > fdata2->ts.nsecs) ? 1 : \
133 packet_list_compare(EthCList *clist, gconstpointer ptr1, gconstpointer ptr2)
135 /* Get row data structures */
136 const EthCListRow *row1 = (const EthCListRow *)ptr1;
137 const EthCListRow *row2 = (const EthCListRow *)ptr2;
139 /* Get the frame data structures for the rows */
140 const frame_data *fdata1 = row1->data;
141 const frame_data *fdata2 = row2->data;
143 /* Get row text strings */
144 const char *text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
145 const char *text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
147 /* Attempt to convert to numbers */
153 gint col_fmt = cfile.cinfo.col_fmt[clist->sort_column];
158 return COMPARE_FRAME_NUM();
161 switch (timestamp_get_type()) {
164 case TS_ABSOLUTE_WITH_DATE:
165 return COMPARE_TS(abs_ts);
168 return COMPARE_TS(rel_ts);
171 return COMPARE_TS(del_ts);
179 case COL_ABS_DATE_TIME:
180 return COMPARE_TS(abs_ts);
183 return COMPARE_TS(rel_ts);
186 return COMPARE_TS(del_ts);
188 case COL_PACKET_LENGTH:
189 return COMPARE_NUM(pkt_len);
191 case COL_CUMULATIVE_BYTES:
192 return COMPARE_NUM(cum_bytes);
197 if ((col_fmt == COL_UNRES_SRC_PORT) || (col_fmt == COL_UNRES_DST_PORT) ||
198 ((num1 != 0) && (num2 != 0) && ((col_fmt == COL_DEF_SRC_PORT) || (col_fmt == COL_RES_SRC_PORT) ||
199 (col_fmt == COL_DEF_DST_PORT) || (col_fmt == COL_RES_DST_PORT)))) {
201 /* Compare numeric column */
205 else if (num1 > num2)
208 return COMPARE_FRAME_NUM();
213 /* Compare text column */
218 return COMPARE_FRAME_NUM();
224 ret = strcmp(text1, text2);
226 return COMPARE_FRAME_NUM();
233 /* What to do when a column is clicked */
235 packet_list_click_column_cb(EthCList *clist, gint column, gpointer data)
237 column_arrows *col_arrows = (column_arrows *) data;
240 eth_clist_freeze(clist);
242 for (i = 0; i < cfile.cinfo.num_cols; i++) {
243 gtk_widget_hide(col_arrows[i].ascend_pm);
244 gtk_widget_hide(col_arrows[i].descend_pm);
247 if (column == clist->sort_column) {
248 if (clist->sort_type == GTK_SORT_ASCENDING) {
249 clist->sort_type = GTK_SORT_DESCENDING;
250 gtk_widget_show(col_arrows[column].descend_pm);
252 clist->sort_type = GTK_SORT_ASCENDING;
253 gtk_widget_show(col_arrows[column].ascend_pm);
257 clist->sort_type = GTK_SORT_ASCENDING;
258 gtk_widget_show(col_arrows[column].ascend_pm);
259 eth_clist_set_sort_column(clist, column);
261 eth_clist_thaw(clist);
263 eth_clist_sort(clist);
266 /* What to do when a list item is selected/unselected */
268 packet_list_select_cb(GtkWidget *w _U_, gint row, gint col _U_, gpointer evt _U_) {
270 /* Remove the hex display tabbed pages */
271 while( (gtk_notebook_get_nth_page( GTK_NOTEBOOK(byte_nb_ptr), 0)))
272 gtk_notebook_remove_page( GTK_NOTEBOOK(byte_nb_ptr), 0);
274 cf_select_packet(&cfile, row);
275 gtk_widget_grab_focus(packet_list);
276 packet_history_add(row);
280 packet_list_unselect_cb(GtkWidget *w _U_, gint row _U_, gint col _U_, gpointer evt _U_) {
282 cf_unselect_packet(&cfile);
287 set_frame_mark(gboolean set, frame_data *frame, gint row) {
293 cf_mark_frame(&cfile, frame);
294 color_t_to_gdkcolor(&fg, &prefs.gui_marked_fg);
295 color_t_to_gdkcolor(&bg, &prefs.gui_marked_bg);
296 eth_clist_set_foreground(ETH_CLIST(packet_list), row, &fg);
297 eth_clist_set_background(ETH_CLIST(packet_list), row, &bg);
299 color_filter_t *cfilter = frame->color_filter;
301 cf_unmark_frame(&cfile, frame);
302 /* Restore the color from the matching color filter if any */
303 if (cfilter) { /* The packet matches a color filter */
304 color_t_to_gdkcolor(&fg, &cfilter->fg_color);
305 color_t_to_gdkcolor(&bg, &cfilter->bg_color);
306 eth_clist_set_foreground(ETH_CLIST(packet_list), row, &fg);
307 eth_clist_set_background(ETH_CLIST(packet_list), row, &bg);
308 } else { /* No color filter match */
309 eth_clist_set_foreground(ETH_CLIST(packet_list), row, NULL);
310 eth_clist_set_background(ETH_CLIST(packet_list), row, NULL);
315 /* call this after last set_frame_mark is done */
316 static void mark_frames_ready(void) {
317 file_save_update_dynamics();
318 packets_bar_update();
321 void packet_list_mark_frame_cb(GtkWidget *w _U_, gpointer data _U_) {
322 if (cfile.current_frame) {
323 /* XXX hum, should better have a "cfile->current_row" here ... */
324 set_frame_mark(!cfile.current_frame->flags.marked,
326 eth_clist_find_row_from_data(ETH_CLIST(packet_list),
327 cfile.current_frame));
332 static void mark_all_frames(gboolean set) {
335 /* XXX: we might need a progressbar here */
336 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
339 eth_clist_find_row_from_data(ETH_CLIST(packet_list), fdata));
344 void packet_list_update_marked_frames(void) {
347 if (cfile.plist == NULL) return;
349 /* XXX: we might need a progressbar here */
350 for (fdata = cfile.plist; fdata != NULL; fdata = fdata->next) {
351 if (fdata->flags.marked)
354 eth_clist_find_row_from_data(ETH_CLIST(packet_list),
360 void packet_list_mark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
361 mark_all_frames(TRUE);
364 void packet_list_unmark_all_frames_cb(GtkWidget *w _U_, gpointer data _U_) {
365 mark_all_frames(FALSE);
369 packet_list_get_event_row_column(GtkWidget *w, GdkEventButton *event_button,
370 gint *row, gint *column)
372 return eth_clist_get_selection_info(ETH_CLIST(w),
373 (gint) event_button->x, (gint) event_button->y,
377 #if GTK_MAJOR_VERSION < 2
379 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
381 GdkEventButton *event_button = (GdkEventButton *)event;
384 if (w == NULL || event == NULL)
387 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
388 event_button->window == ETH_CLIST(w)->clist_window &&
389 packet_list_get_event_row_column(w, event_button, &row, &column)) {
390 frame_data *fdata = (frame_data *) eth_clist_get_row_data(ETH_CLIST(w),
392 set_frame_mark(!fdata->flags.marked, fdata, row);
398 packet_list_button_pressed_cb(GtkWidget *w, GdkEvent *event, gpointer data _U_)
400 GdkEventButton *event_button = (GdkEventButton *)event;
403 if (w == NULL || event == NULL)
406 if (event->type == GDK_BUTTON_PRESS && event_button->button == 2 &&
407 event_button->window == ETH_CLIST(w)->clist_window &&
408 eth_clist_get_selection_info(ETH_CLIST(w), (gint) event_button->x,
409 (gint) event_button->y, &row, &column)) {
410 frame_data *fdata = (frame_data *)eth_clist_get_row_data(ETH_CLIST(w),
412 set_frame_mark(!fdata->flags.marked, fdata, row);
420 /* Set the selection mode of the packet list window. */
422 packet_list_set_sel_browse(gboolean val)
424 GtkSelectionMode new_mode;
425 /* initialize with a mode we don't use, so that the mode == new_mode
426 * test will fail the first time */
427 static GtkSelectionMode mode = GTK_SELECTION_MULTIPLE;
429 /* Yeah, GTK uses "browse" in the case where we do not, but oh well. I
430 * think "browse" in Wireshark makes more sense than "SINGLE" in GTK+ */
431 new_mode = val ? GTK_SELECTION_SINGLE : GTK_SELECTION_BROWSE;
433 if (mode == new_mode) {
435 * The mode isn't changing, so don't do anything.
436 * In particular, don't gratuitiously unselect the
439 * XXX - why do we have to unselect the current packet
440 * ourselves? The documentation for the GtkCList at
442 * http://developer.gnome.org/doc/API/gtk/gtkclist.html
444 * says "Note that setting the widget's selection mode to
445 * one of GTK_SELECTION_BROWSE or GTK_SELECTION_SINGLE will
446 * cause all the items in the GtkCList to become deselected."
451 if (cfile.finfo_selected)
452 cf_unselect_packet(&cfile);
455 eth_clist_set_selection_mode(ETH_CLIST(packet_list), mode);
458 /* Set the font of the packet list window. */
460 packet_list_set_font(FONT_TYPE *font)
464 #if GTK_MAJOR_VERSION < 2
467 style = gtk_style_new();
468 gdk_font_unref(style->font);
472 gtk_widget_set_style(packet_list, style);
476 gtk_widget_modify_font(packet_list, font);
479 /* Compute default column sizes. */
480 for (i = 0; i < cfile.cinfo.num_cols; i++) {
481 #if GTK_MAJOR_VERSION < 2
482 col_width = gdk_string_width(font,
483 get_column_longest_string(get_column_format(i)));
485 layout = gtk_widget_create_pango_layout(packet_list,
486 get_column_longest_string(get_column_format(i)));
487 pango_layout_get_pixel_size(layout, &col_width, NULL);
488 g_object_unref(G_OBJECT(layout));
490 eth_clist_set_column_width(ETH_CLIST(packet_list), i,
496 packet_list_new(e_prefs *prefs)
498 GtkWidget *pkt_scrollw;
502 pkt_scrollw = scrolled_window_new(NULL, NULL);
503 /* The usual policy for scrolled windows is to set both scrollbars to automatic,
504 * meaning they'll only appear if the content doesn't fit into the window.
506 * As this doesn't seem to work in some cases for the vertical scrollbar
507 * (see http://bugs.wireshark.org/bugzilla/show_bug.cgi?id=220),
508 * we show that scrollbar always. */
509 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(pkt_scrollw),
510 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
511 #if GTK_MAJOR_VERSION >= 2
512 /* the eth_clist will have it's own GTK_SHADOW_IN, so don't use a shadow
513 * for both widgets */
514 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(pkt_scrollw),
518 packet_list = eth_clist_new(cfile.cinfo.num_cols);
519 /* Column titles are filled in below */
520 gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
522 packet_list_set_sel_browse(prefs->gui_plist_sel_browse);
523 packet_list_set_font(user_font_get_regular());
524 gtk_widget_set_name(packet_list, "packet list");
525 SIGNAL_CONNECT(packet_list, "select-row", packet_list_select_cb, NULL);
526 SIGNAL_CONNECT(packet_list, "unselect-row", packet_list_unselect_cb, NULL);
527 for (i = 0; i < cfile.cinfo.num_cols; i++) {
528 /* For performance reasons, columns do not automatically resize,
529 but are resizeable by the user. */
530 eth_clist_set_column_auto_resize(ETH_CLIST(packet_list), i, FALSE);
531 eth_clist_set_column_resizeable(ETH_CLIST(packet_list), i, TRUE);
533 /* Right-justify some special columns. */
534 if (cfile.cinfo.col_fmt[i] == COL_NUMBER ||
535 cfile.cinfo.col_fmt[i] == COL_PACKET_LENGTH ||
536 cfile.cinfo.col_fmt[i] == COL_CUMULATIVE_BYTES ||
537 cfile.cinfo.col_fmt[i] == COL_DCE_CALL ||
538 cfile.cinfo.col_fmt[i] == COL_DCE_CTX)
539 eth_clist_set_column_justification(ETH_CLIST(packet_list), i,
542 SIGNAL_CONNECT(packet_list, "button_press_event", popup_menu_handler,
543 OBJECT_GET_DATA(popup_menu_object, PM_PACKET_LIST_KEY));
544 SIGNAL_CONNECT(packet_list, "button_press_event",
545 packet_list_button_pressed_cb, NULL);
546 eth_clist_set_compare_func(ETH_CLIST(packet_list), packet_list_compare);
547 gtk_widget_show(packet_list);
553 packet_list_set_column_titles(void)
556 GdkPixmap *ascend_pm, *descend_pm;
557 GdkBitmap *ascend_bm, *descend_bm;
558 column_arrows *col_arrows;
560 GtkWidget *column_lb;
562 win_style = gtk_widget_get_style(top_level);
563 ascend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &ascend_bm,
564 &win_style->bg[GTK_STATE_NORMAL],
565 (gchar **) clist_ascend_xpm);
566 descend_pm = gdk_pixmap_create_from_xpm_d(top_level->window, &descend_bm,
567 &win_style->bg[GTK_STATE_NORMAL],
568 (gchar **) clist_descend_xpm);
570 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) *
571 cfile.cinfo.num_cols);
572 for (i = 0; i < cfile.cinfo.num_cols; i++) {
573 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
574 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
575 column_lb = gtk_label_new(cfile.cinfo.col_title[i]);
576 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2,
577 GTK_SHRINK, GTK_SHRINK, 0, 0);
578 gtk_widget_show(column_lb);
579 col_arrows[i].ascend_pm = gtk_pixmap_new(ascend_pm, ascend_bm);
580 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
581 col_arrows[i].ascend_pm,
582 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
584 gtk_widget_show(col_arrows[i].ascend_pm);
586 col_arrows[i].descend_pm = gtk_pixmap_new(descend_pm, descend_bm);
587 gtk_table_attach(GTK_TABLE(col_arrows[i].table),
588 col_arrows[i].descend_pm,
589 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
590 eth_clist_set_column_widget(ETH_CLIST(packet_list), i,
591 col_arrows[i].table);
592 gtk_widget_show(col_arrows[i].table);
594 eth_clist_column_titles_show(ETH_CLIST(packet_list));
595 SIGNAL_CONNECT(packet_list, "click-column", packet_list_click_column_cb,
600 packet_list_clear(void)
602 packet_history_clear();
604 eth_clist_clear(ETH_CLIST(packet_list));
608 packet_list_freeze(void)
610 eth_clist_freeze(ETH_CLIST(packet_list));
614 packet_list_resize_columns(void) {
616 int progbar_nextstep;
618 gboolean progbar_stop_flag;
619 GTimeVal progbar_start_time;
621 progdlg_t *progbar = NULL;
622 gchar status_str[100];
624 /* Update the progress bar when it gets to this value. */
625 progbar_nextstep = 0;
626 /* When we reach the value that triggers a progress bar update,
627 bump that value by this amount. */
628 progbar_quantum = cfile.cinfo.num_cols/N_PROGBAR_UPDATES;
629 /* Progress so far. */
632 progbar_stop_flag = FALSE;
633 g_get_current_time(&progbar_start_time);
636 main_window_update();
638 for (i = 0; i < cfile.cinfo.num_cols; i++) {
639 /* Create the progress bar if necessary.
640 We check on every iteration of the loop, so that it takes no
641 longer than the standard time to create it (otherwise, for a
642 large file, we might take considerably longer than that standard
643 time in order to get to the next progress bar step). */
645 progbar = delayed_create_progress_dlg("Resizing", "Resize Columns",
646 TRUE, &progbar_stop_flag, &progbar_start_time, progbar_val);
648 if (i >= progbar_nextstep) {
649 /* let's not divide by zero. I should never be started
650 * with count == 0, so let's assert that
652 g_assert(cfile.cinfo.num_cols > 0);
654 progbar_val = (gfloat) i / cfile.cinfo.num_cols;
656 if (progbar != NULL) {
657 g_snprintf(status_str, sizeof(status_str),
658 "%u of %u columns (%s)", i+1, cfile.cinfo.num_cols, cfile.cinfo.col_title[i]);
659 update_progress_dlg(progbar, progbar_val, status_str);
662 progbar_nextstep += progbar_quantum;
665 if (progbar_stop_flag) {
666 /* Well, the user decided to abort the resizing... */
670 /* auto resize the current column */
671 eth_clist_set_column_auto_resize(ETH_CLIST(packet_list), i, TRUE);
673 /* the current column should be resizeable by the user again */
674 /* (will turn off auto resize again) */
675 eth_clist_set_column_resizeable(ETH_CLIST(packet_list), i, TRUE);
678 /* We're done resizing the columns; destroy the progress bar if it
681 destroy_progress_dlg(progbar);
684 void packet_list_resize_columns_cb(GtkWidget *widget _U_, gpointer data _U_)
686 packet_list_resize_columns();
690 packet_list_thaw(void)
692 eth_clist_thaw(ETH_CLIST(packet_list));
693 packets_bar_update();
694 /*packet_list_resize_columns();*/
698 packet_list_select_row(gint row)
700 SIGNAL_EMIT_BY_NAME(packet_list, "select_row", row);
704 packet_list_next_prev(gboolean next)
706 #if GTK_MAJOR_VERSION >= 2
707 GtkWidget *focus = gtk_window_get_focus(GTK_WINDOW(top_level));
709 SIGNAL_EMIT_BY_NAME(packet_list, "scroll_vertical",
710 next ? GTK_SCROLL_STEP_FORWARD : GTK_SCROLL_STEP_BACKWARD, 0.0);
711 #if GTK_MAJOR_VERSION >= 2
712 /* Set the focus back where it was */
714 gtk_window_set_focus(GTK_WINDOW(top_level), focus);
721 packet_list_next_prev(TRUE);
727 packet_list_next_prev(FALSE);
731 packet_list_moveto_end(void)
733 eth_clist_moveto(ETH_CLIST(packet_list),
734 ETH_CLIST(packet_list)->rows - 1, -1, 1.0, 1.0);
738 packet_list_append(const gchar *text[], gpointer data)
742 row = eth_clist_append(ETH_CLIST(packet_list), (gchar **) text);
743 eth_clist_set_row_data(ETH_CLIST(packet_list), row, data);
748 packet_list_set_colors(gint row, color_t *fg, color_t *bg)
750 GdkColor gdkfg, gdkbg;
754 color_t_to_gdkcolor(&gdkfg, fg);
755 eth_clist_set_foreground(ETH_CLIST(packet_list), row, &gdkfg);
759 color_t_to_gdkcolor(&gdkbg, bg);
760 eth_clist_set_background(ETH_CLIST(packet_list), row, &gdkbg);
765 packet_list_find_row_from_data(gpointer data)
767 return eth_clist_find_row_from_data(ETH_CLIST(packet_list), data);
771 packet_list_set_text(gint row, gint column, const gchar *text)
773 eth_clist_set_text(ETH_CLIST(packet_list), row, column, text);
776 /* Set the column widths of those columns that show the time in
777 * "command-line-specified" format. */
779 packet_list_set_cls_time_width(gint column)
782 #if GTK_MAJOR_VERSION < 2
785 pl_style = gtk_widget_get_style(packet_list);
786 width = gdk_string_width(pl_style->font,
787 get_column_longest_string(COL_CLS_TIME));
791 layout = gtk_widget_create_pango_layout(packet_list,
792 get_column_longest_string(COL_CLS_TIME));
793 pango_layout_get_pixel_size(layout, &width, NULL);
794 g_object_unref(G_OBJECT(layout));
796 eth_clist_set_column_width(ETH_CLIST(packet_list), column, width);
800 packet_list_get_row_data(gint row)
802 return eth_clist_get_row_data(ETH_CLIST(packet_list), row);
806 /* get the first fully visible row number, given row MUST be visible */
808 packet_list_first_full_visible_row(gint row) {
810 g_assert(eth_clist_row_is_visible(ETH_CLIST(packet_list), row) ==
811 GTK_VISIBILITY_FULL);
813 while(eth_clist_row_is_visible(ETH_CLIST(packet_list), row) ==
814 GTK_VISIBILITY_FULL) {
821 /* get the last fully visible row number, given row MUST be visible */
823 packet_list_last_full_visible_row(gint row) {
825 g_assert(eth_clist_row_is_visible(ETH_CLIST(packet_list), row) ==
826 GTK_VISIBILITY_FULL);
828 while(eth_clist_row_is_visible(ETH_CLIST(packet_list), row) ==
829 GTK_VISIBILITY_FULL) {
836 /* Set the selected row and the focus row of the packet list to the specified
837 * row, and make it visible if it's not currently visible. */
839 packet_list_set_selected_row(gint row)
843 gboolean full_visible;
846 full_visible = eth_clist_row_is_visible(ETH_CLIST(packet_list), row) ==
849 /* XXX - why is there no "eth_clist_set_focus_row()", so that we
850 * can make the row for the frame we found the focus row?
852 * See http://www.gnome.org/mailing-lists/archives/gtk-list/2000-January/0038.shtml
854 ETH_CLIST(packet_list)->focus_row = row;
856 eth_clist_select_row(ETH_CLIST(packet_list), row, -1);
860 eth_clist_freeze(ETH_CLIST(packet_list));
862 eth_clist_moveto(ETH_CLIST(packet_list), row, -1, 0.0, 0.0);
864 /* even after move still invisible (happens with empty list) -> give up */
865 if(eth_clist_row_is_visible(ETH_CLIST(packet_list), row) !=
866 GTK_VISIBILITY_FULL) {
867 eth_clist_thaw(ETH_CLIST(packet_list));
871 /* The now selected row will be the first visible row in the list.
872 * This is inconvenient, as the user is usually interested in some
873 * packets *before* the currently selected one too.
875 * Try to adjust the visible rows, so the currently selected row will
876 * be shown around the first third of the list screen.
878 * (This won't even do any harm if the current row is the first or the
879 * last in the list) */
880 visible_rows = packet_list_last_full_visible_row(row) - packet_list_first_full_visible_row(row);
881 first_row = row - visible_rows / 3;
883 eth_clist_moveto(ETH_CLIST(packet_list), first_row >= 0 ? first_row : 0, -1, 0.0, 0.0);
885 eth_clist_thaw(ETH_CLIST(packet_list));
889 /* Return the column number that the clist is currently sorted by */
891 packet_list_get_sort_column(void)
893 return ETH_CLIST(packet_list)->sort_column;