Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Ethereal-dev: Re: [Ethereal-dev] (possible) Packet Fence Patch for CVS

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Guy Harris <gharris@xxxxxxxxxxxx>
Date: Mon, 12 Mar 2001 23:09:39 -0800
On Mon, Mar 12, 2001 at 11:48:11AM -0800, Guy Harris wrote:
> It might also be fixed by changing the packet fence code to include
> "dfilter/dfilter.h", rather than just "dfilter.h", which is what the
> code in Ethereal does.
> 
> If that fixes it,

It does, but the correct fix is not to include it at all!  It, like many
of the other header files include by "packet_fence.c", doesn't need to
be included.

Here's a version of the packet fence patch, plus "packet_fence.h" and
"packet_fence.c", that

	1) is a patch against the current code in CVS, rather than an
	   old version of Ethereal;

	2) includes a *lot* fewer header files in "packet_fence.c" (only
	   the ones that are needed are included - and
	   "dfilter/dfilter.h" is not one that's needed...);

	3) calls "packet_fence_update_ruler()" after creating the ruler,
	   so that the upper and lower limits of the ruler's range are
	   set very early in its life - without that, Ethereal crashed
	   when started up, as both limits were zero when the ruler was
	   exposed, and, when trying to compute something that involved
	   dividing by the difference between those limits, it got a
	   zero divide fault);

	4) fixes up some errors in "gtkclist.c" (you can't use
	   "g_return_if_fail()" in a non-void function, you have to use
	   "gtk_return_val_if_fail()".

Martin, you should probably update your version of the packet fence code
with these versions, and update the patch.
Index: globals.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/globals.h,v
retrieving revision 1.23
diff -c -r1.23 globals.h
*** globals.h	2000/10/19 22:59:23	1.23
--- globals.h	2001/03/13 07:05:41
***************
*** 38,43 ****
--- 38,44 ----
  extern gchar       *ethereal_path;
  extern gchar       *last_open_dir;
  extern gboolean     auto_scroll_live;
+ extern gboolean     packet_fence_active;/* do we update the packet fence */
  extern field_info  *finfo_selected;
  
  extern ts_type timestamp_type;
Index: gtk/Makefile.am
===================================================================
RCS file: /usr/local/cvsroot/ethereal/gtk/Makefile.am,v
retrieving revision 1.33
diff -c -r1.33 Makefile.am
*** Makefile.am	2001/02/01 07:34:33	1.33
--- Makefile.am	2001/03/13 07:05:42
***************
*** 87,93 ****
  	stream_prefs.h	\
  	summary_dlg.c   \
  	summary_dlg.h   \
! 	ui_util.c
  
  EXTRA_DIST = \
  	Makefile.nmake
--- 87,95 ----
  	stream_prefs.h	\
  	summary_dlg.c   \
  	summary_dlg.h   \
! 	ui_util.c	\
! 	packet_fence.c	\
! 	packet_fence.h	
  
  EXTRA_DIST = \
  	Makefile.nmake
Index: gtk/Makefile.nmake
===================================================================
RCS file: /usr/local/cvsroot/ethereal/gtk/Makefile.nmake,v
retrieving revision 1.17
diff -c -r1.17 Makefile.nmake
*** Makefile.nmake	2001/02/01 07:34:33	1.17
--- Makefile.nmake	2001/03/13 07:05:42
***************
*** 43,49 ****
  	simple_dialog.obj \
  	stream_prefs.obj \
  	summary_dlg.obj \
! 	ui_util.obj
  
  
  libui.lib	: ..\config.h $(OBJECTS)
--- 43,50 ----
  	simple_dialog.obj \
  	stream_prefs.obj \
  	summary_dlg.obj \
! 	ui_util.obj \
! 	packet_fence.obj
  
  
  libui.lib	: ..\config.h $(OBJECTS)
Index: gtk/display_opts.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/gtk/display_opts.c,v
retrieving revision 1.18
diff -c -r1.18 display_opts.c
*** display_opts.c	2000/11/01 08:31:35	1.18
--- display_opts.c	2001/03/13 07:05:43
***************
*** 71,76 ****
--- 71,77 ----
  #define E_DISPLAY_TIME_DELTA_KEY "display_time_delta"
  #define E_DISPLAY_AUTO_SCROLL_KEY "display_auto_scroll"
  #define E_DISPLAY_NAME_RESOLUTION_KEY "display_name_resolution"
+ #define E_DISPLAY_PACKET_FENCE "display_packet_fence"
  
  static void display_opt_ok_cb(GtkWidget *, gpointer);
  static void display_opt_apply_cb(GtkWidget *, gpointer);
***************
*** 184,189 ****
--- 185,197 ----
    gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
    gtk_widget_show(button);
      
+   button = dlg_check_button_new_with_label_with_mnemonic(
+   		"Packet _fence graph", accel_group);
+   gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), packet_fence_active);
+   gtk_object_set_data(GTK_OBJECT(display_opt_w), E_DISPLAY_PACKET_FENCE,
+ 		      button);
+   gtk_box_pack_start(GTK_BOX(main_vb), button, TRUE, TRUE, 0);
+   gtk_widget_show(button);
    /* Button row: OK, Apply, and Cancel buttons */
    bbox = gtk_hbutton_box_new();
    gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
***************
*** 269,274 ****
--- 277,286 ----
    button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
  					     E_DISPLAY_NAME_RESOLUTION_KEY);
    g_resolving_actif = (GTK_TOGGLE_BUTTON (button)->active);
+ 
+   button = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(parent_w),
+ 					     E_DISPLAY_PACKET_FENCE);
+   packet_fence_active = (GTK_TOGGLE_BUTTON (button)->active);
  
  }
  
Index: gtk/gtkclist.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/gtk/gtkclist.c,v
retrieving revision 1.7
diff -c -r1.7 gtkclist.c
*** gtkclist.c	2000/05/26 07:47:45	1.7
--- gtkclist.c	2001/03/13 07:05:59
***************
*** 3143,3148 ****
--- 3143,3165 ----
    return GTK_VISIBILITY_FULL;
  }
  
+ /* needed by packet_fence.c to be able determine colors for packet display */
+ GtkCListRow *
+ gtk_clist_get_clistrow (GtkCList *clist,
+ 			  gint      row)
+ {
+   GtkCListRow *clist_row;
+ 
+   g_return_val_if_fail (clist != NULL, NULL);
+   g_return_val_if_fail (GTK_IS_CLIST (clist), NULL);
+ 
+   if (row < 0 || row >= clist->rows)
+     return NULL;
+ 
+   clist_row = ROW_ELEMENT (clist, row)->data;
+   return clist_row;
+ }  
+ 
  void
  gtk_clist_set_foreground (GtkCList *clist,
  			  gint      row,
Index: gtk/gtkclist.h
===================================================================
RCS file: /usr/local/cvsroot/ethereal/gtk/gtkclist.h,v
retrieving revision 1.2
diff -c -r1.2 gtkclist.h
*** gtkclist.h	2000/05/26 07:47:47	1.2
--- gtkclist.h	2001/03/13 07:06:01
***************
*** 626,631 ****
--- 626,635 ----
  			    GdkPixmap **pixmap,
  			    GdkBitmap **mask);
  
+ /* return row info*/
+ 
+ GtkCListRow * gtk_clist_get_clistrow (GtkCList *clist,
+ 			  gint      row);
  /* sets the foreground color of a row, the color must already
   * be allocated
   */
Index: gtk/main.c
===================================================================
RCS file: /usr/local/cvsroot/ethereal/gtk/main.c,v
retrieving revision 1.182
diff -c -r1.182 main.c
*** main.c	2001/03/02 23:10:12	1.182
--- main.c	2001/03/13 07:06:05
***************
*** 9,14 ****
--- 9,16 ----
   * Richard Sharpe, 13-Feb-1999, added support for initializing structures
   *                              needed by dissect routines
   * 
+  * Martin Visser, 15-Nov-2000, added support to allow packet fence  
+  * 
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * as published by the Free Software Foundation; either version 2
***************
*** 130,135 ****
--- 132,138 ----
  #include "packet_win.h"
  #include "gtkglobals.h"
  #include "plugins.h"
+ #include "packet_fence.h"
  #include "colors.h"
  #include "strutil.h"
  
***************
*** 315,321 ****
      return strcmp(text1, text2);
    }
  }
- 
  /* What to do when a column is clicked */
  static void 
  packet_list_click_column_cb(GtkCList *clist, gint column, gpointer data)
--- 318,323 ----
***************
*** 415,420 ****
--- 417,423 ----
  
    blank_packetinfo();
    select_packet(&cfile, row);
+   packet_fence_row_select(row);
  }
  
  static void
***************
*** 1476,1481 ****
--- 1479,1485 ----
  {
    GtkWidget           *main_vbox, *menubar, *u_pane, *l_pane,
                        *stat_hbox,
+ 		      *packet_pane,
                        *filter_bt, *filter_cm, *filter_te,
                        *filter_reset;
    GList               *filter_list = NULL;
***************
*** 1521,1526 ****
--- 1525,1538 ----
    gtk_paned_add2(GTK_PANED(u_pane), l_pane);
    gtk_widget_show(u_pane);
  
+   packet_pane = gtk_hpaned_new(); /* create a horizontal pane to hold packet list and packet fence */
+   gtk_paned_gutter_size(GTK_PANED(packet_pane), (GTK_PANED(packet_pane))->handle_size);
+ /*  gtk_container_border_width(GTK_CONTAINER(packet_pane), 0);*/
+   gtk_paned_add1(GTK_PANED(u_pane), packet_pane);
+   gtk_widget_show(packet_pane);
+   pf = packet_fence_new(); /* create a packet fence */
+   gtk_widget_show(pf->box);/* show it */
+   
    /* Packet list */
    pkt_scrollw = gtk_scrolled_window_new(NULL, NULL);
    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(pkt_scrollw),
***************
*** 1528,1534 ****
    set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
    remember_scrolled_window(pkt_scrollw);
    gtk_widget_show(pkt_scrollw);
!   gtk_paned_add1(GTK_PANED(u_pane), pkt_scrollw);
  
    packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
    gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
--- 1540,1547 ----
    set_scrollbar_placement_scrollw(pkt_scrollw, prefs->gui_scrollbar_on_right);
    remember_scrolled_window(pkt_scrollw);
    gtk_widget_show(pkt_scrollw);
!   gtk_paned_add1(GTK_PANED(packet_pane), pf->box); /* add the packet fence */
!   gtk_paned_add2(GTK_PANED(packet_pane), pkt_scrollw); /* add the packet list */
  
    packet_list = gtk_clist_new_with_titles(cfile.cinfo.num_cols, cfile.cinfo.col_title);
    gtk_container_add(GTK_CONTAINER(pkt_scrollw), packet_list);
***************
*** 1542,1547 ****
--- 1555,1564 ----
      GTK_SIGNAL_FUNC(packet_list_select_cb), NULL);
    gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row",
      GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL);
+   gtk_signal_connect(GTK_OBJECT(GTK_CLIST(packet_list)->vadjustment), "value_changed",
+     GTK_SIGNAL_FUNC(packet_list_value_changed), (gpointer) pf); /* packet fence wants to know somethings changed */
+   gtk_signal_connect(GTK_OBJECT(GTK_CLIST(packet_list)->vadjustment), "changed",
+     GTK_SIGNAL_FUNC(packet_list_changed), (gpointer) pf);
    for (i = 0; i < cfile.cinfo.num_cols; i++) {
      if (get_column_resize_type(cfile.cinfo.col_fmt[i]) != RESIZE_MANUAL)
        gtk_clist_set_column_auto_resize(GTK_CLIST(packet_list), i, TRUE);
/* packet_fence.c
 * Routines for displaying Packet Fence
 *
 * $Id: packet_fence.c,v 1.1 $
 *
 * Copyright (c) 2000 by Martin Visser <martin.visser@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs
 * Copyright 1999 Gerald Combs
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <gtk/gtk.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <errno.h>

#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif

#include "globals.h"
#include "packet.h"
#include "gtkglobals.h"
#include "packet_fence.h"

enum zoomed_func {
	ZOOMEDOUT,
	ZOOMEDIN
};
enum pf_returns {
	PF_COOL,
	PF_REDRAW,
	PF_END,
	PF_BOTTOM,
	PF_TOP
};
enum pf_updates {
	PF_POSCHANGED,
	PF_DRAWAGAIN
};


static void packet_fence_update(packet_fence *);
static int packet_fence_update_ruler(packet_fence *);

/* ON/OFF SWITCH */
gboolean packet_fence_active = TRUE;
packet_fence *pf = NULL;
	
/* Zoom in and out callback */
static void
packet_fence_zoomed(GtkWidget *w, gpointer data){
	static int zoom[] = { 1,2,5,10,20,50,100,200,500,1000,2000,5000,10000,20000,50000,100000,200000,500000,1000000};/* simpler than an algorithm!*/
	static int idx = 12; /* where we start off */
	int zoomnum = sizeof(zoom)/sizeof(int);/* number of levels*/
	char str[30];
	
	switch ((int)data ) {
		case ZOOMEDOUT:
			idx++;
			if (idx >= zoomnum ) idx = zoomnum - 1; 
			break;
		case ZOOMEDIN:
			idx--;
			if (idx <= 0 ) idx = 0; 
			break;
	}
	pf->usecpix = zoom[idx];
	sprintf(str, "%d usec/pixel",pf->usecpix);
	gtk_label_set_text( GTK_LABEL(pf->zoomlevel), str);
	pf->update = PF_DRAWAGAIN;
	packet_fence_update(pf);
}

static void
calc_bytepix(packet_fence *pf)
{
	int availpix;
	availpix = pf->pixwidth - pf->lmargin - pf->rmargin;
	if (availpix <=0) availpix = 10;
	pf->bytepix = (float)pf->maxpacketlength/(float)availpix; /*bytes per pixel */
}
			

/* callback for config event*/
static gint 
packet_fence_config( GtkWidget         *widget,
                             gpointer user_data )
{
GdkColor zoomwinfg = {0,0xc000,0xc000,0xc000};/*grey*/
GdkColor selectfg = {0,0x0000,0x0000,0xffff};/*blue*/
  if (!widget->window) return TRUE;/* too soo yet */
  if (pf->pixmap)
    gdk_pixmap_unref(pf->pixmap);/* destroy the old one*/


  pf->pixmap = gdk_pixmap_new(widget->window,
			  widget->allocation.width,
			  widget->allocation.height,
			  -1);/* create a pixmap the size of drawing area*/
  gdk_draw_rectangle (pf->pixmap,
		      widget->style->white_gc,
		      TRUE,
		      0, 0,
		      widget->allocation.width,
		      widget->allocation.height); /* white out*/
  pf->pixwidth = widget->allocation.width; /* save width of pf drawing area */
  pf->pixheight = widget->allocation.height; /* save height */
  calc_bytepix(pf);
  /*
   * I need a better way of scaling this. Maybe I should size to maximum size
   * that I've seen??
  */
  pf->pixtimeorigin = pf->pixheight/2; /* centre the time to middle of widget */
  pf->gc = gdk_gc_new(widget->window);/* generic gc*/
  pf->selectgc = gdk_gc_new(widget->window);/* gc for drawing selected packet*/
  pf->zoomwingc = gdk_gc_new(widget->window);/*gc for drawing the zoom window */
  gdk_colormap_alloc_color(gtk_widget_get_colormap(widget),&zoomwinfg,FALSE,TRUE);
  gdk_gc_set_foreground(pf->zoomwingc,&zoomwinfg);
  gdk_colormap_alloc_color(gtk_widget_get_colormap(widget),&selectfg,FALSE,TRUE);
  gdk_gc_set_foreground(pf->selectgc,&selectfg);

  if (pf->framearray) {
	  pf->framearray = (frame_data**)g_realloc(pf->framearray,pf->pixheight * sizeof (frame_data *));
	  /* allocate room to store a widget-ful of frame pointers*/
  }
  else {
	  pf->framearray = (frame_data**)g_malloc(pf->pixheight * sizeof (frame_data *));
  }
  pf->update = PF_DRAWAGAIN;
  packet_fence_update(pf);
  return TRUE;
}

/* Redraw the screen from the backing pixmap */
static gint packet_fence_expose( GtkWidget      *widget,
                          GdkEventExpose *event )
{
  gdk_draw_pixmap(widget->window,
		  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
		  pf->pixmap,
		  event->area.x, event->area.y,
		  event->area.x, event->area.y,
		  event->area.width, event->area.height);

  return FALSE;
}
/* callback for a row being selected in the packet list*/
void
packet_fence_row_select(gint row)
{
	if (pf->selectedrow != row ) {/* only bother updating if different*/
		pf->selectedrow = row;/* save the new row*/
		pf->update = PF_DRAWAGAIN;
		packet_fence_update(pf);/* update */
	}
}

/* callback for clicking on the packet fence */
gint
packet_fence_pressed_cb(GtkWidget *widget, GdkEvent *event, gpointer data)
{
	GdkEventButton * event_button;
	frame_data * fdata;
	int i,pos,sign = 1;
	if(widget == NULL || event == NULL ) {
		return FALSE;
	}
	if(event->type == GDK_BUTTON_PRESS) {
		event_button = (GdkEventButton *) event;
		
		if(event_button->button == 1) {
			for (i=0;i< 8; i++) {/*look for nearest frame +/- 8 pixels */
				for (sign = -1; sign<=1;sign+=2) {
					pos = (sign * i ) + (int)event_button->y;/*alternate 0,-1,1,-2,2.... */
					if (pos<0 || pos >=pf->pixheight) return TRUE; /* gone over the edge */
					if ((fdata = (frame_data*)pf->framearray[pos]))
					{
						goto_frame(&cfile,fdata->num); /* goto this frame in clist */
						return TRUE;
					}
				}
			}
			return TRUE;
		}
	}
	return FALSE;/*not one of ours */
}


/*
static void        
packet_fence_size_request_cb              (GtkWidget *widget,
                                              GtkRequisition *requisition,
                                              gpointer user_data)
{
	printf("got size\n");
}
*/

static void        
packet_fence_config_event_cb              (GtkWidget *widget,
                                              GdkEventConfigure *event,
                                              gpointer user_data)
{
	packet_fence_config(widget,user_data);
}
	
			
/* create the packet fence */
packet_fence *
packet_fence_new()
{
	GtkWidget *zoomin;
	GtkWidget *zoomout;
	GtkWidget *bbox;
	pf = (packet_fence*) g_malloc(sizeof(packet_fence));
	pf->pixwidth = 50;
	pf->pixheight = 10;
	pf->lmargin = 10 ;
	pf->rmargin = 20 ;
	pf->hmargin = 20 ;
	pf->maxpacketlength = 1518;/* till we know better */
	calc_bytepix(pf);
	pf->usecpix =  10000 ; /* usecs per pixel */
	pf->timeorigin = 0;
	pf->pixtimeorigin = 0;
	pf->adj_seq = 0;
	pf->started = FALSE;
	pf->update = FALSE;
	pf->box = gtk_table_new (2,2, FALSE); /* create 2 x 2 table */
	gtk_widget_set_usize(pf->box, 100 ,100);
	gtk_widget_show (pf->box);
	pf->ruler = gtk_vruler_new();
	gtk_ruler_set_metric(GTK_RULER(pf->ruler),GTK_PIXELS);
	gtk_widget_set_usize(pf->ruler, 16 ,0);
	gtk_table_attach (GTK_TABLE (pf->box), pf->ruler, 0,1,0,1,GTK_FILL,GTK_FILL|GTK_EXPAND,0,0); /* put a 20 pixel wide ruler down left */
	gtk_widget_show (pf->ruler);
	pf->drawing_area = gtk_drawing_area_new ();
  	gtk_drawing_area_size (GTK_DRAWING_AREA (pf->drawing_area), pf->pixwidth, pf->pixheight);
	gtk_table_attach (GTK_TABLE (pf->box), pf->drawing_area, 1,2,0,1,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL|GTK_EXPAND,0,0); /* put a drawing area up on the right */
	gtk_widget_show (pf->drawing_area);
	packet_fence_update_ruler(pf);
	bbox = gtk_hbox_new(FALSE,1);
	zoomout = gtk_button_new_with_label("<");
	gtk_signal_connect(GTK_OBJECT(zoomout), "clicked",
		     GTK_SIGNAL_FUNC(packet_fence_zoomed), (gpointer) ZOOMEDOUT);
	zoomin = gtk_button_new_with_label(">");
	gtk_signal_connect(GTK_OBJECT(zoomin), "clicked",
		     GTK_SIGNAL_FUNC(packet_fence_zoomed), (gpointer) ZOOMEDIN);
	pf->zoomlevel = gtk_label_new("10000 usec/pixel");
	gtk_widget_set_usize(zoomin, 14 ,14);
	gtk_widget_set_usize(zoomout, 14 ,14);
	gtk_widget_set_usize(pf->zoomlevel, 0 ,14);
	gtk_label_set_justify(GTK_LABEL(pf->zoomlevel),GTK_JUSTIFY_LEFT);

	gtk_box_pack_start(GTK_BOX(bbox), zoomout, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(bbox), zoomin, FALSE, FALSE, 0);
	gtk_box_pack_start(GTK_BOX(bbox), pf->zoomlevel, FALSE, FALSE, 0);
	gtk_table_attach (GTK_TABLE (pf->box), bbox, 1,2,1,2,GTK_FILL|GTK_EXPAND|GTK_SHRINK,GTK_FILL,0,0); /* add the zoom box with two buttons and label to bottom right */
	gtk_widget_show(zoomin);
	gtk_widget_show(zoomout);
	gtk_widget_show(pf->zoomlevel);
	gtk_widget_show(bbox);
	gtk_signal_connect (GTK_OBJECT (pf->drawing_area), "expose_event",
	      (GtkSignalFunc) packet_fence_expose, NULL);
	gtk_signal_connect (GTK_OBJECT(pf->drawing_area),"configure_event",
		(GtkSignalFunc) packet_fence_config_event_cb, NULL);
/*	gtk_signal_connect (GTK_OBJECT(pf->drawing_area),"size_request",
		(GtkSignalFunc) packet_fence_size_request_cb, NULL);
*/ 
	gtk_signal_connect(GTK_OBJECT(pf->drawing_area), "button_press_event",
		     GTK_SIGNAL_FUNC(packet_fence_pressed_cb), NULL);
	gtk_widget_set_events (pf->drawing_area, GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK );
	return pf;

}

/* return the relative time, in usecs, a frame was grabbed */
static int 
framereltime( frame_data * fdata) 
/*	compute  total relative time */
{
	return  fdata->rel_secs * 1000000 + fdata->rel_usecs; 
}

/* convert time to pixels*/
static int
timetopix( packet_fence * pf, int time ) 
/* convert time to pixel position */
{
	int timeoffset;
	int pixtime;
	timeoffset = time - pf->timeorigin;/* diff between now and origin */
	pixtime = timeoffset / pf->usecpix + pf->pixtimeorigin;/* pixels down relative to 0 */
	
	return pixtime;
}

/* convert pixels to time*/
static int
pixtotime( packet_fence * pf, int pix ) 
/* convert pixel position to time in usecs */
{
	int pixoffset;
	int time;
	pixoffset = pix - pf->pixtimeorigin;/* diff between centre and position */
	time = pixoffset * pf->usecpix + pf->timeorigin;/* relative to time  */
	
	return time;
}

/* draw a packet in the right spot */
gboolean
packet_fence_draw_packet(gint row )
{
  frame_data * fdata;
  gint pixlen,time,pixdown;
  GdkGC * packetgc;
  GtkCListRow *clistrow;
	fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), row);
	if (fdata == NULL ) return PF_END; /* might not be loaded yet */
	if (fdata->pkt_len > pf->maxpacketlength ) {
		pf->maxpacketlength = fdata->pkt_len + 100; /* don't want to it toom often */
		calc_bytepix(pf);
		return PF_REDRAW;
	}
		
	pixlen =   fdata->pkt_len / pf->bytepix; /* set packet length  */
	time = framereltime(fdata);
	pixdown = timetopix(pf,time);
	if (pixdown <0 ) return PF_BOTTOM; /* reached a limit */
	if (pixdown >= pf->pixheight) return PF_TOP; /* reached a limit */
	if (pf->selectedrow == row) /* if it is selected in list add the blue bits*/
	{
		gdk_draw_line(pf->pixmap,pf->selectgc,0,pixdown,pf->lmargin-2,pixdown);
		gdk_draw_line(pf->pixmap,pf->selectgc,pf->pixwidth-pf->rmargin+1,pixdown,pf->pixwidth,pixdown);
	}

	clistrow = gtk_clist_get_clistrow(GTK_CLIST(packet_list),row);/* this is the call to my hacked function to get the GtkCListRow info */
	if (!clistrow) return PF_END; /* reached a limit */
		
	if (clistrow->fg_set) {/* its not default*/
		gdk_gc_set_foreground(pf->gc,&(clistrow->foreground));
		packetgc = pf->gc;
	} else { /* its default colour*/
		packetgc = pf->drawing_area->style->black_gc ;
	}
	gdk_draw_line(pf->pixmap,packetgc,pf->lmargin,pixdown,pf->lmargin + pixlen,pixdown);
	pf->framearray[pixdown] = fdata; /* save the (frame_data *) where we drew it for later */
	if (row <=0) return PF_BOTTOM;
	return PF_COOL; /* sucessfully drawn */
}
static int
packet_fence_clear_bg(packet_fence *pf)
{
	  if(!pf || !pf->pixmap || !pf->drawing_area) return FALSE;
	  
	  gdk_draw_rectangle (pf->pixmap,
		      pf->drawing_area->style->white_gc,
		      TRUE,
		      0, 0,
		      pf->drawing_area->allocation.width,
		      pf->drawing_area->allocation.height);/*make a clean slate */
	  return TRUE;
}
static int
packet_fence_draw_zoomrect(packet_fence *pf)
{
  frame_data *fdata;
  int time,zoomrecttop,zoomrectbot;
	  if(!pf || !pf->pixmap) return FALSE;
	/* now print zoom rectangle. This shows where the displayed packet list  is relative to the displayed packet fence*/
	if ((fdata = ((frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), pf->firstrow)) )){
		time = framereltime(fdata);
		zoomrecttop = timetopix(pf,time) - 1;   
		} 
	else zoomrecttop = 0;
	if ((fdata = ((frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), pf->lastrow)) )){
		time = framereltime(fdata);
		zoomrectbot = timetopix(pf,time);
		} 
	else zoomrectbot = pf->pixheight;
	gdk_draw_rectangle(pf->pixmap,pf->zoomwingc,TRUE,pf->lmargin,zoomrecttop,pf->pixwidth - pf->lmargin - pf->rmargin, zoomrectbot - zoomrecttop + 2); /* draw it in */
	return TRUE;
}
static int
packet_fence_new_position(packet_fence *pf)
{
  frame_data *fdata;
  GtkAdjustment *adj;
  int i;

  
  	if (!pf || !packet_fence_active || !pf->framearray) { /* only update if we are ready, willing and able */
		return FALSE;
	}
	adj = GTK_CLIST(packet_list)->vadjustment;
	for (i=0;i<pf->pixheight;i++) pf->framearray[i] = NULL; /* clear out the stored data as it will be all wrong */
	pf->adjvalue = adj->value;
	pf->adjpagesize = adj->page_size;
	pf->firstrow = (int)(adj->value)/(GTK_CLIST(packet_list)->row_height+1); /* get the first row in the packet list. (The +1 works for me) */
	pf->lastrow = pf->firstrow - 1 + (int)(adj->page_size)/(GTK_CLIST(packet_list)->row_height);/* work out what the last row should be. page_size and row_height are in pixels*/	
	pf->midrow = (pf->firstrow + pf->lastrow) / 2; /* find the middle*/
	fdata = (frame_data *) gtk_clist_get_row_data(GTK_CLIST(packet_list), pf->midrow);
	if (fdata == NULL ) {
		return FALSE;
	}
	pf->timeorigin = framereltime(fdata); /* this is the time in the mid of widget */
	return TRUE;
}
static int
packet_fence_refresh_drawing_area(packet_fence *pf)
{
	GdkRectangle update_rect;
	if(!pf || !pf->drawing_area) return FALSE;
	update_rect.x = 0;
	update_rect.y = 0;
	update_rect.width = pf->drawing_area->allocation.width;
	update_rect.height = pf->drawing_area->allocation.height;
	gtk_widget_draw( pf->drawing_area, &update_rect);/* we can draw to screen now */
	return TRUE;
}
static int
packet_fence_update_ruler(packet_fence *pf)
{
	int firsttime,lasttime;
	firsttime = pixtotime(pf,0);
	lasttime = pixtotime(pf,pf->pixheight);
	/* set the ruler limits */
	gtk_ruler_set_range( GTK_RULER(pf->ruler), firsttime/1000000.0,
	    lasttime/1000000.0, pf->timeorigin/1000000.0, 10000);
	return TRUE;
}
static int
packet_fence_update_packets(packet_fence *pf)
{
	int flag = TRUE;
	int ret = 0;
	int static draw_count=0;
	while(flag) {
		ret = packet_fence_draw_packet(pf->currentrow) ;  /* draw until none left */
		if (ret == PF_BOTTOM)  {
			pf->currentrow = pf->midrow + 1;
			continue;
		} else if (ret == PF_REDRAW ) { 
			pf->currentrow = pf->midrow;
			continue;
		} else if (ret == PF_END || ret == PF_TOP ) { 
			flag = FALSE;
			continue;
		}
		if(draw_count++>200) {
			draw_count = 0;
			packet_fence_refresh_drawing_area(pf);
			if (gtk_events_pending()) {/* someone wants some time */
				pf->idleid = gtk_idle_add((GtkFunction)&packet_fence_update,pf);/* wait for someone else */
				return FALSE;
			}
		}
		
		if(pf->currentrow <= pf->midrow ){
			pf->currentrow--;
		}
		else if(pf->currentrow > pf->midrow ){
			pf->currentrow++;
		}
	}
	return TRUE;
		
			
}
/* update the packet fence */
static void 
packet_fence_update(packet_fence * pf){
	
	if(!pf) return ;
	if(pf->idleid) {/* this is a return from being interrupted */
		gtk_idle_remove(pf->idleid);
		pf->idleid = 0;
	}
	if(!packet_fence_new_position(pf)) return;
	if(!packet_fence_clear_bg(pf)) return;
	if(!packet_fence_draw_zoomrect(pf)) return;
	pf->currentrow = pf->midrow;
	pf->started = TRUE;
	if(!packet_fence_update_packets(pf)) return;
		pf->started = FALSE;
		if(!packet_fence_refresh_drawing_area(pf)) return;
		if(!packet_fence_update_ruler(pf))return;
	return;
}

/* packet list value has changed */
void 
packet_list_value_changed(GtkAdjustment *adj, gpointer user_data)
{
	packet_fence * pf;
	pf = (packet_fence *)user_data;
	if (!pf) return;
	pf->adj_seq++;
	pf->update = PF_POSCHANGED;
	packet_fence_update(pf);
}
/* packet list has changed, might be resize */
void 
packet_list_changed(GtkAdjustment *adj, gpointer user_data)
{
	packet_fence * pf;
	pf = (packet_fence *)user_data;
	if (!pf) return;
	if (adj->value == pf->adjvalue && adj->page_size == pf->adjpagesize) {
		return; /* nothing really changed, the clist just got nudged. Probably by us writing to the zoom label */
	}
	pf->update = PF_POSCHANGED;
	packet_fence_update(pf);
}
/* packet_fence.h
 * Definitions for Packet Fence
 *
 * $Id: packet_fence.h,v 1.1 $
 *
 * Copyright (c) 2000 by Martin Visser <martin.visser@xxxxxxxxxx>
 *
 * Ethereal - Network traffic analyzer
 * By Gerald Combs
 * Copyright 1999 Gerald Combs
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

typedef struct _packet_fence {
	GtkWidget *box ;
	GtkWidget *drawing_area;
	GtkWidget *ruler;
	GtkWidget *zoomlevel;
	GdkPixmap * pixmap;
	GdkGC * gc;
	GdkGC * zoomwingc;
	GdkGC * selectgc;
	int pixwidth;
	int pixheight;
	int hmargin;
	int lmargin;
	int rmargin;
	float bytepix;
	int usecpix;
	int timeorigin;
	int pixtimeorigin;
	int selectedrow;
	int currentrow;
	int firstrow;
	int lastrow;
	int midrow;
	int maxpacketlength;
	int adj_seq;
	int started;
	int interrupted;
	int update;
	int idleid;
	float begintime;
	float endtime;
	gfloat adjvalue;
	gfloat adjpagesize;
	frame_data **framearray;
} packet_fence;


packet_fence *packet_fence_new();
void packet_list_value_changed(GtkAdjustment * adj, gpointer user_data);
void packet_list_changed(GtkAdjustment * adj, gpointer user_data);
void packet_fence_row_select(gint row);

extern packet_fence * pf;