[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

gEDA-cvs: CVS update: Makefile.am



  User: ahvezda 
  Date: 06/07/13 22:23:57

  Modified:    .        Makefile.am
  Added:       .        a_pan.c a_zoom.c g_funcs.c g_hook.c g_keys.c g_rc.c
                        g_register.c globals.c gschem.c i_basic.c
                        i_callbacks.c i_vars.c o_arc.c o_attrib.c o_basic.c
                        o_box.c o_buffer.c o_bus.c o_circle.c o_complex.c
                        o_copy.c o_cue.c o_delete.c o_find.c o_grips.c
                        o_line.c o_misc.c o_move.c o_net.c o_picture.c
                        o_pin.c o_select.c o_slot.c o_text.c o_undo.c
                        parsecmd.c x_attribedit.c x_basic.c x_color.c
                        x_dialog.c x_event.c x_fileselect.c x_grid.c
                        x_image.c x_log.c x_menus.c x_multiattrib.c
                        x_pagesel.c x_preview.c x_print.c x_script.c
                        x_stroke.c x_window.c
  Log:
  Commited noweb removal patch by Jason Childs.
  
  
  
  
  Revision  Changes    Path
  1.43      +20 -40    eda/geda/gaf/gschem/src/Makefile.am
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: Makefile.am
  ===================================================================
  RCS file: /home/cvspsrv/cvsroot/eda/geda/gaf/gschem/src/Makefile.am,v
  retrieving revision 1.42
  retrieving revision 1.43
  diff -u -b -r1.42 -r1.43
  --- Makefile.am	21 May 2006 13:19:56 -0000	1.42
  +++ Makefile.am	14 Jul 2006 02:23:54 -0000	1.43
  @@ -3,37 +3,27 @@
   # directory are distributed by the demo_distfiles variable in the top
   # level Makefile.
   #
  -
  -NOTANGLE=       @NOTANGLE@
  -NOTANGLEROOT=	@NOTANGLEROOT@
  -NOTANGLEFLAGS=  @NOTANGLEFLAGS@
  -
  -INDENTBIN=      @INDENT@
  -INDENTFLAG=     -kr -i2
  -
  -VPATH = ../noweb:../include:src
  +VPATH = ../include:src
   
   bin_PROGRAMS = gschem
   
  -BUILT_SOURCES = \
  -	a_pan.nw a_zoom.nw \
  -	g_register.nw g_hook.nw\
  -	g_rc.nw g_keys.nw g_funcs.nw \
  -	globals.nw gschem.nw \
  -	i_basic.nw i_callbacks.nw i_vars.nw \
  -	o_basic.nw o_attrib.nw o_move.nw o_copy.nw o_delete.nw o_misc.nw \
  -	o_slot.nw o_grips.nw \
  -	o_arc.nw o_box.nw o_circle.nw o_complex.nw o_select.nw o_find.nw \
  -	o_line.nw o_net.nw o_text.nw o_pin.nw o_bus.nw o_buffer.nw o_undo.nw \
  -	o_picture.nw \
  -	x_basic.nw x_dialog.nw \
  -	x_event.nw x_grid.nw x_log.nw x_menus.nw x_script.nw \
  -	x_pagesel.nw x_print.nw x_window.nw x_stroke.nw x_image.nw x_color.nw \
  -	x_fileselect.nw x_preview.nw x_attribedit.nw \
  -	x_multiattrib.nw \
  -	parsecmd.nw o_cue.nw
  -
  -gschem_SOURCES = $(BUILT_SOURCES:.nw=.c)
  +gschem_SOURCES = \
  +	a_pan.c a_zoom.c \
  +	g_register.c g_hook.c\
  +	g_rc.c g_keys.c g_funcs.c \
  +	globals.c gschem.c \
  +	i_basic.c i_callbacks.c i_vars.c \
  +	o_basic.c o_attrib.c o_move.c o_copy.c o_delete.c o_misc.c \
  +	o_slot.c o_grips.c \
  +	o_arc.c o_box.c o_circle.c o_complex.c o_select.c o_find.c \
  +	o_line.c o_net.c o_text.c o_pin.c o_bus.c o_buffer.c o_undo.c \
  +	o_picture.c \
  +	x_basic.c x_dialog.c \
  +	x_event.c x_grid.c x_log.c x_menus.c x_script.c \
  +	x_pagesel.c x_print.c x_window.c x_stroke.c x_image.c x_color.c \
  +	x_fileselect.c x_preview.c x_attribedit.c \
  +	x_multiattrib.c \
  +	parsecmd.c o_cue.c
   
   if CCISGCC
   AM_CFLAGS = -Wall
  @@ -52,14 +42,6 @@
   src: $(gschem_SOURCES)
   	@echo Finished building the C source
   
  -SUFFIXES = .nw
  -
  -.nw.c:
  -	$(NOTANGLE) $(NOTANGLEFLAGS) $(NOTANGLEROOT)'$@ : *' $< > ../src/$@.tmp
  -	mv -f ../src/$@.tmp ../src/$@
  -#	$(INDENTBIN) $(INDENTFLAG) ../src/$@
  -	rm -f ../src/$@~
  -
   CPROTO =	cproto
   CPROTOCFLAGS = 	$(INCLUDES) -I. -I.. -I../include
   ALES_HACK =	-D__GNUC__
  @@ -74,13 +56,11 @@
   	rm -f po/$(PACKAGE).pot
   	@mv -f po/POTFILES.in po/POTFILES.in~ ; true
   	grep '\([^A-Za-z0-9_]_(\)\|\(^_(\)\|\(gettext[[:blank:]]*(\)' \
  -	noweb/*.nw | cut -d: -f1 | sort -u >po/POTFILES.in
  +	*.c | cut -d: -f1 | sort -u >po/POTFILES.in
   	$(MAKE)
   
   MOSTLYCLEANFILES = *.log core FILE *~ prototype.bak
   CLEANFILES = *.log core FILE *~ prototype.bak
   DISTCLEANFILES = *.log core FILE *~ prototype.bak
   MAINTAINERCLEANFILES = *.log core FILE *~ prototype.bak prototype.h \
  -			Makefile.in configure \
  -			*.c 
  -
  +			Makefile.in configure 
  
  
  
  1.21      +180 -378  eda/geda/gaf/gschem/src/a_pan.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: a_pan.c
  ===================================================================
  RCS file: a_pan.c
  diff -N a_pan.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ a_pan.c	14 Jul 2006 02:23:54 -0000	1.21
  @@ -0,0 +1,255 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/x_states.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* Kazu on July 8, 1999 - added these macros to simplify the code */
  +/* keep these macros local to this file! KISS! */
  +/*! \brief */
  +#define GET_PAGE_WIDTH(w)					\
  +	((w)->page_current->right  - (w)->page_current->left)
  +/*! \brief */
  +#define GET_PAGE_HEIGHT(w)					\
  +	((w)->page_current->bottom - (w)->page_current->top )
  +
  +/*! \brief */
  +#define GET_PAGE_CENTER_X(w)					\
  +        (((w)->page_current->left + (w)->page_current->right)  / 2.0)
  +/*! \brief */
  +#define GET_PAGE_CENTER_Y(w)					\
  +        (((w)->page_current->top + (w)->page_current->bottom) / 2.0)
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Kazu Hirata <kazu@xxxxxxxx> on July 25, 1999 - all zoom- and
  + * pan-related functions should eventually get to this function. It
  + * takes the desired center coordinate and the desired zoom
  + * factor. Necessary adjustments may be done depending on situations.
  + * */
  +/* this code is not longer experimental an is used by several functions
  +   like every zooming-function and the x_event_configure (Werner Hoch,(hw))*/
  +void a_pan_general(TOPLEVEL *w_current, double world_cx, double world_cy,
  +		   double relativ_zoom_factor,int flags)
  +{
  +  /* see libgeda/include/defines.h for flags */
  +  /*if the borders should be ignored always, remove, outcomment or changes
  +    the flags in the function-calls*/
  +  /*	flags |= A_PAN_IGNORE_BORDERS;
  +   */		
  +  /* think it's better that the zoomfactor is defined as pix/mills
  +     this will be the same as w_current->page_current->to_screen_x/y_constant*/
  +  int zoom_max = 5;	
  +  int start_x, start_y;
  +  double zx, zy, zoom_old, zoom_new, zoom_min;
  +
  +#if DEBUG
  +  printf("a_pan_general(): world_cx=%f, world_cy=%f\n",world_cx, world_cy);
  +#endif	
  +
  +  /* calc minimum zoomfactors and choose the smaller one. They are equal
  +     if the aspectratio of the world is the same as the screen ratio */
  +  zx = (double) w_current->width / (w_current->init_right -
  +                                    w_current->init_left);
  +  zy = (double) w_current->height / (w_current->init_bottom -
  +                                     w_current->init_top);
  +  zoom_min = zx < zy ? zx : zy;
  +
  +#if DEBUG
  +  printf("  zx_min=%f, zy_min=%f , flags=%d\n ",zx, zy, flags);
  +#endif	
  +
  +  /* to_screen_x_constant and to_screen_y_constant are almost the same.
  +     lets use to_screen_y_constant */
  +  zoom_old = w_current->page_current->to_screen_y_constant;
  +		
  +  /* calc new zooming factor */
  +  /* check if there's a zoom_full (relativ_zoom_factor == -1) */
  +  if (relativ_zoom_factor <0)  {
  +    zoom_new = zoom_min;
  +  }
  +  else {
  +    zoom_new = zoom_old * relativ_zoom_factor;
  +    zoom_new = zoom_new > zoom_max ? zoom_max : zoom_new;
  +    if (!(flags & A_PAN_IGNORE_BORDERS)) {
  +      zoom_new = zoom_new < zoom_min ? zoom_min : zoom_new;
  +    }
  +  }
  +
  +  /* check to see if we are inside an action draw net, etc.  If
  +   * yes, convert the start screen coords to world coords */
  +  if (w_current->inside_action) {
  +    SCREENtoWORLD(w_current,
  +		  w_current->start_x, w_current->start_y,
  +		  &start_x, &start_y);
  +  }
  +
  +  /* calculate the new visible area; adding 0.5 to round */
  +  w_current->page_current->left = world_cx - (double) w_current->width
  +    / 2 / zoom_new + 0.5;
  +  w_current->page_current->right = world_cx + (double) w_current->width
  +    / 2 / zoom_new + 0.5;
  +  w_current->page_current->top = world_cy - (double) w_current->height
  +    / 2 / zoom_new + 0.5;
  +  w_current->page_current->bottom = world_cy + (double) w_current->height
  +    / 2 / zoom_new + 0.5;
  +	
  +  /* and put it back to the borders */
  +  if (!(flags & A_PAN_IGNORE_BORDERS)) {
  +    /* check right border */
  +    if (w_current->page_current->right > w_current->init_right) {
  +      w_current->page_current->left +=
  +        w_current->init_right -
  +        w_current->page_current->right;
  +      w_current->page_current->right =
  +        w_current->init_right;
  +    }
  +    /* check left border; this have to be done after the right border */
  +    if (w_current->page_current->left < w_current->init_left) {
  +      w_current->page_current->right +=
  +        w_current->init_left -
  +        w_current->page_current->left;
  +      w_current->page_current->left =
  +        w_current->init_left;
  +    }
  +    /* check bottom border */
  +    if (w_current->page_current->bottom > w_current->init_bottom) {
  +      w_current->page_current->top +=
  +        w_current->init_bottom -
  +        w_current->page_current->bottom;
  +      w_current->page_current->bottom = w_current->init_bottom;
  +    }
  +    /* check top border this have to be done after the bottom border*/
  +    if (w_current->page_current->top < w_current->init_top) {
  +      w_current->page_current->bottom +=
  +        w_current->init_top -
  +        w_current->page_current->top;
  +      w_current->page_current->top = w_current->init_top;
  +    }
  +  }
  +	
  +#if DEBUG
  +  printf("zoom_old: %f, zoom_new: %f \n ",zoom_old, zoom_new);
  +  printf("left: %d, right: %d, top: %d, bottom: %d\n",
  +         w_current->page_current->left, w_current->page_current->right, 
  +	 w_current->page_current->top, w_current->page_current->bottom);
  +  printf("aspect: %f\n",
  +         (float) fabs(w_current->page_current->right  
  +		      - w_current->page_current->left) /
  +         (float) fabs(w_current->page_current->bottom 
  +		      - w_current->page_current->top ));
  +#endif
  +	
  +  /* set_window */
  +  set_window(w_current, w_current->page_current,
  +             w_current->page_current->left  ,
  +             w_current->page_current->right ,
  +             w_current->page_current->top   ,
  +             w_current->page_current->bottom);
  +
  +  /* convert world coords back to screen coords */
  +  if (w_current->inside_action) {
  +    WORLDtoSCREEN(w_current,
  +		  start_x, start_y,
  +		  &(w_current->start_x), &(w_current->start_y));
  +    /* set all rubberband points to it's start values:
  +       As we don't draw the rubberbands after zooming/paning this
  +       will lead the a redraw of the rubberbands with the next
  +       motion event */
  +    w_current->last_x = w_current->second_x = w_current->start_x;
  +    w_current->save_x = w_current->start_x;
  +    w_current->last_y = w_current->second_y = w_current->start_y;
  +    w_current->save_y = w_current->start_y;
  +    w_current->distance = w_current->loc_y = w_current->loc_x = 0;
  +  }
  +
  +  /* redraw */
  +  if (!(flags & A_PAN_DONT_REDRAW)) {
  +    x_scrollbars_update(w_current);
  +    o_redraw_all(w_current);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \todo Kazu on July 8, 1999 - distill common part from a_pan() and
  + *  a_pan_mouse() because they are doing basically the same thing
  + */
  +void a_pan(TOPLEVEL *w_current, int x, int y)
  +{
  +  double world_cx, world_cy;
  +
  +#if DEBUG
  +  printf("a_pan(): x=%d, y=%d\n", x, y);
  +#endif	
  +
  +  /* make mouse to the new world-center;
  +     attention: there are information looses because of type cast in mil_x */
  +
  +  world_cx = mil_x(w_current, x);
  +  world_cy = mil_y(w_current, y);
  +
  +  a_pan_general(w_current, world_cx, world_cy, 1, 0);
  +
  +  /*! \bug FIXME? This call will trigger a motion event (x_event_motion()),
  +   * even if the user doesn't move the mouse 
  +   * Not ready for prime time, maybe there is another way to trigger the
  +   * motion event without changing the cursor position (Werner)
  +   */
  +  /* x_basic_warp_cursor(w_current->drawing_area, x, y, 0); */
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void a_pan_mouse(TOPLEVEL *w_current, int diff_x, int diff_y)
  +{
  +  double world_cx, world_cy;
  +
  +#if DEBUG
  +  printf("a_pan_mouse(): diff_x=%d, diff_y=%d\n", diff_x, diff_y);
  +#endif	
  +
  +  world_cx=GET_PAGE_CENTER_X(w_current) - WORLDabs(w_current, diff_x);
  +  world_cy=GET_PAGE_CENTER_Y(w_current) + WORLDabs(w_current, diff_y);
  +
  +#if DEBUG
  +  printf("  world_cx=%f, world_cy=%f, world_dx=%d, world_dy=%d\n",
  +	 world_cx, world_cy, world_dx, world_dy);
  +#endif
  +  
  +  a_pan_general(w_current, world_cx, world_cy, 1, 0);
  +}
  
  
  
  1.22      +286 -273  eda/geda/gaf/gschem/src/a_zoom.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: a_zoom.c
  ===================================================================
  RCS file: a_zoom.c
  diff -N a_zoom.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ a_zoom.c	14 Jul 2006 02:23:54 -0000	1.22
  @@ -0,0 +1,416 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* Kazu - discuss with Ales
  + * 1) rint
  + * 2) SWAP & SORT
  + */
  +
  +/* Kazu on July 8, 1999 - added these macros to simplify the code */
  +/* keep these macros local to this file! KISS! */
  +/*! \brief */
  +#define GET_PAGE_WIDTH(w)					\
  +	((w)->page_current->right  - (w)->page_current->left)
  +/*! \brief */
  +#define GET_PAGE_HEIGHT(w)					\
  +	((w)->page_current->bottom - (w)->page_current->top )
  +/*! \brief */
  +#define GET_PAGE_ASPECT_RATIO(w)		\
  +	((float) fabs(GET_PAGE_WIDTH (w)) /	\
  +	 (float) fabs(GET_PAGE_HEIGHT(w)))
  +
  +/*! \brief */
  +#define GET_BOX_WIDTH(w)			\
  +	abs((w)->last_x - (w)->start_x)
  +/*! \brief */
  +#define GET_BOX_HEIGHT(w)			\
  +	abs((w)->last_y - (w)->start_y)
  +/*! \brief */
  +#define GET_BOX_LEFT(w)				\
  +	min((w)->start_x, (w)->last_x);
  +/*! \brief */
  +#define GET_BOX_TOP(w)				\
  +	min((w)->start_y, (w)->last_y);
  +
  +/*! \brief */
  +#define XOR_SETUP(w)				\
  +	gdk_gc_set_foreground((w)->xor_gc, 	\
  +		              x_get_darkcolor(w_current->zoom_box_color))
  +
  +/*! \brief */
  +#define XOR_DRAW_BOX(w, x, y, wd, ht)				\
  +	gdk_draw_rectangle((w)->window, (w)->xor_gc, FALSE,	\
  +			   (x), (y), (wd), (ht));
  +
  +/*! \brief */
  +#define SWAP_INT(a, b)				\
  +	{ int tmp = a; a = b; b = tmp; }
  +/*! \brief */
  +#define SORT2_INT(a, b)				\
  +	{ if((b) < (a)) { SWAP_INT(a, b); }}
  +
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +/* dir is either ZOOM_IN, ZOOM_OUT or ZOOM_FULL which are defined in globals.h */
  +void a_zoom(TOPLEVEL *w_current, int dir, int selected_from, int pan_flags)
  +{
  +  double world_pan_center_x,world_pan_center_y,relativ_zoom_factor = - 1;
  +  int start_x, start_y;
  +
  +  /*calc center: either "mouse_to_world" or center=center */
  +  if (w_current->zoom_with_pan == TRUE && selected_from == HOTKEY) {
  +    world_pan_center_x = (double) mouse_x *
  +    w_current->page_current->to_world_x_constant +
  +    w_current->page_current->left;
  +    world_pan_center_y = (double) w_current->page_current->bottom - mouse_y *
  +    w_current->page_current->to_world_y_constant;
  +  }
  +  else {
  +    world_pan_center_x = (double) (w_current->page_current->left +
  +                                   w_current->page_current->right ) / 2;
  +    world_pan_center_y = (double) (w_current->page_current->top +
  +                                   w_current->page_current->bottom ) / 2;
  +  }
  +
  +  switch(dir) {
  +    case(ZOOM_IN):
  +    relativ_zoom_factor = 1.5;
  +    break;	
  +	
  +    case(ZOOM_OUT):
  +    relativ_zoom_factor = 0.6667;
  +    break;
  +
  +    case(ZOOM_FULL):
  +    /*hope someone have a better idea (hw)*/
  +    relativ_zoom_factor = -1;
  +    break;
  +  }
  +
  +
  +
  +#if DEBUG
  +  printf("relative zoomfactor: %E\n", relativ_zoom_factor);
  +  printf("new center: x: %E, y: %E \n",
  +         world_pan_center_x, world_pan_center_y);
  +#endif
  +
  +
  +  /* calculate new window and draw it */
  +  a_pan_general(w_current, world_pan_center_x, world_pan_center_y,
  +                relativ_zoom_factor, pan_flags);
  +	
  +  /* warp the cursor to the right position */ 
  +  if (w_current->warp_cursor) {
  +     WORLDtoSCREEN(w_current, world_pan_center_x, world_pan_center_y, 
  +		   &start_x, &start_y);
  +     x_basic_warp_cursor(w_current->drawing_area, start_x, start_y, 0);
  +  }
  +  else {
  +    /*! \bug FIXME? trigger a x_event_motion() call without moving the cursor 
  +     *  this will redraw rubberband lines 
  +     *  Find a way to trigger the x_event_motion() without moving
  +     *  the mouse cursor (werner) 
  +     */
  +    /* x_basic_warp_cursor(w_current->drawing_area, mouse_x, mouse_y, 0); */
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void a_zoom_extents(TOPLEVEL *w_current, OBJECT *o_current, int pan_flags)
  +{
  +  int lleft, lright, ltop, lbottom;
  +  double zx, zy, relativ_zoom_factor;
  +  double world_pan_center_x,world_pan_center_y;
  +  /*	double new_aspect, delta_x, delta_y, pad_x, pad_y;
  +	int zoom_scale;
  +	int diff_x;
  +  */
  +  if (o_current != NULL) {
  +    if (o_current->next == NULL) {
  +      return;
  +    }
  +  } else {
  +    return;
  +  }
  +
  +  world_get_complex_bounds(w_current, o_current,
  +                           &lleft, &ltop,
  +                           &lright, &lbottom);
  +
  +#if DEBUG
  +  printf("in a_zoom_extents:  left: %d, right: %d, top: %d, bottom: %d\n",
  +         lleft, lright, ltop, lbottom);
  +#endif
  +
  +  /*calc the necessary zoomfactor to show everything
  +    taking the fabs makes only sense if they're not sorted*/
  +  zx = (double) GET_PAGE_WIDTH(w_current) / fabs(lright-lleft);
  +  zy = (double) GET_PAGE_HEIGHT(w_current) / fabs(lbottom-ltop);
  +  /* choose the smaller one, 0.9 for paddings on all side*/
  +  relativ_zoom_factor = (zx < zy ? zx : zy) * 0.9;
  +	
  +  /*get the center of the objects*/
  +  world_pan_center_x = (double) (lright + lleft) /2;
  +  world_pan_center_y = (double) (lbottom + ltop) /2;
  +	
  +  /* and create the new window*/
  +  a_pan_general(w_current, world_pan_center_x, world_pan_center_y,
  +                relativ_zoom_factor, pan_flags );	
  +
  +  /*! \bug FIXME? trigger a x_event_motion() call without moving the cursor 
  +   *  this will redraw rubberband lines after zooming
  +   *  removed!, it has side effects in the preview of the part dialog 
  +   *  need to find another way to trigger x_event_motion() (Werner)
  +   */
  +  /* x_basic_warp_cursor(w_current->drawing_area, mouse_x, mouse_y, 0); */
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +/* made a rewrite (hw) */
  +void a_zoom_box(TOPLEVEL *w_current, int pan_flags)
  +{
  +  double cx,cy;
  +  double zx, zy, relativ_zoom_factor;
  +  double world_pan_center_x,world_pan_center_y;
  +
  +  /*test if there is really a box*/
  +  if (w_current->start_x == w_current->last_x ||
  +      w_current->start_y == w_current->last_y) {
  +    s_log_message(_("Zoom too small!  Cannot zoom further.\n"));
  +    return;
  +  }
  +	
  +  /*calc new zoomfactors and choose the smaller one*/
  +  zx = (double) w_current->width /
  +  abs(w_current->start_x - w_current->last_x);
  +  zy = (double) w_current->height /
  +  abs(w_current->start_y - w_current->last_y);
  +  relativ_zoom_factor = (zx < zy ? zx : zy);
  +	
  +  /*calc new center, first in the box*/	
  +  cx = (double) (w_current->start_x + w_current->last_x) /2;
  +  cy = (double) (w_current->start_y + w_current->last_y) /2;
  +
  +  /* and translate that point to world */		
  +  world_pan_center_x = (double) cx *
  +  w_current->page_current->to_world_x_constant +
  +  w_current->page_current->left;
  +  world_pan_center_y = (double) w_current->page_current->bottom -
  +  cy * w_current->page_current->to_world_y_constant;
  +
  +  /* and create the new window*/
  +  a_pan_general(w_current, world_pan_center_x, world_pan_center_y,
  +                relativ_zoom_factor, pan_flags);	
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void a_zoom_box_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  int box_left, box_top;
  +  int box_width, box_height;
  +
  +  box_left = w_current->last_x = w_current->start_x = x;
  +  box_top  = w_current->last_y = w_current->start_y = y;
  +  box_width  = 0;
  +  box_height = 0;
  +
  +  /* draw the box (1st XOR) */
  +  XOR_SETUP(w_current);
  +  XOR_DRAW_BOX(w_current, box_left, box_top, box_width, box_height);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void a_zoom_box_end(TOPLEVEL *w_current, int x, int y)
  +{
  +  int box_width, box_height;
  +  int box_left, box_top;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  box_width  = GET_BOX_WIDTH (w_current);
  +  box_height = GET_BOX_HEIGHT(w_current);
  +  box_left   = GET_BOX_LEFT  (w_current);
  +  box_top    = GET_BOX_TOP   (w_current);
  +
  +  /* erase the box (2nd XOR) */
  +  XOR_SETUP(w_current);
  +  XOR_DRAW_BOX(w_current, box_left, box_top, box_width, box_height);
  +
  +  a_zoom_box(w_current, 0);
  +  o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void a_zoom_box_rubberband(TOPLEVEL *w_current, int x, int y)
  +{
  +  int box_width, box_height;
  +  int box_left, box_top;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  box_width  = GET_BOX_WIDTH (w_current);
  +  box_height = GET_BOX_HEIGHT(w_current);
  +  box_left   = GET_BOX_LEFT  (w_current);
  +  box_top    = GET_BOX_TOP   (w_current);
  +
  +  /* erase the old box (2nd XOR) */
  +  XOR_SETUP(w_current);
  +  XOR_DRAW_BOX(w_current, box_left, box_top, box_width, box_height);
  +
  +  w_current->last_x = (int) x;
  +  w_current->last_y = (int) y;
  +
  +  box_width  = GET_BOX_WIDTH (w_current);
  +  box_height = GET_BOX_HEIGHT(w_current);
  +  box_left   = GET_BOX_LEFT  (w_current);
  +  box_top    = GET_BOX_TOP   (w_current);
  +
  +  /* draw a new box (1st XOR) */
  +  XOR_DRAW_BOX(w_current, box_left, box_top, box_width, box_height);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void correct_aspect(TOPLEVEL *w_current)
  +{
  +  double new_aspect;
  +
  +  new_aspect = GET_PAGE_ASPECT_RATIO(w_current);
  +
  +  /* Make sure aspect ratio is correct */
  +  if (fabs(new_aspect - w_current->page_current->coord_aspectratio)) {
  +    /* sign was > */
  +    if (new_aspect > w_current->page_current->coord_aspectratio) {
  +#if DEBUG
  +      printf("new larger then coord\n");
  +      printf("implies that height is too large\n");
  +#endif
  +      /* calculate neccesary padding on Y */
  +      w_current->page_current->bottom =
  +        w_current->page_current->top +
  +        GET_PAGE_WIDTH(w_current) /
  +        w_current->page_current->coord_aspectratio;
  +
  +#if 0 /* ER's original zoom extents code */
  +      pad_y = (delta_y -
  +               delta_x *
  +               w_current->page_current->coord_aspectratio) /
  +        2;
  +      /* widening */
  +      w_current->page_current->bottom += pad_y;
  +      w_current->page_current->top    -= pad_y;
  +#endif
  +    } else {
  +#if DEBUG
  +      printf("new smaller then coord\n");
  +      printf("implies that width is too small\n");
  +#endif
  +      /* calculate necessary padding on X */
  +      w_current->page_current->right =
  +        w_current->page_current->left +
  +        GET_PAGE_HEIGHT(w_current) *
  +        w_current->page_current->coord_aspectratio;
  +
  +#if 0 /* ER's original zoom extents code */
  +      pad_x = (delta_x -
  +               delta_y *
  +               w_current->page_current->coord_aspectratio) /
  +        2;
  +      /* shortening */
  +      w_current->page_current->right -= pad_x;
  +      w_current->page_current->left  += pad_x;
  +#endif
  +    }
  +#if DEBUG
  +    printf("invalid aspectratio corrected\n");
  +#endif
  +  }
  +
  +  new_aspect = GET_PAGE_ASPECT_RATIO(w_current);
  +
  +#if DEBUG
  +  printf("final %f\n", new_aspect);
  +#endif
  +
  +#if 0 /* no longer needed to calc zoom_factor */
  +  diff_x = fabs(GET_PAGE_WIDTH(w_current));
  +
  +#ifdef HAS_RINT
  +  zoom_scale = (int) rint(w_current->init_right / diff_x);
  +#else
  +  zoom_scale = (int)     (w_current->init_right / diff_x);
  +#endif
  +
  +  if (zoom_scale > w_current->max_zoom) {
  +    zoom_scale = w_current->max_zoom;
  +  }
  +  if (zoom_scale < w_current->min_zoom) {
  +    zoom_scale = w_current->min_zoom;
  +  }
  +  w_current->page_current->zoom_factor = zoom_scale;
  +#endif
  +}
  
  
  
  1.18      +265 -123  eda/geda/gaf/gschem/src/g_funcs.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: g_funcs.c
  ===================================================================
  RCS file: g_funcs.c
  diff -N g_funcs.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ g_funcs.c	14 Jul 2006 02:23:54 -0000	1.18
  @@ -0,0 +1,347 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/stat.h>
  +#include <ctype.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +#include "../include/x_dialog.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_print(SCM filename)
  +{
  +  SCM_ASSERT (SCM_NIMP (filename) && SCM_STRINGP (filename), filename,
  +              SCM_ARG1, "gschem-print");
  +
  +  if (output_filename) {
  +    f_print (global_window_current, output_filename);
  +  } else  {
  +    f_print (global_window_current, SCM_STRING_CHARS (filename));
  +  }
  +  
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_image(SCM filename)
  +{
  +  SCM_ASSERT (SCM_NIMP (filename) && SCM_STRINGP (filename), filename,
  +              SCM_ARG1, "gschem-image");
  +
  +  if (output_filename) {
  +    x_image_lowlevel (global_window_current, output_filename);
  +  } else  {
  +    x_image_lowlevel (global_window_current, SCM_STRING_CHARS (filename));
  +  }
  +  
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_exit(void)
  +{
  +  exit(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_log(SCM msg)
  +{
  +
  +  SCM_ASSERT (SCM_NIMP (msg) && SCM_STRINGP (msg), msg,
  +              SCM_ARG1, "gschem-log");
  +
  +  s_log_message (SCM_STRING_CHARS (msg));
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_msg(SCM msg)
  +{
  +
  +  SCM_ASSERT (SCM_NIMP (msg) && SCM_STRINGP (msg), msg,
  +              SCM_ARG1, "gschem-msg");
  +
  +  generic_msg_dialog (SCM_STRING_CHARS (msg));
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_confirm(SCM msg)
  +{
  +  int r;
  +
  +  SCM_ASSERT (SCM_NIMP (msg) && SCM_STRINGP (msg), msg,
  +	      SCM_ARG1, "gschem-msg");
  +  
  +  r = generic_confirm_dialog (SCM_STRING_CHARS (msg));
  +
  +  if (r)
  +    return SCM_BOOL_T;
  +  else
  +    return SCM_BOOL_F;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_filesel(SCM msg, SCM templ, SCM flags)
  +{
  +  int c_flags;
  +  char * r;
  +  SCM v;
  +
  +  SCM_ASSERT (SCM_NIMP (msg) && SCM_STRINGP (msg), msg,
  +	      SCM_ARG1, "gschem-filesel");
  +  
  +  SCM_ASSERT (SCM_NIMP (templ) && SCM_STRINGP (templ), templ,
  +	      SCM_ARG1, "gschem-filesel");
  +  
  +  /*! \bug FIXME -- figure out the magic SCM_ASSERT for the flags */
  +
  +  /*! \bug FIXME -- how to deal with conflicting flags? 
  +   * Should I throw a scheme error?  Just deal in the c code?
  +   */
  +  for (c_flags = 0; scm_pair_p (flags) == SCM_BOOL_T; flags = SCM_CDR (flags)) {
  +    SCM f = SCM_CAR (flags);
  +    if (strcmp (SCM_STRING_CHARS (f), "may_exist") == 0) {
  +      c_flags |= FSB_MAY_EXIST;
  +
  +    } else if (strcmp (SCM_STRING_CHARS (f), "must_exist") == 0) {
  +      c_flags |= FSB_MUST_EXIST;
  +      
  +    } else if (strcmp (SCM_STRING_CHARS (f), "must_not_exist") == 0) {
  +      c_flags |= FSB_SHOULD_NOT_EXIST;
  +
  +    } else if (strcmp (SCM_STRING_CHARS (f), "save") == 0) {
  +      c_flags |= FSB_SAVE;
  +
  +    } else if (strcmp (SCM_STRING_CHARS (f), "open") == 0) {
  +      c_flags |= FSB_LOAD;
  +
  +    } else {
  +      scm_wrong_type_arg ("gschem-filesel", 1, f);
  +    }
  +  }
  +
  +  r = generic_filesel_dialog (SCM_STRING_CHARS (msg),
  +			      SCM_STRING_CHARS (templ),
  +			      c_flags
  +			      );
  +
  +  v = scm_makfrom0str (r);
  +  g_free (r);
  +
  +  return v;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_use_rc_values(void)
  +{
  +  i_vars_set(global_window_current);
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \brief */
  +static gchar *key_value_string = NULL;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \bug there is no string size checking here... so if it core dumps... DOH!
  + *  it's actually pretty usable right now, but needs to be reviewed again
  + */
  +SCM g_funcs_key_name(SCM keystring)
  +{
  +  SCM_ASSERT (SCM_STRINGP (keystring), keystring, 1, "gschem-key-name");
  +
  +  if (key_value_string != NULL) {
  +    x_dialog_hotkeys_fill (key_value_string);
  +    g_free (key_value_string); 
  +    key_value_string = NULL;
  +  }
  +
  +  /* the 25 is for a few spaces and the characters */
  +  key_value_string = g_strdup_printf ("%s :%25c",
  +                                      SCM_STRING_CHARS (keystring), ' ');
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_key_value(SCM keystring)
  +{
  +  gchar *temp;
  +
  +  SCM_ASSERT (SCM_STRINGP (keystring), keystring, 1, "gschem-key-value");
  +
  +  if (key_value_string == NULL) {
  +    fprintf(stderr, _("Ack! something got fouled up with the keymappings!\n"));
  +    exit(-1);
  +  }
  +
  +  temp = g_strdup_printf ("%s %s",
  +                          key_value_string,
  +                          SCM_STRING_CHARS (keystring));
  +  g_free (key_value_string);
  +  key_value_string = temp;
  +	
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_funcs_key_done(void)
  +{
  +  x_dialog_hotkeys_fill (key_value_string);
  +  g_free(key_value_string);
  +  key_value_string = NULL;
  +  return SCM_BOOL_T;
  +}
  +
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*
  + * Gets names from all objects of current page which selected-flags are true.
  + */
  +/* all of the declaration part is copied from some other c-code of
  + * gEDA gschem. 
  + * I don't really know, whether this all are necessary or not, but 
  + * it works :-). */
  +static void
  +hash_table_2_list (gpointer key,
  +                   gpointer value,
  +                   gpointer user_data)
  +{
  +  SCM *plist = (SCM*)user_data;
  +  *plist = scm_cons (scm_makfrom0str ((char*)value), *plist);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM get_selected_component_attributes(TOPLEVEL *toplevel)
  +{
  +  SCM list = SCM_EOL;
  +  OBJECT *obj;
  +  GHashTable *ht;
  + 
  +  /* build a hash table */
  +  ht = g_hash_table_new (g_str_hash, g_str_equal);
  +  for (obj = toplevel->page_current->object_head; obj != NULL;
  +       obj = obj->next) {
  +    if (obj->selected &&
  +        obj->type == OBJ_TEXT &&
  +        obj->text->string != NULL) {
  +      /* add text string in the hash table */
  +      g_hash_table_insert (ht,
  +                           obj->text->string,
  +                           obj->text->string);
  +     }
  +   }
  +  /* now create a scheme list of the entries in the hash table */
  +  g_hash_table_foreach (ht, hash_table_2_list, &list);
  +  /* and get ride of the hast table */
  +  g_hash_table_destroy (ht);
  +
  +  return list;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Get selected filename of current schematic.
  + *  \par Function Description
  + *  This function gets the whole filename of the current schematic.
  + *  Specifically, the <B>page_filename</B> of the current page.
  + *
  + *  \param [in] w_current  The TOPLEVEL object to get filename from.
  + *  \return whole filename of current schematic.
  + */
  +SCM get_selected_filename(TOPLEVEL *w_current)
  +{
  +  SCM return_value;
  +  
  +  exit_if_null(w_current);
  +  
  +  return_value = scm_take0str (w_current->page_current->page_filename);
  +
  +  return(return_value);
  +}
  
  
  
  1.4       +409 -54   eda/geda/gaf/gschem/src/g_hook.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: g_hook.c
  ===================================================================
  RCS file: g_hook.c
  diff -N g_hook.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ g_hook.c	14 Jul 2006 02:23:54 -0000	1.4
  @@ -0,0 +1,453 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Makes a list of all attributes currently connected to curr_object. *
  + * Principle stolen from o_attrib_return_attribs */
  +SCM g_make_attrib_smob_list(TOPLEVEL *curr_w, OBJECT *curr_object)
  +{
  +  ATTRIB *a_current;      
  +  OBJECT *object;
  +  SCM smob_list = SCM_EOL;
  +
  +  object = (OBJECT *) o_list_search(curr_object, curr_object);
  +
  +  if (!object) {
  +    return(SCM_EOL);   
  +  }
  +
  +  if (!object->attribs) {
  +    return(SCM_EOL);
  +  }
  +
  +  if (!object->attribs->next) {
  +    return(SCM_EOL);
  +  }
  +
  +  /* go through attribs */
  +  a_current = object->attribs->next;      
  +  while(a_current != NULL) {
  +    if (a_current->object->type == OBJ_TEXT && 
  +        a_current->object->text) {
  +      if (a_current->object->text->string) {
  +        smob_list = scm_cons (g_make_attrib_smob (curr_w, a_current), 
  +                              smob_list);
  +      }
  +    } else {
  +      printf(_("Attribute failed ot find.\n"));
  +    }
  +    a_current = a_current->next;
  +  }
  +
  +  return smob_list;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/**************************************************************************
  + * This function partly part of libgeda, since it belongs to the smob     *
  + * definition. But since I use o_text_change, which is defined in gschem, *
  + * we have to do it like this.                                            *
  + **************************************************************************/
  +SCM g_set_attrib_value_x(SCM attrib_smob, SCM scm_value)
  +{
  +  SCM returned;
  +  TOPLEVEL *world;
  +  OBJECT *o_attrib;
  +  char *new_string;
  +
  +  returned = g_set_attrib_value_internal(attrib_smob, scm_value, 
  +                                         &world, &o_attrib, &new_string);
  +
  +  o_text_change(world, o_attrib, new_string, o_attrib->visibility, o_attrib->show_name_value);
  +
  +  free(new_string);
  +
  +  return returned;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*
  + * Adds an attribute <B>scm_attrib_name</B> with value <B>scm_attrib_value</B> to the given <B>object</B>.
  +The attribute has the visibility <B>scm_vis</B> and show <B>scm_show</B> flags.
  +The possible values are:
  +  - <B>scm_vis</B>: scheme boolean. Visible (TRUE) or hidden (FALSE).
  +  - <B>scm_show</B>: a list containing what to show: "name", "value", or both.
  +The return value is always TRUE.
  + */
  +SCM g_add_attrib(SCM object, SCM scm_attrib_name, 
  +		 SCM scm_attrib_value, SCM scm_vis, SCM scm_show)
  +{
  +  TOPLEVEL *w_current=NULL; 
  +  OBJECT *o_current=NULL;
  +  gboolean vis;
  +  int show=0;
  +  gchar *attrib_name=NULL;
  +  gchar *attrib_value=NULL;
  +  gchar *value=NULL;
  +  int i;
  +  gchar *newtext=NULL;
  +
  +  SCM_ASSERT (SCM_STRINGP(scm_attrib_name), scm_attrib_name,
  +	      SCM_ARG2, "add-attribute-to-object");
  +  SCM_ASSERT (SCM_STRINGP(scm_attrib_value), scm_attrib_value,
  +	      SCM_ARG3, "add-attribute-to-object");
  +  SCM_ASSERT (scm_boolean_p(scm_vis), scm_vis,
  +	      SCM_ARG4, "add-attribute-to-object");
  +  SCM_ASSERT (scm_list_p(scm_show), scm_show,
  +	      SCM_ARG5, "add-attribute-to-object");
  +  
  +  /* Get w_current and o_current */
  +  SCM_ASSERT (g_get_data_from_object_smob (object, &w_current, &o_current),
  +	      object, SCM_ARG1, "add-attribute-to-object");
  +
  +  /* Get parameters */
  +  attrib_name = SCM_STRING_CHARS(scm_attrib_name);
  +  attrib_value = SCM_STRING_CHARS(scm_attrib_value);
  +  vis = SCM_NFALSEP(scm_vis);
  +
  +  for (i=0; i<=SCM_INUM(scm_length(scm_show))-1; i++) {
  +    value = SCM_STRING_CHARS(scm_list_ref(scm_show, SCM_MAKINUM(i)));
  +    SCM_ASSERT(!((strcasecmp(value, "name") != 0) &&
  +		 (strcasecmp(value, "value") != 0) ), scm_show,
  +	       SCM_ARG5, "add-attribute-to-object"); 
  +    /* show = 1 => show value; 
  +       show = 2 => show name; 
  +       show = 3 => show both */
  +    if (strcasecmp(value, "value") == 0) {
  +      show |= 1;
  +    }
  +    else if (strcasecmp(value, "name") == 0) {
  +      show |= 2;
  +    }	  
  +  }
  +  /* Show name and value (show = 3) => show=0 for gschem */
  +  if (show == 3) {
  +    show = 0;
  +  }
  +  
  +  newtext = g_strdup_printf("%s=%s", attrib_name, attrib_value);
  +  o_attrib_add_attrib (w_current, newtext, vis, show, o_current);
  +  g_free(newtext);
  +
  +  return SCM_BOOL_T;
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*
  + * Returns a list with coords of the ends of  the given pin <B>object</B>.
  +The list is ( (x0 y0) (x1 y1) ), where the beginning is at (x0,y0) and the end at (x1,y1). 
  +The active connection end of the pin is the beginning, so this function cares about the whichend property of the pin object. If whichend is 1, then it has to reverse the ends.
  + */
  +SCM g_get_pin_ends(SCM object)
  +{
  +  TOPLEVEL *w_current;
  +  OBJECT *o_current;
  +  SCM coord1 = SCM_EOL;
  +  SCM coord2 = SCM_EOL;
  +  SCM coords = SCM_EOL;
  +
  +  /* Get w_current and o_current */
  +  SCM_ASSERT (g_get_data_from_object_smob (object, &w_current, &o_current),
  +	      object, SCM_ARG1, "get-pin-ends");
  +  
  +  /* Check that it is a pin object */
  +  SCM_ASSERT (o_current != NULL,
  +	      object, SCM_ARG1, "get-pin-ends");
  +  SCM_ASSERT (o_current->type == OBJ_PIN,
  +	      object, SCM_ARG1, "get-pin-ends");
  +  SCM_ASSERT (o_current->line != NULL,
  +	      object, SCM_ARG1, "get-pin-ends");
  +
  +  coord1 = scm_cons(SCM_MAKINUM(o_current->line->x[0]), 
  +		    SCM_MAKINUM(o_current->line->y[0]));
  +  coord2 = scm_cons(SCM_MAKINUM(o_current->line->x[1]),
  +		    SCM_MAKINUM(o_current->line->y[1]));
  +  if (o_current->whichend == 0) {
  +    coords = scm_cons(coord1, scm_list(coord2));
  +  } else {
  +    coords = scm_cons(coord2, scm_list(coord1));
  +  }    
  +		     
  +  return coords;  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*
  + * Sets several text properties of the given <B>attribute smob</B>:
  +  - <B>colorname</B>: The colorname of the text, or "" to keep previous color.
  +  - <B>size</B>: Size (numeric) of the text, or -1 to keep the previous size.
  +  - <B>alignment</B>: String with the alignment of the text. Possible values are:
  +    * ""           : Keep the previous alignment.
  +    * "Lower Left"
  +    * "Middle Left"
  +    * "Upper Left"
  +    * "Lower Middle"
  +    * "Middle Middle"
  +    * "Upper Middle"
  +    * "Lower Right"
  +    * "Middle Right"
  +    * "Upper Right"
  +  - <B>rotation</B>: Angle of the text, or -1 to keep previous angle.
  +  - <B>x</B>, <B>y</B>: Coords of the text.
  + */
  +SCM g_set_attrib_text_properties(SCM attrib_smob, SCM scm_colorname,
  +				 SCM scm_size, SCM scm_alignment,
  +				 SCM scm_rotation, SCM scm_x, SCM scm_y)
  +{
  +  struct st_attrib_smob *attribute = 
  +  (struct st_attrib_smob *)SCM_CDR(attrib_smob);
  +  OBJECT *object;
  +  TOPLEVEL *w_current = (TOPLEVEL *) attribute->world;
  +
  +  char *colorname=NULL;
  +  int color=0;
  +  int size = -1;
  +  char *alignment_string;
  +  int alignment = -2;
  +  int rotation = 0;
  +  int x = -1, y = -1;
  +  gboolean changed = FALSE;
  +
  +  SCM_ASSERT (SCM_STRINGP(scm_colorname), scm_colorname,
  +	      SCM_ARG2, "set-attribute-text-properties!");
  +  SCM_ASSERT ( SCM_INUMP(scm_size),
  +               scm_size, SCM_ARG3, "set-attribute-text-properties!");
  +  SCM_ASSERT (SCM_STRINGP(scm_alignment), scm_alignment,
  +	      SCM_ARG4, "set-attribute-text-properties!");
  +  SCM_ASSERT ( SCM_INUMP(scm_rotation),
  +               scm_rotation, SCM_ARG5, "set-attribute-text-properties!");
  +  SCM_ASSERT ( SCM_INUMP(scm_x),
  +               scm_x, SCM_ARG6, "set-attribute-text-properties!");
  +  SCM_ASSERT ( SCM_INUMP(scm_y),
  +               scm_y, SCM_ARG7, "set-attribute-text-properties!");
  +
  +  colorname = SCM_STRING_CHARS(scm_colorname);
  +
  +  if (colorname && strlen(colorname) != 0) {
  +    SCM_ASSERT ( (color = s_color_get_index(colorname)) != -1,
  +		 scm_colorname, SCM_ARG2, "set-attribute-text-properties!");
  +  }
  +  else {
  +    color = -1;
  +  }
  +  
  +  size = SCM_INUM(scm_size);
  +  rotation = SCM_INUM(scm_rotation);
  +  x = SCM_INUM(scm_x);
  +  y = SCM_INUM(scm_y);
  +  
  +  alignment_string = SCM_STRING_CHARS(scm_alignment);
  +
  +  if (strlen(alignment_string) == 0) {
  +    alignment = -1;
  +  }
  +  if (strcmp(alignment_string, "Lower Left") == 0) {
  +    alignment = 0;
  +  }
  +  if (strcmp(alignment_string, "Middle Left") == 0) {
  +    alignment = 1;
  +  }
  +  if (strcmp(alignment_string, "Upper Left") == 0) {
  +    alignment = 2;
  +  }
  +  if (strcmp(alignment_string, "Lower Middle") == 0) {
  +    alignment = 3;
  +  }
  +  if (strcmp(alignment_string, "Middle Middle") == 0) {
  +    alignment = 4;
  +  }
  +  if (strcmp(alignment_string, "Upper Middle") == 0) {
  +    alignment = 5;
  +  }
  +  if (strcmp(alignment_string, "Lower Right") == 0) {
  +    alignment = 6;
  +  }
  +  if (strcmp(alignment_string, "Middle Right") == 0) {
  +    alignment = 7;
  +  }
  +  if (strcmp(alignment_string, "Upper Right") == 0) {
  +    alignment = 8;
  +  }
  +  if (alignment == -2) {
  +    /* Bad specified */
  +    SCM_ASSERT (SCM_STRINGP(scm_alignment), scm_alignment,
  +		SCM_ARG4, "set-attribute-text-properties!");
  +  }
  +
  +  if (attribute &&
  +      attribute->attribute &&
  +      attribute->attribute->object) {
  +    object = (OBJECT *) attribute->attribute->object;
  +    if (object &&
  +	object->text) {
  +      o_text_erase(w_current, object);
  +      if (x != -1) {
  +	object->text->x = x;
  +	changed = TRUE;
  +      }
  +      if (y != -1) {
  +	object->text->y = y;
  +	changed = TRUE;
  +      }
  +      if (changed) {
  +	WORLDtoSCREEN(w_current, x, y, &object->text->screen_x, &object->text->screen_y);
  +      }
  +      if (size != -1) {
  +	object->text->size = size;
  +	changed = TRUE;
  +      }
  +      if (alignment != -1) {
  +	object->text->alignment = alignment;
  +	changed = TRUE;
  +      }
  +      if (rotation != -1) {
  +	object->text->angle = rotation;
  +	changed = TRUE;
  +      }
  +      o_text_recreate(w_current, object);
  +      if (!w_current->DONT_REDRAW) {
  +	o_text_draw(w_current, object);
  +      }
  +    }
  +  }
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*! \bug FIXME
  + *  Returns a list of the bounds of the <B>object smob</B>. 
  + *  The list has the format: ( (left right) (top bottom) )
  + *  I got top and bottom values reversed from world_get_complex_bounds,
  + *  so don\'t rely on the position in the list. 
  + */
  +SCM g_get_object_bounds (SCM object_smob, SCM scm_inc_attribs)
  +{
  +  TOPLEVEL *w_current=NULL;
  +  OBJECT *object=NULL;
  +  int left=0, right=0, bottom=0, top=0; 
  +  SCM returned = SCM_EOL;
  +  SCM vertical = SCM_EOL;
  +  SCM horizontal = SCM_EOL;
  +  OBJECT *new_object = NULL;
  +  gboolean include_attribs;
  +
  +  SCM_ASSERT (scm_boolean_p(scm_inc_attribs), scm_inc_attribs,
  +	      SCM_ARG2, "get-object-bounds");
  +  include_attribs = SCM_NFALSEP(scm_inc_attribs);
  +
  +  /* Get w_current and o_current */
  +  SCM_ASSERT (g_get_data_from_object_smob (object_smob, &w_current, &object),
  +	      object_smob, SCM_ARG1, "get-object-bounds");
  +
  +  if (!include_attribs) {
  +    new_object = (OBJECT *) malloc(sizeof(OBJECT));
  +    memcpy (new_object, object, sizeof(OBJECT));
  +    new_object->attribs = NULL;
  +    new_object->next = NULL;
  +    new_object->prev = NULL;
  +  }
  +  else { 
  +    new_object = object;
  +  } 
  +    
  +  world_get_complex_bounds (w_current, new_object, 
  +			    &left, &top, &right, &bottom);
  +  
  +  if (!include_attribs) {
  +    /* Free the newly created object */
  +    g_free(new_object);
  +  }
  +  
  +  horizontal = scm_cons (SCM_MAKINUM(left), SCM_MAKINUM(right));
  +  vertical = scm_cons (SCM_MAKINUM(top), SCM_MAKINUM(bottom));
  +  returned = scm_cons (horizontal, vertical);
  +  return (returned);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*
  + *Returns a list of the pins of the <B>object smob</B>.
  + */
  +SCM g_get_object_pins (SCM object_smob)
  +{
  +  TOPLEVEL *w_current=NULL;
  +  OBJECT *object=NULL;
  +  OBJECT *prim_obj;
  +  SCM returned=SCM_EOL;
  +
  +  /* Get w_current and o_current */
  +  SCM_ASSERT (g_get_data_from_object_smob (object_smob, &w_current, &object),
  +	      object_smob, SCM_ARG1, "get-object-pins");
  +
  +  if (object->complex && object->complex->prim_objs) {
  +    prim_obj = object->complex->prim_objs;
  +    while (prim_obj != NULL) {
  +      if (prim_obj->type == OBJ_PIN) {
  +	returned = scm_cons (g_make_object_smob(w_current, prim_obj),returned);
  +      }
  +      prim_obj = prim_obj->next;
  +    }
  +  }
  +  
  +  return (returned);
  +}
  
  
  
  1.1                  eda/geda/gaf/gschem/src/g_keys.c
  
  Index: g_keys.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * gschem - gEDA Schematic Capture
   * Copyright (C) 1998-2000 Ales V. Hvezda
   *
   * 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 USA
   */
  #include <config.h>
  
  #include <stdio.h>
  #include <sys/stat.h>
  #include <ctype.h>
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  #ifdef HAVE_UNISTD_H
  #include <unistd.h>
  #endif
  
  #include <libgeda/libgeda.h>
  
  #include "../include/globals.h"
  #include "../include/prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void set_window_current_key(TOPLEVEL *w_current)
  {
         /*window_current = w_current;*/
         /* this function is now a nop, remove it */
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  /* for now this only supports single chars, not shift/alt/ctrl etc... */
  void g_keys_execute(int state, int keyval)
  {
    char *guile_string = NULL;
    char *modifier = NULL;
  
    if (keyval == 0) {
      return;
    }
  
    /* don't pass the raw modifier key presses to the guile code */
    if (strstr(gdk_keyval_name(keyval), "Alt")) {
      return;
    }
  
    if (strstr(gdk_keyval_name(keyval), "Shift")) {
      return;
    }
  
    if (strstr(gdk_keyval_name(keyval), "Control")) {
      return;
    }
  
    if (state & GDK_SHIFT_MASK) {
      modifier = g_strdup_printf("\"Shift ");
    } else if (state & GDK_CONTROL_MASK) {
      modifier = g_strdup_printf("\"Control ");
    } else if (state & GDK_MOD1_MASK) {
      modifier = g_strdup_printf("\"Alt ");
    } else {
      modifier = g_strdup_printf("\"");
    }
  
    guile_string = g_strdup_printf("(press-key %s%s\")",
  				 modifier, gdk_keyval_name (keyval));
  
  #if DEBUG 
    printf("_%s_\n", guile_string);
  #endif
    scm_c_eval_string (guile_string);
    free(guile_string);
    free(modifier);
  
  #if 0 /* playing with thi's guile stuff */
    gh_eval_str("(display (reverse last-command-sequence))");
    printf("\n");
  #endif
  }
  
  /*! \brief
   *
   */
  #define DEFINE_G_KEYS(name)				\
  SCM g_keys_ ## name(void)				\
  {							\
  	i_callback_ ## name(global_window_current, 0, NULL);	\
  	return SCM_BOOL_T;				\
  }
  
  /*! \brief test-comment
   * test-comment
   */
  DEFINE_G_KEYS(file_new)
  
  DEFINE_G_KEYS(file_new_window)
  
  /* don't use the widget parameter on this function, or do some checking... */
  /* since there is a call: widget = NULL, data = 0 (will be w_current) */
  /* This should be renamed to page_open perhaps... */
  DEFINE_G_KEYS(file_open)
  
  /* don't use the widget parameter on this function, or do some checking... */
  /* since there is a call: widget = NULL, data = 0 (will be w_current) */
  DEFINE_G_KEYS(file_script)
  
  /* don't use the widget parameter on this function, or do some checking... */
  /* since there is a call: widget = NULL, data = 0 (will be w_current) */
  DEFINE_G_KEYS(file_save)
  DEFINE_G_KEYS(file_save_as)
  DEFINE_G_KEYS(file_save_all)
  DEFINE_G_KEYS(file_print)
  DEFINE_G_KEYS(file_write_png)
  
  /* don't use the widget parameter on this function, or do some checking... */
  /* since there is a call: widget = NULL, data = 0 (will be w_current) */
  /* this function closes a window */
  DEFINE_G_KEYS(file_close)
  DEFINE_G_KEYS(file_quit)
  
  /* Select also does not update the middle button shortcut */
  DEFINE_G_KEYS(edit_undo)
  DEFINE_G_KEYS(edit_redo)
  DEFINE_G_KEYS(edit_select)
  DEFINE_G_KEYS(edit_copy)
  DEFINE_G_KEYS(edit_copy_hotkey)
  DEFINE_G_KEYS(edit_mcopy)
  DEFINE_G_KEYS(edit_mcopy_hotkey)
  DEFINE_G_KEYS(edit_move)
  DEFINE_G_KEYS(edit_move_hotkey)
  DEFINE_G_KEYS(edit_delete)
  DEFINE_G_KEYS(edit_rotate_90)
  DEFINE_G_KEYS(edit_rotate_90_hotkey)
  DEFINE_G_KEYS(edit_mirror)
  DEFINE_G_KEYS(edit_mirror_hotkey)
  #if 0 /* obsolete */
  DEFINE_G_KEYS(edit_stretch)
  DEFINE_G_KEYS(edit_stretch_hotkey)
  #endif
  DEFINE_G_KEYS(edit_slot)
  DEFINE_G_KEYS(edit_color)
  DEFINE_G_KEYS(edit_edit)
  DEFINE_G_KEYS(edit_text)
  DEFINE_G_KEYS(edit_lock)
  DEFINE_G_KEYS(edit_unlock)
  DEFINE_G_KEYS(edit_linetype)
  DEFINE_G_KEYS(edit_filltype)
  DEFINE_G_KEYS(edit_translate)
  DEFINE_G_KEYS(edit_embed)
  DEFINE_G_KEYS(edit_unembed)
  DEFINE_G_KEYS(edit_update)
  DEFINE_G_KEYS(edit_show_hidden)
  DEFINE_G_KEYS(edit_make_visible)
  DEFINE_G_KEYS(edit_find)
  DEFINE_G_KEYS(edit_show_text)
  DEFINE_G_KEYS(edit_hide_text)
  DEFINE_G_KEYS(edit_autonumber_text)
  
  DEFINE_G_KEYS(buffer_copy1)
  DEFINE_G_KEYS(buffer_copy2)
  DEFINE_G_KEYS(buffer_copy3)
  DEFINE_G_KEYS(buffer_copy4)
  DEFINE_G_KEYS(buffer_copy5)
  DEFINE_G_KEYS(buffer_cut1)
  DEFINE_G_KEYS(buffer_cut2)
  DEFINE_G_KEYS(buffer_cut3)
  DEFINE_G_KEYS(buffer_cut4)
  DEFINE_G_KEYS(buffer_cut5)
  DEFINE_G_KEYS(buffer_paste1)
  DEFINE_G_KEYS(buffer_paste2)
  DEFINE_G_KEYS(buffer_paste3)
  DEFINE_G_KEYS(buffer_paste4)
  DEFINE_G_KEYS(buffer_paste5)
  DEFINE_G_KEYS(buffer_paste1_hotkey)
  DEFINE_G_KEYS(buffer_paste2_hotkey)
  DEFINE_G_KEYS(buffer_paste3_hotkey)
  DEFINE_G_KEYS(buffer_paste4_hotkey)
  DEFINE_G_KEYS(buffer_paste5_hotkey)
  
  /* repeat middle shortcut doesn't make sense on redraw, just hit right
   * button */
  DEFINE_G_KEYS(view_redraw)
  
  /* for these functions, repeat middle shortcut would get into the way
   * of what user is try to do */
  DEFINE_G_KEYS(view_zoom_full)
  DEFINE_G_KEYS(view_zoom_extents)
  DEFINE_G_KEYS(view_zoom_in)
  DEFINE_G_KEYS(view_zoom_out)
  DEFINE_G_KEYS(view_zoom_in_hotkey)
  DEFINE_G_KEYS(view_zoom_out_hotkey)
  
  DEFINE_G_KEYS(view_zoom_box)
  DEFINE_G_KEYS(view_zoom_box_hotkey)
  DEFINE_G_KEYS(view_pan)
  DEFINE_G_KEYS(view_pan_hotkey)
  DEFINE_G_KEYS(view_update_cues)
  DEFINE_G_KEYS(page_manager)
  DEFINE_G_KEYS(page_next)
  DEFINE_G_KEYS(page_prev)
  DEFINE_G_KEYS(page_new)
  DEFINE_G_KEYS(page_close)
  DEFINE_G_KEYS(page_revert)
  DEFINE_G_KEYS(page_discard)
  DEFINE_G_KEYS(page_print)
  DEFINE_G_KEYS(add_component)
  DEFINE_G_KEYS(add_attribute)
  DEFINE_G_KEYS(add_attribute_hotkey)
  DEFINE_G_KEYS(add_net)
  DEFINE_G_KEYS(add_net_hotkey)
  DEFINE_G_KEYS(add_bus)
  DEFINE_G_KEYS(add_bus_hotkey)
  DEFINE_G_KEYS(add_text)
  DEFINE_G_KEYS(add_line)
  DEFINE_G_KEYS(add_line_hotkey)
  DEFINE_G_KEYS(add_box)
  DEFINE_G_KEYS(add_box_hotkey)
  DEFINE_G_KEYS(add_picture)
  DEFINE_G_KEYS(add_picture_hotkey)
  DEFINE_G_KEYS(add_circle)
  DEFINE_G_KEYS(add_circle_hotkey)
  DEFINE_G_KEYS(add_arc)
  DEFINE_G_KEYS(add_arc_hotkey)
  DEFINE_G_KEYS(add_pin)
  DEFINE_G_KEYS(add_pin_hotkey)
  DEFINE_G_KEYS(hierarchy_down_schematic)
  DEFINE_G_KEYS(hierarchy_down_symbol)
  DEFINE_G_KEYS(hierarchy_up)
  DEFINE_G_KEYS(hierarchy_documentation)
  DEFINE_G_KEYS(attributes_attach)
  DEFINE_G_KEYS(attributes_detach)
  DEFINE_G_KEYS(attributes_show_name)
  DEFINE_G_KEYS(attributes_show_value)
  DEFINE_G_KEYS(attributes_show_both)
  DEFINE_G_KEYS(attributes_visibility_toggle)
  
  /* i_callback_script_console is not currently implemented */
  DEFINE_G_KEYS(script_console)
  
  /* repeat last command doesn't make sense on options either??? (does
   * it?) */
  DEFINE_G_KEYS(options_text_size)
  
  /* repeat last command doesn't make sense on options either??? (does
   * it?) */
  DEFINE_G_KEYS(options_afeedback)
  DEFINE_G_KEYS(options_grid)
  DEFINE_G_KEYS(options_snap)
  DEFINE_G_KEYS(options_snap_size)
  DEFINE_G_KEYS(options_rubberband)
  DEFINE_G_KEYS(options_show_log_window)
  DEFINE_G_KEYS(options_show_coord_window)
  DEFINE_G_KEYS(misc)
  DEFINE_G_KEYS(misc2)
  DEFINE_G_KEYS(misc3)
  
  DEFINE_G_KEYS(help_about)
  DEFINE_G_KEYS(help_manual)
  DEFINE_G_KEYS(help_hotkeys)
  
  /* be sure that you don't use the widget parameter in this one, since it is
  being called with a null, I suppose we should call it with the right param.
  hack */
  DEFINE_G_KEYS(cancel)
  
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  /*help for generate-netlist hot key*/
  SCM g_get_selected_filename(void)                     
  {                                                     
  	return (get_selected_filename(global_window_current));
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  SCM g_get_selected_component_attributes(void)                 
  {
    return (get_selected_component_attributes(global_window_current));
  }
  
  
  
  1.35      +1506 -1441eda/geda/gaf/gschem/src/g_rc.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: g_rc.c
  ===================================================================
  RCS file: g_rc.c
  diff -N g_rc.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ g_rc.c	14 Jul 2006 02:23:54 -0000	1.35
  @@ -0,0 +1,1664 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/stat.h>
  +#include <ctype.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_DIRENT_H
  +#include <dirent.h>
  +#endif
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/i_vars.h"
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define RETURN_G_RC_MODE(rc, var, size) \
  +  return g_rc_mode_general(mode,        \
  +                           (rc),        \
  +                           &(var),      \
  +                           mode_table,  \
  +                           size)
  +
  +/*! a random int, used only as a place holder */
  +int default_dummy;
  +
  +/*! \brief */
  +typedef struct {
  +  int   m_val;
  +  char *m_str;
  +} vstbl_entry;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void g_rc_parse_gtkrc()
  +{
  +  gchar *filename;
  +  const gchar *home;
  +
  +  filename = g_strconcat (g_rc_parse_path (),
  +                          G_DIR_SEPARATOR_S,
  +                          "gschem-gtkrc",
  +                          NULL);
  +  gtk_rc_parse (filename);
  +  g_free (filename);
  +  
  +  home = g_getenv ("HOME");
  +  if (home != NULL) {
  +    filename = g_strconcat (home,
  +                            G_DIR_SEPARATOR_S,
  +                            ".gschem-gtkrc",
  +                            NULL);
  +    gtk_rc_parse (filename);
  +    g_free (filename);
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_gschem_version(SCM version)
  +{
  +  SCM ret;
  +  
  +  SCM_ASSERT (SCM_NIMP (version) && SCM_STRINGP (version), version,
  +              SCM_ARG1, "gschem-version");
  +
  +  if (g_strcasecmp (SCM_STRING_CHARS (version), VERSION) != 0) {
  +    fprintf(stderr,
  +            _("Found a version [%s] gschemrc file:\n[%s]\n"),
  +            SCM_STRING_CHARS (version), rc_filename);
  +    fprintf(stderr,
  +            _("While gschem is in ALPHA, "
  +            "please be sure that you have the latest rc file.\n"));
  +    ret = SCM_BOOL_F;
  +  } else {
  +    ret = SCM_BOOL_T;
  +  }
  +
  +  return ret;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief General color setting function
  + *  \par Function Description
  + *
  + */
  +static SCM g_rc_color_general(SCM index, SCM color, SCM outline_color, 
  +			      SCM ps_color, SCM ir, SCM ig, SCM ib,
  +			      const char *rc_name, int *color_var)
  +{
  +  int status;
  +  int color_index;
  +  char *color_name;
  +  char *outline_color_name;
  +  char *ps_color_string;
  +  int image_red;
  +  int image_green;
  +  int image_blue;
  +  SCM ret;
  +
  +  SCM_ASSERT (SCM_INUMP (index),   index, SCM_ARG1, rc_name);
  +  SCM_ASSERT (SCM_STRINGP (color), color, SCM_ARG2, rc_name);
  +  SCM_ASSERT (SCM_NIMP (outline_color) && SCM_STRINGP (outline_color),
  +              outline_color, SCM_ARG3, rc_name);
  +  SCM_ASSERT (SCM_NIMP (ps_color) && SCM_STRINGP (ps_color), ps_color,
  +              SCM_ARG4, rc_name);
  +  SCM_ASSERT (SCM_INUMP (ir), ir, SCM_ARG5, rc_name);
  +  SCM_ASSERT (SCM_INUMP (ig), ig, SCM_ARG6, rc_name);
  +  SCM_ASSERT (SCM_INUMP (ib), ib, SCM_ARG7, rc_name);
  +
  +  color_index        = SCM_INUM (index);
  +  color_name         = SCM_STRING_CHARS (color);
  +  outline_color_name = SCM_STRING_CHARS (outline_color);
  +  ps_color_string    = SCM_STRING_CHARS (ps_color);
  +  image_red          = SCM_INUM (ir);
  +  image_green        = SCM_INUM (ig);
  +  image_blue         = SCM_INUM (ib);
  +  
  +  status = s_color_request (color_index, color_name, outline_color_name,
  +                            ps_color_string, 
  +                            image_red, image_green, image_blue);
  +
  +#if DEBUG
  +  printf("%d %s %s %s %d %d %d\n", color_index, color_name, 
  +         outline_color_name, ps_color_string,
  +         image_red, image_green, image_blue);
  +#endif
  +
  +  /* invalid color? */
  +  if (status == -1) {
  +    fprintf (stderr,
  +             _("Invalid color [%s] passed to %s\n"),
  +             color_name,
  +             rc_name);
  +    ret = SCM_BOOL_F;
  +  } else {
  +    *color_var = color_index;
  +    ret = SCM_BOOL_T;
  +  }
  +  
  +  return ret;
  +}
  +
  +#define DEFINE_G_RC_COLOR(func, rc, var)                         \
  +SCM func(SCM index, SCM color, SCM outline_color, SCM ps_color,  \
  +         SCM ir, SCM ig, SCM ib)                                 \
  +{                                                                \
  +  return g_rc_color_general(index, color, outline_color,         \
  +                            ps_color, ir, ig, ib, (rc), &(var)); \
  +}
  +
  +DEFINE_G_RC_COLOR(g_rc_override_net_color,
  +		  "override-net-color",
  +		  default_override_net_color)
  +
  +DEFINE_G_RC_COLOR(g_rc_override_bus_color,
  +		  "override-bus-color",
  +		  default_override_bus_color)
  +
  +DEFINE_G_RC_COLOR(g_rc_override_pin_color,
  +		  "override-pin-color",
  +		  default_override_pin_color)
  +
  +DEFINE_G_RC_COLOR(g_rc_attribute_color,
  +		  "attribute-color",
  +		  default_attribute_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_detachedattr_color,
  +		  "detached-attribute-color",
  +		  default_detachattr_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_text_color,
  +		  "text-color",
  +		  default_text_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_net_color,
  +		  "net-color",
  +		  default_net_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_bus_color,
  +		  "bus-color",
  +		  default_bus_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_pin_color,
  +		  "pin-color",
  +		  default_pin_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_graphic_color,
  +		  "graphic-color",
  +		  default_graphic_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_grid_color,
  +		  "grid-color",
  +		  default_grid_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_background_color,
  +		  "background-color",
  +		  default_background_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_select_color,
  +		  "select-color",
  +		  default_select_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_boundingbox_color,
  +		  "boundingbox-color",
  +		  default_bb_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_zoom_box_color,
  +		  "zoom-box-color",
  +		  default_zoom_box_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_net_endpoint_color,
  +		  "net-endpoint-color",
  +		  default_net_endpoint_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_logic_bubble_color,
  +		  "logic-bubble-color",
  +		  default_logic_bubble_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_lock_color,
  +		  "lock-color",
  +		  default_lock_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_output_color_background,
  +		  "output-color-background",
  +		  default_print_color_background);
  +
  +DEFINE_G_RC_COLOR(g_rc_stroke_color,
  +		  "stroke-color",
  +		  default_stroke_color);
  +
  +DEFINE_G_RC_COLOR(g_rc_freestyle_color,
  +		  "freestyle-color",
  +		  default_dummy);
  +
  +#if 0
  +/*! \deprecated Currently unused.
  + *  \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static int vstbl_lookup_val(const vstbl_entry *table, int size, int val)
  +{
  +  int i;
  +
  +  for(i = 0; i < size; i++) {
  +    if(table[i].m_val == val) {
  +      break;
  +    }
  +  }
  +  return i;
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static int vstbl_lookup_str(const vstbl_entry *table,
  +			    int size, const char *str)
  +{
  +  int i;
  +
  +  for(i = 0; i < size; i++) {
  +    if(strcmp(table[i].m_str, str) == 0) {
  +      break;
  +    }
  +  }
  +  return i;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static int vstbl_get_val(const vstbl_entry *table, int index)
  +{
  +  return table[index].m_val;
  +}
  +
  +#if 0
  +/*! \deprecated Currently Unused.
  + *  \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static const char *vstbl_get_str(const vstbl_entry *table, int index)
  +{
  +  return table[index].m_str;
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static SCM g_rc_mode_general(SCM scmmode,
  +			     const char *rc_name,
  +			     int *mode_var,
  +			     const vstbl_entry *table,
  +			     int table_size)
  +{
  +  SCM ret;
  +  int index;
  +  char *mode;
  +
  +  SCM_ASSERT (SCM_NIMP (scmmode) && SCM_STRINGP (scmmode), scmmode,
  +              SCM_ARG1, rc_name);
  +  
  +  mode = SCM_STRING_CHARS (scmmode);
  +  
  +  index = vstbl_lookup_str(table, table_size, mode);
  +  /* no match? */
  +  if(index == table_size) {
  +    fprintf(stderr,
  +            _("Invalid mode [%s] passed to %s\n"),
  +            mode,
  +            rc_name);
  +    ret = SCM_BOOL_F;
  +  } else {
  +    *mode_var = vstbl_get_val(table, index);
  +    ret = SCM_BOOL_T;
  +  }
  +  
  +  return ret;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_net_endpoint_mode(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {FILLEDBOX, "filledbox"}
  +  };
  +
  +  RETURN_G_RC_MODE("net-endpoint-mode",
  +		   default_net_endpoint_mode,
  +		   1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_net_midpoint_mode(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {FILLED, "filled"}
  +  };
  +
  +  RETURN_G_RC_MODE("net-midpoint-mode",
  +		   default_net_midpoint_mode,
  +		   1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_net_style(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {THIN , "thin" },
  +    {THICK, "thick"}
  +  };
  +
  +  RETURN_G_RC_MODE("net-style",
  +		   default_net_style,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_bus_style(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {THIN , "thin" },
  +    {THICK, "thick"}
  +  };
  +
  +  RETURN_G_RC_MODE("bus-style",
  +		   default_bus_style,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_pin_style(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {THIN , "thin" },
  +    {THICK, "thick"}
  +  };
  +
  +  RETURN_G_RC_MODE("pin-style",
  +		   default_pin_style,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_action_feedback_mode(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {OUTLINE    , "outline"   },
  +    {BOUNDINGBOX, "boundingbox"}
  +  };
  +
  +  RETURN_G_RC_MODE("action-feedback-mode",
  +		   default_actionfeedback_mode,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_zoom_with_pan(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE,  "enabled" },
  +    {FALSE, "disabled"}
  +  };
  +
  +  RETURN_G_RC_MODE("zoom-with-pan",
  +		   default_zoom_with_pan,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_text_feedback(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {ALWAYS            , "always"            },
  +    {ONLY_WHEN_READABLE, "only-when-readable"}
  +  };
  +
  +  RETURN_G_RC_MODE("text-feedback",
  +		   default_text_feedback,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_text_display_zoomfactor(SCM zoomfactor)
  +{
  +  int val;
  +  
  +  SCM_ASSERT (SCM_INUMP (zoomfactor), zoomfactor,
  +              SCM_ARG1, "test-display-zoom-factor");
  +
  +  val = SCM_INUM (zoomfactor);
  +  if (val == 0) {
  +    fprintf(stderr,
  +            _("Invalid zoomfactor [%d] passed to %s\n"),
  +            val,
  +            "text-display-zoom-factor");
  +    val = 10; /* absolute default */
  +  }
  +
  +  default_text_display_zoomfactor = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_scrollbar_update(SCM scmmode)
  +{
  +#if 0
  +  char *mode;
  +  GtkUpdateType policy;
  +#endif
  +  SCM ret = SCM_BOOL_T;
  +
  +  SCM_ASSERT (SCM_NIMP (scmmode) && SCM_STRINGP (scmmode), scmmode,
  +              SCM_ARG1, "scrollbar-update");
  +  
  +#if 0
  +  mode = SCM_STRING_CHARS (scmmode);
  +
  +  if (strcmp (mode, "continuous") == 0) {
  +    policy = GTK_UPDATE_CONTINUOUS;
  +    ret = SCM_BOOL_T;
  +  } else if (strcmp (mode, "delayed") == 0) {
  +    policy = GTK_UPDATE_DELAYED
  +    ret = SCM_BOOL_T;
  +  } else {
  +    fprintf(stderr,
  +            _("Invalid mode [%s] passed to scrollbar-update\n"),
  +            mode);
  +    ret = SCM_BOOL_F;
  +  }
  +
  +  if (ret == SCM_BOOL_T) {
  +    gtk_range_set_update_policy (GTK_RANGE (window_current->v_scrollbar),
  +                                 policy);
  +    gtk_range_set_update_policy (GTK_RANGE (window_current->h_scrollbar),
  +                                 policy);
  +  }
  +#endif
  +
  +  return ret;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_object_clipping(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"}
  +  };
  +
  +  RETURN_G_RC_MODE("object-clipping",
  +		   default_object_clipping,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_logging(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"}
  +  };
  +
  +  RETURN_G_RC_MODE("logging",
  +		   default_do_logging,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_embed_components(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"}
  +  };
  +
  +  RETURN_G_RC_MODE("embed-components",
  +		   default_embed_complex,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_text_size(SCM size)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (size), size, SCM_ARG1, "text-size");
  +  
  +  val = SCM_INUM (size);
  +  if (val == 0) {
  +    fprintf(stderr,
  +            _("Invalid size [%d] passed to text-size\n"),
  +            val);
  +    val = 10; /* absolute default */
  +  }
  +
  +  default_text_size = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \todo inconsistant naming with keyword name and variable to hold
  + *        variable
  + */
  +SCM g_rc_text_caps_style(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {LOWER, "lower" },
  +    {UPPER, "upper" },
  +    {BOTH , "both"  }
  +  };
  +
  +  RETURN_G_RC_MODE("text-caps-style",
  +		   default_text_caps,
  +		   3);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_snap_size(SCM size)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (size), size, SCM_ARG1, "snap-size");
  +
  +  val = SCM_INUM (size);
  +  if (val == 0) {
  +    fprintf(stderr, _("Invalid size [%d] passed to snap-size\n"),
  +            val);
  +    val = 100; /* absolute default */
  +  }
  +
  +  default_snap_size = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_logging_destination(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {LOG_WINDOW         , "log_window" },
  +    {STDOUT_TTY         , "tty"        },
  +    {BOTH_LOGWIN_STDOUT , "both"       }
  +  };
  +
  +  RETURN_G_RC_MODE("logging-destination",
  +		   logging_dest,
  +		   3);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_attribute_name(SCM scm_path)
  +{
  +  char *path;
  +  SCM ret;
  +
  +  SCM_ASSERT (SCM_NIMP (scm_path) && SCM_STRINGP (scm_path), scm_path,
  +              SCM_ARG1, "attribute-name");
  +
  +  path = SCM_STRING_CHARS (scm_path);
  +
  +  /* not unique? */
  +  if (!s_attrib_uniq(path)) {
  +    ret = SCM_BOOL_F;
  +  } else {
  +    s_attrib_add_entry (path);
  +    ret = SCM_BOOL_T;
  +  }
  +  
  +  return ret;
  +}
  +
  +#if 0
  +/*! \deprecated Old obsolete way of handling strokes.
  + *  \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_stroke(SCM scm_stroke, SCM scm_guile_func)
  +{
  +  SCM ret;
  +#ifdef HAS_LIBSTROKE
  +  char *stroke;
  +
  +  SCM_ASSERT (SCM_NIMP (scm_stroke) && SCM_STRINGP (scm_stroke), scm_stroke,
  +              SCM_ARG1, "stroke");
  +
  +  stroke = SCM_STRING_CHARS (scm_stroke);
  +
  +  if (!s_stroke_uniq(stroke)) {
  +    if (stroke_info_mode) {
  +      s_log_message(_("Duplicate stroke definition "
  +                    "passed to stroke! [%s]\n"),
  +                    stroke);
  +      printf(_("Duplicate stroke definition "
  +             "passed to stroke! [%s]\n"),
  +             stroke);
  +    }
  +    ret = SCM_BOOL_F;
  +  } else {
  +    s_stroke_add_entry(stroke, scm_guile_func);
  +    ret = SCM_BOOL_T;
  +  }
  +#else
  +  if (stroke_info_mode) {
  +    printf(_("A stroke keyword has been found in an rc file, but gschem\n"
  +           "is not compiled to support strokes, please recompile gschem\n"
  +           "with LibStroke\n"));
  +  }
  +#endif
  +
  +  return ret;
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_scrollbars(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("scrollbars",
  +		   default_scrollbars_flag,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_paper_size(SCM width, SCM height)
  +#define FUNC_NAME "paper-size"
  +{
  +  SCM_ASSERT (SCM_NIMP (width) && SCM_REALP (width), width,
  +              SCM_ARG1, FUNC_NAME);
  +  SCM_ASSERT (SCM_NIMP (height) && SCM_REALP (height), height,
  +              SCM_ARG2, FUNC_NAME);
  +  
  +  /* yes this is legit, we are casting the resulting double to an int */
  +  default_paper_width  = (int) (SCM_NUM2DOUBLE (0, width)  * MILS_PER_INCH);
  +  default_paper_height = (int) (SCM_NUM2DOUBLE (0, height) * MILS_PER_INCH);
  +
  +  return SCM_BOOL_T;
  +}
  +#undef FUNC_NAME
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_paper_sizes(SCM scm_papername, SCM scm_width, SCM scm_height)
  +#define FUNC_NAME "paper-sizes"
  +{
  +  int width;
  +  int height;
  +  char *papername;
  +  SCM ret;
  +
  +  SCM_ASSERT (SCM_STRINGP (scm_papername), scm_papername,
  +              SCM_ARG1, FUNC_NAME);
  +  SCM_ASSERT (SCM_NIMP (scm_width) && SCM_REALP (scm_width), scm_width,
  +              SCM_ARG2, FUNC_NAME);
  +  SCM_ASSERT (SCM_NIMP (scm_height) && SCM_REALP (scm_height), scm_height,
  +              SCM_ARG3, FUNC_NAME);
  +
  +  papername = SCM_STRING_CHARS (scm_papername);
  +  width  = (int) (SCM_NUM2DOUBLE (0, scm_width)  * MILS_PER_INCH);
  +  height = (int) (SCM_NUM2DOUBLE (0, scm_height) * MILS_PER_INCH);
  +
  +  if (!s_papersizes_uniq(papername)) {
  +    ret = SCM_BOOL_F;
  +  } else {
  +    s_papersizes_add_entry(papername, width, height);
  +    ret = SCM_BOOL_T;
  +  }
  +
  +  return ret;
  +}
  +#undef FUNC_NAME
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_output_text(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {VECTOR_FONTS , "vector" },
  +    {PS_FONTS     , "ps"     },
  +  };
  +
  +  RETURN_G_RC_MODE("output-text",
  +		   default_text_output,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \todo this keyword needs a better name ...
  + */
  +SCM g_rc_output_type(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {WINDOW, "current window" },
  +    {EXTENTS, "limits" },  /* deprecated */
  +    {EXTENTS, "extents" },
  +    {EXTENTS_NOMARGINS, "extents no margins" },
  +  };
  +
  +  RETURN_G_RC_MODE("output-type",
  +		   default_print_output_type,
  +		   4);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_output_orientation(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {PORTRAIT , "portrait" },
  +    {LANDSCAPE, "landscape"},
  +  };
  +  
  +  RETURN_G_RC_MODE("output-orientation",
  +		   default_print_orientation,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_image_color(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("image-color",
  +		   default_image_color,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_image_size(SCM width, SCM height)
  +{
  +  SCM_ASSERT (SCM_INUMP (width),  width,  SCM_ARG1, "image-size");
  +  SCM_ASSERT (SCM_INUMP (height), height, SCM_ARG2, "image-size");
  +  
  +  /* yes this is legit, we are casting the resulting double to an int */
  +  default_image_width  = SCM_INUM (width);
  +  default_image_height = SCM_INUM (height);
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_output_color(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  /* this variable is inconsistantly named with the rest */
  +  RETURN_G_RC_MODE("output-color",
  +		   default_print_color,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_output_capstyle(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {BUTT_CAP , "butt" },
  +    {ROUND_CAP , "round" },
  +    {SQUARE_CAP, "square"},
  +  };
  +
  +  RETURN_G_RC_MODE("output-capstyle",
  +		   default_print_output_capstyle,
  +		   3);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_log_window(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {MAP_ON_STARTUP, "startup" },
  +    {MAP_LATER     , "later"   },
  +  };
  +
  +  RETURN_G_RC_MODE("log-window",
  +		   default_log_window,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_log_window_type(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRANSIENT, "transient" },
  +    {DECORATED, "decorated" },
  +  };
  +  
  +  RETURN_G_RC_MODE("log-window-type",
  +		   default_log_window_type,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_third_button(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {POPUP_ENABLED   , "popup"   },
  +    {MOUSEPAN_ENABLED, "mousepan"},
  +  };
  +
  +  RETURN_G_RC_MODE("third-button",
  +		   default_third_button,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_middle_button(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {STROKE, "stroke"},
  +    {REPEAT, "repeat"},
  +    {ACTION, "action"},
  +  };
  +
  +  RETURN_G_RC_MODE("middle-button",
  +		   default_middle_button,
  +		   3);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_net_consolidate(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("net-consolidate",
  +		   default_net_consolidate,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_file_preview(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  /* this variable is inconsistantly named with the rest */
  +  RETURN_G_RC_MODE("file-preview",
  +		   default_file_preview,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_enforce_hierarchy(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("enforce-hierarchy",
  +		   default_enforce_hierarchy,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_text_origin_marker(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("text-origin-marker",
  +		   default_text_origin_marker,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_fast_mousepan(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("fast-mousepan",
  +		   default_fast_mousepan,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_raise_dialog_boxes_on_expose(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +  
  +  RETURN_G_RC_MODE("raise-dialog-boxes-on-expose",
  +		   default_raise_dialog_boxes,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_attribute_promotion(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("attribute-promotion",
  +		   default_attribute_promotion,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_promote_invisible(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("promote-invisible",
  +		   default_promote_invisible,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_keep_invisible(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("keep-invisible",
  +		   default_keep_invisible,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_continue_component_place(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("continue-component-place",
  +		   default_continue_component_place,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_undo_levels(SCM levels)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (levels), levels, SCM_ARG1, "undo-levels");
  +
  +  val = SCM_INUM (levels);
  +
  +  if (val == 0) {
  +    fprintf(stderr, _("Invalid num levels [%d] passed to undo-levels\n"),
  +            val);
  +    val = 10; /* absolute default */
  +  }
  +
  +  default_undo_levels = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_undo_control(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("undo-control", default_undo_control, 2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_undo_type(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {UNDO_DISK  , "disk"   },
  +    {UNDO_MEMORY, "memory" },
  +  };
  +
  +  RETURN_G_RC_MODE("undo-type",
  +		   default_undo_type,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_draw_grips(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +  
  +  RETURN_G_RC_MODE("draw-grips",
  +		   default_draw_grips,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_netconn_rubberband(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("netconn-rubberband",
  +		   default_netconn_rubberband,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_sort_component_library(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("sort_component_library",
  +                   default_sort_component_library, 
  +                   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_add_menu(SCM menu_name, SCM menu_items)
  +{
  +  SCM_ASSERT (SCM_NIMP (menu_name) && SCM_STRINGP (menu_name), menu_name,
  +              SCM_ARG1, "add-menu");
  +  SCM_ASSERT (SCM_NIMP (menu_items) && SCM_CONSP (menu_items), menu_items,
  +              SCM_ARG2, "add-menu");
  +
  +  s_menu_add_entry(SCM_STRING_CHARS (menu_name), menu_items);  
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_window_size(SCM width, SCM height)
  +{
  +  SCM_ASSERT (SCM_INUMP (width),  width,  SCM_ARG1, "window-size");
  +  SCM_ASSERT (SCM_INUMP (height), height, SCM_ARG2, "window-size");
  +  
  +  default_width  = SCM_INUM (width);
  +  default_height = SCM_INUM (height);
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_warp_cursor(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("warp-cursor",
  +		   default_warp_cursor,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_toolbars(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("toolbars",
  +		   default_toolbars,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_handleboxes(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("handleboxes",
  +		   default_handleboxes,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_setpagedevice_orientation(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("setpagedevice-orientation",
  +                   default_setpagedevice_orientation,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_setpagedevice_pagesize(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE , "enabled" },
  +    {FALSE, "disabled"},
  +  };
  +
  +  RETURN_G_RC_MODE("setpagedevice-pagesize",
  +                   default_setpagedevice_pagesize,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_bus_ripper_size(SCM size)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (size), size, SCM_ARG1, "bus-ripper-size");
  +  
  +  val = SCM_INUM (size);
  +
  +  if (val == 0) {
  +    fprintf(stderr, _("Invalid size [%d] passed to bus-ripper-size\n"),
  +            val);
  +    val = 200; /* absolute default */
  +  }
  +
  +  default_bus_ripper_size = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_bus_ripper_type(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {COMP_BUS_RIPPER, "component" },
  +    {NET_BUS_RIPPER,  "net" }
  +  };
  +
  +  RETURN_G_RC_MODE("bus-ripper-type",
  +		   default_bus_ripper_type,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_bus_ripper_rotation(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {SYMMETRIC,     "symmetric" },
  +    {NON_SYMMETRIC, "non-symmetric"  }
  +  };
  +
  +  RETURN_G_RC_MODE("bus-ripper-rotation",
  +		   default_bus_ripper_rotation,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_force_boundingbox(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE,  "enabled" },
  +    {FALSE, "disabled"  }
  +  };
  +
  +  RETURN_G_RC_MODE("force-boundingbox",
  +		   default_force_boundingbox,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_grid_dot_size(SCM dotsize)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (dotsize), dotsize, SCM_ARG1, "grid-dot-size");
  +  
  +  val = SCM_INUM (dotsize);
  +
  +  if (val <= 0) {
  +    fprintf(stderr, _("Invalid dot size [%d] passed to grid-dot-size\n"),
  +            val);
  +    val = 1; /* absolute default */
  +  }
  +
  +  default_grid_dot_size = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_grid_mode(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {GRID_VARIABLE_MODE,  "variable" },
  +    {GRID_FIXED_MODE, "fixed"  }
  +  };
  +
  +  RETURN_G_RC_MODE("grid-mode",
  +		   default_grid_mode,
  +		   2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_grid_fixed_threshold(SCM spacing)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (spacing), spacing, SCM_ARG1, "grid-fixed-threshold");
  +  
  +  val = SCM_INUM (spacing);
  +
  +  if (val <= 0) {
  +    fprintf(stderr, _("Invalid pixel spacing [%d] passed to grid-fixed-threshold\n"),
  +            val);
  +    val = 10; /* absolute default */
  +  }
  +
  +  default_grid_fixed_threshold = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_output_vector_threshold(SCM numlines)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (numlines), numlines,
  +              SCM_ARG1, "output-vector-threshold");
  +  
  +  val = SCM_INUM (numlines);
  +
  +  default_print_vector_threshold = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_add_attribute_offset(SCM offset)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (offset), offset,
  +              SCM_ARG1, "add-attribute-offset");
  +  
  +  val = SCM_INUM (offset);
  +
  +  if (val < 0) {
  +    fprintf(stderr, _("Invalid offset [%d] passed to add-attribute-offset\n"),
  +            val);
  +    val = 50; /* absolute default */
  +  }
  +
  +  default_add_attribute_offset = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_auto_save_interval(SCM seconds)
  +{
  +  int val;
  +
  +  SCM_ASSERT (SCM_INUMP (seconds), seconds, SCM_ARG1, "auto-save-interval");
  +
  +  val = SCM_INUM (seconds);
  +
  +  if (val < 0) {
  +    fprintf(stderr, _("Invalid number of seconds [%d] passed to auto-save-interval\n"),
  +            val);
  +    val = 120; /* absolute default */
  +  }
  +
  +  default_auto_save_interval = val;
  +
  +  return SCM_BOOL_T;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +SCM g_rc_drag_can_move(SCM mode)
  +{
  +  static const vstbl_entry mode_table[] = {
  +    {TRUE,  "enabled" },
  +    {FALSE, "disabled"  }
  +  };
  +
  +  RETURN_G_RC_MODE("drag-can-move",
  +		   default_drag_can_move,
  +		   2);
  +}
  
  
  
  1.41      +318 -258  eda/geda/gaf/gschem/src/g_register.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: g_register.c
  ===================================================================
  RCS file: g_register.c
  diff -N g_register.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ g_register.c	14 Jul 2006 02:23:54 -0000	1.41
  @@ -0,0 +1,354 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/stat.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_ASSERT_H
  +#include <assert.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief */
  +struct gsubr_t {
  +  char* name;
  +  int req;
  +  int opt;
  +  int rst;
  +  SCM (*fnc)();
  +};
  +
  +/*! \brief */
  +static struct gsubr_t gschem_funcs[] = {
  +  /* rc file */
  +  { "gschem-version",           1, 0, 0, g_rc_gschem_version },
  +  
  +  { "override-net-color",       7, 0, 0, g_rc_override_net_color },
  +  { "override-bus-color",       7, 0, 0, g_rc_override_bus_color },
  +  { "override-pin-color",       7, 0, 0, g_rc_override_pin_color },
  +  { "attribute-color",          7, 0, 0, g_rc_attribute_color },
  +  { "detached-attribute-color", 7, 0, 0, g_rc_detachedattr_color },
  +  { "text-color",               7, 0, 0, g_rc_text_color },
  +  { "logic-bubble-color",       7, 0, 0, g_rc_logic_bubble_color },
  +  { "lock-color",               7, 0, 0, g_rc_lock_color },
  +  { "zoom-box-color",           7, 0, 0, g_rc_zoom_box_color },
  +  { "net-color",                7, 0, 0, g_rc_net_color },
  +  { "bus-color",                7, 0, 0, g_rc_bus_color },
  +  { "pin-color",                7, 0, 0, g_rc_pin_color },
  +  { "graphic-color",            7, 0, 0, g_rc_graphic_color },
  +  { "grid-color",               7, 0, 0, g_rc_grid_color },
  +  { "background-color",         7, 0, 0, g_rc_background_color },
  +  { "select-color",             7, 0, 0, g_rc_select_color },
  +  { "boundingbox-color",        7, 0, 0, g_rc_boundingbox_color },
  +  { "net-endpoint-color",       7, 0, 0, g_rc_net_endpoint_color },
  +  { "stroke-color",             7, 0, 0, g_rc_stroke_color },
  +  { "output-color-background",  7, 0, 0, g_rc_output_color_background },
  +  { "freestyle-color",          7, 0, 0, g_rc_freestyle_color },
  +
  +  { "net-endpoint-mode",         1, 0, 0, g_rc_net_endpoint_mode },
  +  { "net-midpoint-mode",         1, 0, 0, g_rc_net_midpoint_mode },
  +  { "net-style",                 1, 0, 0, g_rc_net_style },
  +  { "bus-style",                 1, 0, 0, g_rc_bus_style },
  +  { "pin-style",                 1, 0, 0, g_rc_pin_style },
  +  { "zoom-with-pan",             1, 0, 0, g_rc_zoom_with_pan },
  +  { "action-feedback-mode",      1, 0, 0, g_rc_action_feedback_mode },
  +  { "text-feedback",             1, 0, 0, g_rc_text_feedback },
  +  { "text-display-zoomfactor",   1, 0, 0, g_rc_text_display_zoomfactor },
  +  { "scrollbars",                1, 0, 0, g_rc_scrollbars },
  +  { "scrollbar-update",          1, 0, 0, g_rc_scrollbar_update },
  +  { "object-clipping",           1, 0, 0, g_rc_object_clipping },
  +  { "embed-components",          1, 0, 0, g_rc_embed_components },
  +  { "logging",                   1, 0, 0, g_rc_logging },
  +  { "text-size",                 1, 0, 0, g_rc_text_size },
  +  { "snap-size",                 1, 0, 0, g_rc_snap_size },
  +
  +  { "text-caps-style",           1, 0, 0, g_rc_text_caps_style },
  +  { "logging-destination",       1, 0, 0, g_rc_logging_destination },
  +
  +  { "attribute-name",            1, 0, 0, g_rc_attribute_name },
  +  { "paper-size",                2, 0, 0, g_rc_paper_size },
  +  { "paper-sizes",               3, 0, 0, g_rc_paper_sizes },
  +  /* text-output is old... will eventually be removed! */
  +  { "text-output",               1, 0, 0, g_rc_output_text }, 
  +  { "output-text",               1, 0, 0, g_rc_output_text },
  +  { "output-type",               1, 0, 0, g_rc_output_type },
  +  { "output-orientation",        1, 0, 0, g_rc_output_orientation },
  +  { "output-color",              1, 0, 0, g_rc_output_color },
  +  { "output-capstyle",           1, 0, 0, g_rc_output_capstyle },
  +  { "image-color",               1, 0, 0, g_rc_image_color },
  +  { "image-size",                2, 0, 0, g_rc_image_size },
  +  { "log-window",                1, 0, 0, g_rc_log_window },
  +  { "log-window-type",           1, 0, 0, g_rc_log_window_type },
  +  { "third-button",              1, 0, 0, g_rc_third_button },
  +  { "middle-button",             1, 0, 0, g_rc_middle_button },
  +  { "net-consolidate",           1, 0, 0, g_rc_net_consolidate },
  +  { "file-preview",              1, 0, 0, g_rc_file_preview },
  +  { "enforce-hierarchy",         1, 0, 0, g_rc_enforce_hierarchy },
  +  { "text-origin-marker",        1, 0, 0, g_rc_text_origin_marker },
  +  { "fast-mousepan",             1, 0, 0, g_rc_fast_mousepan },
  +  { "raise-dialog-boxes-on-expose", 1, 0, 0, g_rc_raise_dialog_boxes_on_expose },
  +  { "attribute-promotion",       1, 0, 0, g_rc_attribute_promotion },
  +  { "promote-invisible",         1, 0, 0, g_rc_promote_invisible },
  +  { "keep-invisible",            1, 0, 0, g_rc_keep_invisible },
  +  { "continue-component-place",  1, 0, 0, g_rc_continue_component_place },
  +  { "undo-levels",               1, 0, 0, g_rc_undo_levels },
  +  { "undo-control",              1, 0, 0, g_rc_undo_control },
  +  { "undo-type",                 1, 0, 0, g_rc_undo_type },
  +
  +  { "drag-can-move",             1, 0, 0, g_rc_drag_can_move },
  +
  +  { "draw-grips",                1, 0, 0, g_rc_draw_grips },
  +  { "netconn-rubberband",        1, 0, 0, g_rc_netconn_rubberband },
  +  { "sort-component-library",    1, 0, 0, g_rc_sort_component_library },
  +  { "add-menu",                  2, 0, 0, g_rc_add_menu },
  +  { "window-size",               2, 0, 0, g_rc_window_size },
  +  { "warp-cursor",               1, 0, 0, g_rc_warp_cursor },
  +  { "toolbars",                  1, 0, 0, g_rc_toolbars },
  +  { "handleboxes",               1, 0, 0, g_rc_handleboxes },
  +  { "setpagedevice-orientation", 1, 0, 0, g_rc_setpagedevice_orientation },
  +  { "setpagedevice-pagesize",    1, 0, 0, g_rc_setpagedevice_pagesize },
  +  { "bus-ripper-size",           1, 0, 0, g_rc_bus_ripper_size },
  +  { "bus-ripper-type",           1, 0, 0, g_rc_bus_ripper_type },
  +  { "bus-ripper-rotation",       1, 0, 0, g_rc_bus_ripper_rotation },
  +  { "force-boundingbox",         1, 0, 0, g_rc_force_boundingbox },
  +  { "grid-dot-size",             1, 0, 0, g_rc_grid_dot_size },
  +  { "grid-mode",		 1, 0, 0, g_rc_grid_mode },
  +  { "grid-fixed-threshold",   	 1, 0, 0, g_rc_grid_fixed_threshold },
  +  { "output-vector-threshold",   1, 0, 0, g_rc_output_vector_threshold },
  +  { "add-attribute-offset",      1, 0, 0, g_rc_add_attribute_offset },
  +
  +  /* backup functions */
  +  { "auto-save-interval",        1, 0, 0, g_rc_auto_save_interval },
  +
  +  /* general guile functions */
  +  { "gschem-print",              1, 0, 0, g_funcs_print },
  +  { "gschem-image",              1, 0, 0, g_funcs_image },
  +  { "gschem-key-name",           1, 0, 0, g_funcs_key_name },
  +  { "gschem-key-value",          1, 0, 0, g_funcs_key_value },
  +  { "gschem-key-done",           0, 0, 0, g_funcs_key_done },
  +  { "gschem-use-rc-values",      0, 0, 0, g_funcs_use_rc_values },
  +  { "gschem-exit",               0, 0, 0, g_funcs_exit },
  +  { "gschem-log",                1, 0, 0, g_funcs_log },
  +  { "gschem-msg",                1, 0, 0, g_funcs_msg },
  +  { "gschem-confirm",            1, 0, 0, g_funcs_confirm },
  +  { "gschem-filesel",            2, 0, 1, g_funcs_filesel },
  +
  +  /* keymapping callbacks */
  +  { "file-new-window",           0, 0, 0, g_keys_file_new_window },
  +  { "file-new",                  0, 0, 0, g_keys_file_new },
  +  { "file-open",                 0, 0, 0, g_keys_file_open },
  +  { "file-script",               0, 0, 0, g_keys_file_script },
  +  { "file-save",                 0, 0, 0, g_keys_file_save },
  +  { "file-save-as",              0, 0, 0, g_keys_file_save_as },
  +  { "file-save-all",             0, 0, 0, g_keys_file_save_all },
  +  { "file-print",                0, 0, 0, g_keys_file_print },
  +  { "file-image",                0, 0, 0, g_keys_file_write_png },
  +  { "file-close-window",         0, 0, 0, g_keys_file_close },
  +  { "file-quit",                 0, 0, 0, g_keys_file_quit },
  +  { "edit-undo",                 0, 0, 0, g_keys_edit_undo },
  +  { "edit-redo",                 0, 0, 0, g_keys_edit_redo },
  +  { "edit-select",               0, 0, 0, g_keys_edit_select },
  +  { "edit-copy",                 0, 0, 0, g_keys_edit_copy },
  +  { "edit-copy-hotkey",          0, 0, 0, g_keys_edit_copy_hotkey },
  +  { "edit-mcopy",                0, 0, 0, g_keys_edit_mcopy },
  +  { "edit-mcopy-hotkey",         0, 0, 0, g_keys_edit_mcopy_hotkey },
  +  { "edit-move",                 0, 0, 0, g_keys_edit_move },
  +  { "edit-move-hotkey",          0, 0, 0, g_keys_edit_move_hotkey },
  +  { "edit-delete",               0, 0, 0, g_keys_edit_delete },
  +  { "edit-rotate-90",            0, 0, 0, g_keys_edit_rotate_90 },
  +  { "edit-rotate-90-hotkey",     0, 0, 0, g_keys_edit_rotate_90_hotkey },
  +  { "edit-mirror",               0, 0, 0, g_keys_edit_mirror },
  +  { "edit-mirror-hotkey",        0, 0, 0, g_keys_edit_mirror_hotkey },
  +#if 0 /* Obsolete */
  +  { "edit-stretch",              0, 0, 0, g_keys_edit_stretch },
  +  { "edit-stretch-hotkey",       0, 0, 0, g_keys_edit_stretch_hotkey },
  +#endif
  +  { "edit-slot",                 0, 0, 0, g_keys_edit_slot },
  +  { "edit-color",                0, 0, 0, g_keys_edit_color },
  +  { "edit-edit",                 0, 0, 0, g_keys_edit_edit },
  +  { "edit-text",                 0, 0, 0, g_keys_edit_text },
  +  { "edit-lock",                 0, 0, 0, g_keys_edit_lock },
  +  { "edit-unlock",               0, 0, 0, g_keys_edit_unlock },
  +  { "edit-linetype",             0, 0, 0, g_keys_edit_linetype },
  +  { "edit-filltype",             0, 0, 0, g_keys_edit_filltype },
  +  { "edit-translate",            0, 0, 0, g_keys_edit_translate },
  +  { "edit-embed",                0, 0, 0, g_keys_edit_embed },
  +  { "edit-unembed",              0, 0, 0, g_keys_edit_unembed },
  +  { "edit-update",               0, 0, 0, g_keys_edit_update },
  +  { "edit-show-hidden",          0, 0, 0, g_keys_edit_show_hidden },
  +  { "edit-make-text-visible",    0, 0, 0, g_keys_edit_make_visible },
  +  { "edit-find-text",            0, 0, 0, g_keys_edit_find },
  +  { "edit-show-text",            0, 0, 0, g_keys_edit_show_text },
  +  { "edit-hide-text",            0, 0, 0, g_keys_edit_hide_text },
  +  { "edit-autonumber",           0, 0, 0, g_keys_edit_autonumber_text },
  +
  +  { "buffer-copy1",              0, 0, 0, g_keys_buffer_copy1 },
  +  { "buffer-copy2",              0, 0, 0, g_keys_buffer_copy2 },
  +  { "buffer-copy3",              0, 0, 0, g_keys_buffer_copy3 },
  +  { "buffer-copy4",              0, 0, 0, g_keys_buffer_copy4 },
  +  { "buffer-copy5",              0, 0, 0, g_keys_buffer_copy5 },
  +  { "buffer-cut1",               0, 0, 0, g_keys_buffer_cut1 },
  +  { "buffer-cut2",               0, 0, 0, g_keys_buffer_cut2 },
  +  { "buffer-cut3",               0, 0, 0, g_keys_buffer_cut3 },
  +  { "buffer-cut4",               0, 0, 0, g_keys_buffer_cut4 },
  +  { "buffer-cut5",               0, 0, 0, g_keys_buffer_cut5 },
  +  { "buffer-paste1",             0, 0, 0, g_keys_buffer_paste1 },
  +  { "buffer-paste2",             0, 0, 0, g_keys_buffer_paste2 },
  +  { "buffer-paste3",             0, 0, 0, g_keys_buffer_paste3 },
  +  { "buffer-paste4",             0, 0, 0, g_keys_buffer_paste4 },
  +  { "buffer-paste5",             0, 0, 0, g_keys_buffer_paste5 },
  +  { "buffer-paste1-hotkey",      0, 0, 0, g_keys_buffer_paste1_hotkey },
  +  { "buffer-paste2-hotkey",      0, 0, 0, g_keys_buffer_paste2_hotkey },
  +  { "buffer-paste3-hotkey",      0, 0, 0, g_keys_buffer_paste3_hotkey },
  +  { "buffer-paste4-hotkey",      0, 0, 0, g_keys_buffer_paste4_hotkey },
  +  { "buffer-paste5-hotkey",      0, 0, 0, g_keys_buffer_paste5_hotkey },
  +
  +  { "view-redraw",               0, 0, 0, g_keys_view_redraw },
  +  { "view-zoom-full",            0, 0, 0, g_keys_view_zoom_full },
  +  { "view-zoom-extents",         0, 0, 0, g_keys_view_zoom_extents },
  +  { "view-zoom-in",              0, 0, 0, g_keys_view_zoom_in },
  +  { "view-zoom-out",             0, 0, 0, g_keys_view_zoom_out },
  +  { "view-zoom-in-hotkey",       0, 0, 0, g_keys_view_zoom_in_hotkey },
  +  { "view-zoom-out-hotkey",      0, 0, 0, g_keys_view_zoom_out_hotkey },
  +  { "view-zoom-box",             0, 0, 0, g_keys_view_zoom_box },
  +  { "view-zoom-box-hotkey",      0, 0, 0, g_keys_view_zoom_box_hotkey },
  +  { "view-pan",                  0, 0, 0, g_keys_view_pan },
  +  { "view-pan-hotkey",           0, 0, 0, g_keys_view_pan_hotkey },
  +  { "view-update-cues",          0, 0, 0, g_keys_view_update_cues },
  +  { "page-manager",              0, 0, 0, g_keys_page_manager },
  +  { "page-next",                 0, 0, 0, g_keys_page_next },
  +  { "page-prev",                 0, 0, 0, g_keys_page_prev },
  +  { "page-new",                  0, 0, 0, g_keys_page_new },
  +  { "page-close",                0, 0, 0, g_keys_page_close },
  +  { "page-revert",               0, 0, 0, g_keys_page_revert },
  +  { "page-discard",              0, 0, 0, g_keys_page_discard },
  +  { "page-print",                0, 0, 0, g_keys_page_print },
  +  { "add-component",             0, 0, 0, g_keys_add_component },
  +  { "add-attribute",             0, 0, 0, g_keys_add_attribute },
  +  { "add-attribute-hotkey",      0, 0, 0, g_keys_add_attribute_hotkey },
  +  { "add-net",                   0, 0, 0, g_keys_add_net },
  +  { "add-net-hotkey",            0, 0, 0, g_keys_add_net_hotkey },
  +  { "add-bus",                   0, 0, 0, g_keys_add_bus },
  +  { "add-bus-hotkey",            0, 0, 0, g_keys_add_bus_hotkey },
  +  { "add-text",                  0, 0, 0, g_keys_add_text },
  +  { "add-line",                  0, 0, 0, g_keys_add_line },
  +  { "add-line-hotkey",           0, 0, 0, g_keys_add_line_hotkey },
  +  { "add-box",                   0, 0, 0, g_keys_add_box },
  +  { "add-box-hotkey",            0, 0, 0, g_keys_add_box_hotkey },
  +  { "add-picture",               0, 0, 0, g_keys_add_picture},
  +  { "add-picture-hotkey",        0, 0, 0, g_keys_add_picture_hotkey},
  +  { "add-circle",                0, 0, 0, g_keys_add_circle },
  +  { "add-circle-hotkey",         0, 0, 0, g_keys_add_circle_hotkey },
  +  { "add-arc",                   0, 0, 0, g_keys_add_arc },
  +  { "add-arc-hotkey",            0, 0, 0, g_keys_add_arc_hotkey },
  +  { "add-pin",                   0, 0, 0, g_keys_add_pin },
  +  { "add-pin-hotkey",            0, 0, 0, g_keys_add_pin_hotkey },
  +  { "hierarchy-down-schematic",  0, 0, 0, g_keys_hierarchy_down_schematic },
  +  { "hierarchy-down-symbol",     0, 0, 0, g_keys_hierarchy_down_symbol },
  +  { "hierarchy-up",              0, 0, 0, g_keys_hierarchy_up },
  +  { "hierarchy-documentation",   0, 0, 0, g_keys_hierarchy_documentation },
  +  { "attributes-attach",         0, 0, 0, g_keys_attributes_attach },
  +  { "attributes-detach",         0, 0, 0, g_keys_attributes_detach },
  +  { "attributes-show-name",      0, 0, 0, g_keys_attributes_show_name },
  +  { "attributes-show-value",     0, 0, 0, g_keys_attributes_show_value },
  +  { "attributes-show-both",      0, 0, 0, g_keys_attributes_show_both },
  +  { "attributes-visibility-toggle", 0, 0, 0, g_keys_attributes_visibility_toggle },
  +  { "options-text-size",         0, 0, 0, g_keys_options_text_size },
  +  { "options-snap-size",         0, 0, 0, g_keys_options_snap_size },
  +  { "options-action-feedback",   0, 0, 0, g_keys_options_afeedback },
  +  { "options-grid",              0, 0, 0, g_keys_options_grid },
  +  { "options-snap",              0, 0, 0, g_keys_options_snap },
  +  { "options-rubberband",        0, 0, 0, g_keys_options_rubberband },
  +  { "options-show-log-window",   0, 0, 0, g_keys_options_show_log_window },
  +  { "options-show-coord-window", 0, 0, 0, g_keys_options_show_coord_window },
  +  { "help-about",                0, 0, 0, g_keys_help_about },
  +  { "help-manual",               0, 0, 0, g_keys_help_manual },
  +  { "help-hotkeys",              0, 0, 0, g_keys_help_hotkeys },
  +  { "help-component",            0, 0, 0, g_keys_hierarchy_documentation },
  +  { "misc-misc",                 0, 0, 0, g_keys_misc },
  +  { "misc-misc2",                0, 0, 0, g_keys_misc2 },
  +  { "misc-misc3",                0, 0, 0, g_keys_misc3 },
  +  { "cancel",                    0, 0, 0, g_keys_cancel },
  +
  +  /*help functions for generating netlists*/
  +  { "get-selected-filename",     0, 0, 0, g_get_selected_filename },
  +  { "get-selected-component-attributes", 0, 0, 0, g_get_selected_component_attributes },
  +  
  +  { NULL,                        0, 0, 0, NULL } };
  +  
  +/*! \brief Register function with Scheme.
  + *  \par Function Description
  + *  Creates <B>subr</B> objects to make <B>g_rc_*</B> functions that are defined *  #g_rc.c, #g_keys.c and #g_funcs.c visible to Scheme.
  + */
  +void g_register_funcs (void)
  +{
  +  struct gsubr_t *tmp = gschem_funcs;
  + 
  +  while (tmp->name != NULL) {
  +    scm_c_define_gsubr (tmp->name, tmp->req, tmp->opt, tmp->rst, tmp->fnc);
  +    tmp++;
  +  }
  +
  +  g_init_attrib_smob ();
  +  g_init_object_smob ();
  +
  +  /* Hook stuff */
  +  scm_c_define_gsubr ("add-attribute-to-object", 5, 0, 0, g_add_attrib);
  +  scm_c_define_gsubr ("get-object-attributes", 1, 0, 0, g_get_object_attributes);
  +  scm_c_define_gsubr ("get-object-bounds", 2, 0, 0, g_get_object_bounds);
  +  scm_c_define_gsubr ("get-object-pins", 1, 0, 0, g_get_object_pins);
  +  scm_c_define_gsubr ("get-pin-ends", 1, 0, 0, g_get_pin_ends);
  +  scm_c_define_gsubr ("set-attribute-text-properties!", 7, 0, 0, g_set_attrib_text_properties);
  +  scm_c_define_gsubr ("set-attribute-value!", 2, 0, 0, g_set_attrib_value_x);
  +
  +  add_component_hook  = scm_create_hook ("add-component-hook", 1);
  +  add_component_object_hook  = scm_create_hook ("add-component-object-hook", 
  +						1);
  +  rotate_component_object_hook  = scm_create_hook ("rotate-component-object-hook",
  +						   1);
  +  mirror_component_object_hook  = scm_create_hook ("mirror-component-object-hook", 
  +						1);
  +  copy_component_hook = scm_create_hook ("copy-component-hook", 1);
  +  move_component_hook = scm_create_hook ("move-component-hook", 1);
  +  deselect_component_hook = scm_create_hook ("deselect-component-hook", 1);
  +  deselect_net_hook = scm_create_hook ("deselect-net-hook", 1);
  +  deselect_all_hook = scm_create_hook ("deselect-all-hook", 1);
  +  select_component_hook = scm_create_hook ("select-component-hook", 1);
  +  select_net_hook = scm_create_hook ("select-net-hook", 1);
  +
  +  add_pin_hook = scm_create_hook ("add-pin-hook", 1);
  +  mirror_pin_hook = scm_create_hook ("mirror-pin-hook", 1);
  +  rotate_pin_hook = scm_create_hook ("rotate-pin-hook", 1);
  +  add_attribute_hook = scm_create_hook ("add-attribute-hook", 1);
  +
  +}
  
  
  
  1.16      +28 -6     eda/geda/gaf/gschem/src/globals.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: globals.c
  ===================================================================
  RCS file: globals.c
  diff -N globals.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ globals.c	14 Jul 2006 02:23:54 -0000	1.16
  @@ -0,0 +1,96 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +/*! \todo Add global variable documentation!!!
  + *
  + */
  +#include <config.h>
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* this is needed since guile scripts only deal with the current
  + * window set in x_event* functions */
  +TOPLEVEL *global_window_current = NULL;
  +
  +char *rc_filename     = NULL;
  +char *script_filename = NULL;
  +char *output_filename = NULL;
  +
  +/* color stuff */
  +GdkColormap *colormap;
  +GdkVisual *visual;
  +
  +/* colors */
  +GdkColor white;
  +GdkColor black;
  +
  +int do_logging = TRUE;
  +int logging_dest = LOG_WINDOW;
  +
  +/* these are required by libgeda */
  +void (*arc_draw_func)()      = o_arc_draw;
  +void (*box_draw_func)()      = o_box_draw;
  +#ifndef HAS_GTK12
  +void (*picture_draw_func)()  = o_picture_draw;
  +#endif
  +void (*circle_draw_func)()   = o_circle_draw;
  +void (*complex_draw_func)()  = o_complex_draw;
  +void (*line_draw_func)()     = o_line_draw;
  +void (*net_draw_func)()      = o_net_draw;
  +void (*bus_draw_func)()      = o_bus_draw;
  +void (*text_draw_func)()     = o_text_draw;
  +void (*pin_draw_func)()      = o_pin_draw;
  +void (*select_func)()        = o_select_object; /* NEW SELECTION code */
  +void (*x_log_update_func)()  = NULL;
  +void (*quit_func)()          = NULL;  /* not used by gschem */
  +void (*variable_set_func)()  = NULL;  /* not used by gschem */
  +int (*load_newer_backup_func)()  = x_fileselect_load_backup;
  +
  +/* command line options */
  +int quiet_mode = FALSE;
  +int verbose_mode = FALSE;
  +int stroke_info_mode = FALSE;
  +int auto_place_mode = FALSE;
  +
  +/* Global buffers */
  +OBJECT *object_buffer[MAX_BUFFERS];
  +
  +/* Hooks */
  +SCM add_attribute_hook;
  +SCM add_component_hook;
  +SCM add_component_object_hook;
  +SCM mirror_component_object_hook;
  +SCM rotate_component_object_hook;
  +SCM copy_component_hook;
  +SCM move_component_hook;
  +SCM add_pin_hook;
  +SCM rotate_pin_hook;
  +SCM mirror_pin_hook;
  +SCM deselect_component_hook;
  +SCM deselect_net_hook;
  +SCM deselect_all_hook;
  +SCM select_component_hook;
  +SCM select_net_hook;
  
  
  
  1.32      +328 -239  eda/geda/gaf/gschem/src/gschem.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: gschem.c
  ===================================================================
  RCS file: gschem.c
  diff -N gschem.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ gschem.c	14 Jul 2006 02:23:54 -0000	1.32
  @@ -0,0 +1,385 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/i_vars.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#ifdef HAVE_LOCALE_H
  +#include <locale.h>
  +#endif
  +
  +#ifdef HAS_LIBSTROKE
  +/* libstroke prototype */
  +void stroke_init(void);
  +#endif
  +
  +/*! \brief Cleanup gSchem on exit.
  + *  \par Function Description
  + *  This function cleans up all memory objects allocated during the
  + *  gSchem runtime.
  + */
  +void gschem_quit(void)
  +{
  +  s_clib_free();
  +  s_slib_free();
  +  s_menu_free();
  +  /* o_text_freeallfonts();*/
  +  s_attrib_free();
  +  s_papersizes_free();
  +  x_stroke_free_all();
  +  x_dialog_hotkeys_free_all();
  +  s_color_destroy_all();
  +  o_undo_cleanup();
  +  /* s_stroke_free(); no longer needed */
  +
  +  i_vars_freenames();
  +
  +  /* x_window_free_head(); can't do this since it causes a
  +   * condition in which window_head->... is still being refered
  +   * after this */
  +
  +  /* enable this to get more memory usage from glib */
  +  /* You also have to enable something in glib I think */
  +  /* g_mem_profile();*/
  +	 
  +
  +  gtk_main_quit();
  +}
  +
  +/*! \brief Main Scheme(GUILE) program function.
  + *  \par Function Description
  + *  This function is the main program called from scm_boot_guile.
  + *  It handles initializing all libraries and gSchem variables
  + *  and passes control to the gtk main loop.
  + */
  +void main_prog(void *closure, int argc, char *argv[])
  +{
  +  int i;
  +  char *cwd = NULL;
  +  TOPLEVEL *w_current = NULL;
  +  char *input_str = NULL;
  +  int argv_index;
  +  int first_page = 1;
  +  char *geda_data = NULL;
  +  char *filename;
  +
  +#if ENABLE_NLS
  +  /* this should be equivalent to setlocale (LC_ALL, "") */
  +  gtk_set_locale();
  +
  +  /* This must be the same for all locales */
  +  setlocale(LC_NUMERIC, "POSIX");
  +
  +  /* Disable gtk's ability to set the locale. */ 
  +  /* If gtk is allowed to set the locale, then it will override the     */
  +  /* setlocale for LC_NUMERIC (which is important for proper PS output. */
  +  /* This may look funny here, given we make a call to gtk_set_locale() */
  +  /* above.  I don't know yet, if this is really the right thing to do. */
  +#ifdef HAS_GTK22
  +  gtk_disable_setlocale(); 
  +#endif
  +
  +#endif
  +
  +
  +  gtk_init(&argc, &argv);
  +  visual = gdk_visual_get_system();
  +
  +  argv_index = parse_commandline(argc, argv);
  +  cwd = getcwd(NULL, 1024);
  +#ifdef __MINGW32__
  +    u_basic_strip_trailing(cwd, G_DIR_SEPARATOR);
  +#endif
  +  
  +  libgeda_init();
  +  
  +  /*! \todo Probably the file name shuold be defined elsewhere */
  +  /* create log file right away even if logging is enabled */
  +  filename = g_build_path (G_DIR_SEPARATOR_S,
  +                           cwd,
  +                           "gschem.log",
  +                           NULL);
  +  s_log_init (filename);
  +  g_free (filename);
  +
  +#ifdef HAS_LIBSTROKE
  +  stroke_init(); /* libstroke function */
  +  /* s_stroke_init(); no longer needed libgeda function */
  +#endif
  +	
  +  s_log_message(
  +                _("gEDA/gschem version %s\n"), VERSION);
  +  s_log_message(
  +                _("gEDA/gschem comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"));
  +  s_log_message(
  +                _("This is free software, and you are welcome to redistribute it under certain\n"));
  +  s_log_message(
  +                _("conditions; please see the COPYING file for more details.\n\n")); 
  +
  +  if (!quiet_mode) {
  +    fprintf(stderr, 
  +            _("gEDA/gschem version %s\n"), VERSION);
  +    fprintf(stderr, 
  +            _("gEDA/gschem comes with ABSOLUTELY NO WARRANTY; see COPYING for more details.\n"));
  +    fprintf(stderr, 
  +            _("This is free software, and you are welcome to redistribute it under certain\n"));
  +    fprintf(stderr, 
  +            _("conditions; please see the COPYING file for more details.\n\n")); 
  +  }
  +
  +#ifdef __MINGW32__
  +  fprintf(stderr, _("This is the MINGW32 port.\n"));
  +#endif  
  +
  +#if DEBUG
  +  fprintf(stderr, _("Current locale settings: %s\n"), setlocale(LC_ALL, NULL));
  +#endif
  +
  +  /* init global buffers */
  +  o_buffer_init();
  +
  +  /* register guile (scheme) functions */
  +  g_register_funcs();
  +
  +  o_undo_init(); 
  +
  +  geda_data = getenv("GEDADATA");
  +  if (geda_data == NULL) {
  +    fprintf(stderr, _("You must set the GEDADATA environment variable!\n"));
  +    exit(-1);
  +  }
  +
  +  /* Allocate w_current.   */
  +  w_current = s_toplevel_new ();
  +  global_window_current = w_current;
  +
  +  /* Now read in RC files. */
  +  g_rc_parse_gtkrc();
  +  g_rc_parse(w_current, "gschemrc", rc_filename);
  +  
  +  input_str = g_strdup_printf("%s%cgschem.scm", default_scheme_directory, 
  +			      G_DIR_SEPARATOR);
  +  if (g_read_file(input_str) != -1) {
  +    s_log_message(_("Read init scm file [%s]\n"), input_str);
  +  } else {
  +    /*! \todo These two messages are the same. Should be
  +     * integrated. */
  +    s_log_message(_("Failed to read init scm file [%s]\n"),
  +                  input_str);
  +    fprintf(stderr,
  +            _("Failed to read init scm file [%s]\n"), input_str);
  +  }
  +  free(input_str);
  +
  +  /* At end, complete set up of window. */
  +  colormap = gdk_colormap_get_system ();
  +  x_window_setup_colors();
  +
  +  x_window_setup (w_current);
  +
  +  /* so we can call key funcs from guile */
  +  set_window_current_key(w_current);
  +
  +  /* o_text_init(); goes away */
  +  /* o_text_init(); Moved inside libgeda_init() */
  +
  +  x_repaint_background(w_current);
  +
  +  i = argv_index;
  +  while (argv[i] != NULL) {
  +
  +#ifdef __MINGW32__
  +     if (argv[i][1] == ':' && (argv[i][2] == G_DIR_SEPARATOR ||
  +                               argv[i][2] == OTHER_PATH_SEPARATER_CHAR)) 
  +#else
  +    if (argv[i][0] == G_DIR_SEPARATOR) 
  +#endif
  +    {
  +      /* Path is already absolute so no need to do any concat of cwd */
  +      filename = g_strdup (argv[i]);
  +    } else {
  +      filename = g_strconcat (cwd, G_DIR_SEPARATOR_S, argv[i], NULL);
  +    }
  +
  +    if (first_page) {
  +      if (w_current->page_current->page_filename) {
  +        free(w_current->page_current->page_filename);
  +      }
  +
  +      /* Page structure has already been created...
  +       * so, just set the filename and open the
  +       * schematic for the first page */
  +
  +      /* always use absolute file names to eliminate confusion */
  +      w_current->page_current->page_filename = filename;
  +
  +      /* 
  +       * SDB notes:  at this point the filename might be unnormalized, like
  +       * /path/to/foo/../bar/baz.sch.  Bad filenames will be normalized
  +       * in f_open.  This works for Linux and MINGW32.
  +       */
  +
  +      if (!quiet_mode) {
  +        printf(_("Loading schematic [%s]\n"), filename);
  +      }
  +
  +      (void)f_open(w_current,
  +                   w_current->page_current->page_filename);
  +      i_set_filename(w_current,
  +                     w_current->page_current->page_filename);
  +
  +      a_zoom_extents(w_current,
  +                     w_current->page_current->object_head,
  +                     A_PAN_DONT_REDRAW);
  +      o_undo_savestate(w_current, UNDO_ALL);
  +
  +      first_page = 0;
  +    } else {
  +      /* Much simpler	*/
  +
  +      /* create new page, and only load if page not loaded */
  +      if (!s_page_search (w_current, filename)) {
  +        PAGE *page = s_page_new (w_current, filename);
  +        s_page_goto (w_current, page);
  +        
  +        if (!quiet_mode) {
  +          printf(_("Loading schematic [%s]\n"), 
  +                 filename);
  +        }
  +        
  +        f_open(w_current,
  +               w_current->page_current->page_filename);
  +        i_set_filename(w_current,
  +                       w_current->page_current->page_filename);
  +        a_zoom_extents(w_current,
  +                       w_current->page_current->object_head,
  +                       A_PAN_DONT_REDRAW);
  +        o_undo_savestate(w_current, UNDO_ALL);
  +      }
  +    }
  +    i++;
  +  }
  +
  +  free(cwd);	
  +
  +  if (argv[argv_index] == NULL) {
  +    if (w_current->page_current->page_filename) {
  +      free(w_current->page_current->page_filename);
  +    }
  +
  +    w_current->cwd = g_get_current_dir ();
  +#ifdef __MINGW32__
  +    u_basic_strip_trailing(w_current->cwd, G_DIR_SEPARATOR);
  +#endif
  +
  +    w_current->page_current->page_filename =
  +      malloc(sizeof(char) * (
  +                             strlen(w_current->cwd) +
  +                             strlen(w_current->untitled_name) +
  +                             strlen("/_##########.sch") +
  +                             1));
  +
  +    w_current->num_untitled++;
  +    sprintf(w_current->page_current->page_filename,
  +            "%s%c%s_%d.sch",
  +            w_current->cwd, G_DIR_SEPARATOR,
  +            w_current->untitled_name,
  +            w_current->num_untitled);
  +
  +    i_set_filename(w_current,
  +                   w_current->page_current->page_filename);
  +  }
  +
  +  x_scrollbars_update(w_current);
  +  o_redraw_all_fast(w_current);
  +
  +#if DEBUG
  +  scm_c_eval_string ("(display \"hello guile\n\")");
  +#endif
  +
  +  if (w_current->scheme_directory == NULL) {
  +    fprintf(stderr, _("Scheme directory NOT set!\n"));
  +    exit(-1);
  +  }
  +
  +
  +  /* Execute a script if it exists */
  +  if (script_filename) {
  +    s_log_message(_("Executing guile script [%s]\n"),
  +                  script_filename);
  +    g_read_file(script_filename);
  +  }
  +
  +  /* open up log window on startup */
  +  if (w_current->log_window == MAP_ON_STARTUP) {
  +    x_log_open ();
  +  }
  +
  +  /* if there were any symbols which had major changes, put up an error */
  +  /* dialog box */
  +  major_changed_dialog(w_current);
  +    
  +  /* enter main loop */
  +  gtk_main();
  +}
  +
  +/*! \brief Main executable entrance point.
  + *  \par Function Description
  + *  This is the main function for gSchem. It sets up the Scheme(GUILE)
  + *  environment and passes control to via scm_boot_guile to
  + *  the #main_prog function.
  + */
  +int main (int argc, char *argv[])
  +{
  +
  +#if ENABLE_NLS
  +  setlocale(LC_ALL, "");
  +  setlocale(LC_NUMERIC, "POSIX");
  +  bindtextdomain(PACKAGE, LOCALEDIR);
  +  textdomain(PACKAGE);
  +#ifdef HAS_GTK22
  +  bind_textdomain_codeset(PACKAGE, "UTF-8");
  +#endif
  +#endif
  +
  +  /* disable the deprecated warnings in guile 1.6.3 */
  +  /* Eventually the warnings will need to be fixed */
  +  if(getenv("GUILE_WARN_DEPRECATED") == NULL)
  +    putenv("GUILE_WARN_DEPRECATED=no");
  +
  +  scm_boot_guile (argc, argv, main_prog, 0);
  +  
  +  return 0;
  +}
  
  
  
  1.12      +625 -104  eda/geda/gaf/gschem/src/i_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: i_basic.c
  ===================================================================
  RCS file: i_basic.c
  diff -N i_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ i_basic.c	14 Jul 2006 02:23:54 -0000	1.12
  @@ -0,0 +1,690 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void i_update_status(TOPLEVEL *w_current, const char *string)
  +{
  +  if (!w_current->status_label) {
  +    return;
  +  }
  +
  +  if (string) {
  +    /* NOTE: consider optimizing this if same label */
  +    w_current->DONT_RESIZE=1;
  +    gtk_label_set(GTK_LABEL(w_current->status_label),
  +                  (char *) string);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Prefix to i_show_state(), i_set_state() and i_set_state_msg()
  + , Allows expose events to happen
  + * *EK* Egil Kvaleberg
  + */
  +void i_allow_expose(void)
  +{
  +  /* This function is probably not needed and should be deleted eventually */
  +#if 0
  +   /* HACK: This one allows the expose events to happen? */
  +    w_current->DONT_EXPOSE = 1;
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Get string corresponding to the currently selected mode
  + * The returned string will only last until the next time
  + * the function is called (which is probably just fine, really)
  + * *EK* Egil Kvaleberg
  + */
  +static const char *i_status_string(TOPLEVEL *w_current)
  +{
  +  static char *buf = 0;
  +
  +  switch ( w_current->event_state ) {
  +    case NONE:
  +    case STARTROUTENET: /*! \todo */
  +    case ENDROUTENET: /*! \todo */
  +      return "";
  +    case STARTSELECT:
  +    case SELECT:
  +    case SBOX:
  +    case GRIPS:
  +      return _("Select Mode");
  +    case DRAWATTRIB:
  +    case ENDATTRIB:
  +      return _("Attribute Mode"); /*EK* new */
  +    case DRAWCOMP:
  +    case ENDCOMP:
  +      return _("Component Mode"); /*EK* new */
  +    case TEXTENTRY:
  +    case ENDTEXT:
  +    case DRAWTEXT:
  +      return _("Text Mode"); /*EK* new */
  +    case STARTCOPY:
  +    case ENDCOPY:
  +      return _("Copy Mode");
  +    case STARTMOVE:
  +    case ENDMOVE:
  +      return _("Move Mode");
  +    case ENDROTATEP:
  +      return _("Rotate Mode");
  +    case ENDMIRROR:
  +      return _("Mirror Mode");
  +    case ZOOM:
  +    case ZOOMBOXEND:
  +    case ZOOMBOXSTART:
  +      return _("Zoom Box");
  +    case STARTPAN:
  +    case PAN:
  +    case MOUSEPAN:
  +      return _("Pan Mode");
  +    case STARTPASTE:
  +    case ENDPASTE:
  +      if (buf) free(buf);
  +      buf = g_strdup_printf(_("Paste %d Mode"), w_current->buffer_number+1);
  +      return buf;
  +    case STARTDRAWNET:
  +    case DRAWNET:
  +    case NETCONT:
  +      return _("Net Mode");
  +    case STARTDRAWBUS:
  +    case DRAWBUS:
  +    case BUSCONT:
  +      return _("Bus Mode");
  +    case DRAWLINE:
  +    case ENDLINE:
  +      return _("Line Mode");
  +    case DRAWBOX:
  +    case ENDBOX:
  +      return _("Box Mode");
  +    case DRAWPICTURE:
  +    case ENDPICTURE:
  +      return _("Picture Mode");
  +    case DRAWCIRCLE:
  +    case ENDCIRCLE:
  +      return _("Circle Mode");
  +    case DRAWARC:
  +    case ENDARC:
  +      return _("Arc Mode");
  +    case DRAWPIN:
  +    case ENDPIN:
  +      return _("Pin Mode");
  +    case COPY:
  +      return _("Copy");
  +    case MOVE:
  +      return _("Move");
  +    case MCOPY:
  +      return _("Multiple Copy");
  +    case STARTMCOPY:
  +    case ENDMCOPY:
  +      return _("Multiple Copy Mode");
  +  }
  +  return ""; /* should not happen */
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Show state field on screen,
  + * possibly with the addition of an extra message
  + * *EK* Egil Kvaleberg
  + */
  +void i_show_state(TOPLEVEL *w_current, const char *message)
  +{
  +  static char *buf = 0;
  +  char *aux = 0;
  +  const char *state_string = i_status_string(w_current);
  +  const char *what_to_say;
  +
  +  /* This may be a memory leak... either way it's weird and -Wall is */
  +  /* complaining... */
  +  buf = g_strdup("");
  +  aux = buf;
  +
  +  if ( message != NULL) {
  +    if ( message && message[0] ) {
  +      buf = g_strdup_printf("%s - ", message);
  +      if (aux) free(aux);
  +      aux = buf;
  +    }
  +  }
  +
  +  if ( !w_current->snap ) {
  +    buf = g_strdup_printf("%s%s - ", buf, _("Snap Off"));
  +    if (aux) free(aux);
  +    aux = buf;
  +  }
  +
  +  if ( w_current->show_hidden_text ) {
  +    buf = g_strdup_printf("%s%s - ", buf, _("Show Hidden"));
  +    if (aux) free(aux);
  +    aux = buf;
  +  }
  +
  +  if (buf != NULL) {
  +    if (strlen(buf) > 0) {
  +      buf = g_strdup_printf("%s%s", buf, state_string);
  +      if (aux) free(aux);
  +      aux = buf;
  +      what_to_say = buf;
  +    } else {
  +      what_to_say = state_string;
  +    }
  +  }
  +  else {
  +    what_to_say = state_string;
  +  }
  +
  +  i_update_status(w_current, what_to_say);
  +  if (buf != NULL) free(buf);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Set new state, then show state field
  + * *EK* Egil Kvaleberg
  + */
  +void i_set_state(TOPLEVEL *w_current, enum x_states newstate)
  +{
  +  i_set_state_msg(w_current, newstate, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Set new state, then show state field including some message
  + * *EK* Egil Kvaleberg
  + */
  +void i_set_state_msg(TOPLEVEL *w_current, enum x_states newstate,
  +		     const char *message)
  +{
  +  w_current->event_state = newstate;
  +  i_show_state(w_current, message);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void i_update_left_button(const char *string)
  +{
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void i_update_middle_button(TOPLEVEL *w_current,
  +			    void *func_ptr, const char *string)
  +{
  +  char *temp_string;
  +
  +  if (func_ptr == NULL) {
  +    return;
  +  }
  +
  +  if (string == NULL) {
  +    return;
  +  }	
  +
  +  if (!w_current->middle_label) {
  +    return;
  +  }
  +
  +  switch(w_current->middle_button) {
  +
  +    /* remove this case eventually and make it a null case */
  +    case(ACTION):
  +    w_current->DONT_RESIZE = 1;
  +    gtk_label_set(GTK_LABEL(w_current->middle_label),
  +                  _("Action"));
  +    break;
  +
  +#ifdef HAS_LIBSTROKE
  +    case(STROKE):
  +    w_current->DONT_RESIZE = 1;
  +
  +    gtk_label_set(GTK_LABEL(w_current->middle_label),
  +                  _("Stroke"));
  +    break;
  +#else 
  +    /* remove this case eventually and make it a null case */
  +    case(STROKE):
  +    w_current->DONT_RESIZE = 1;
  +    gtk_label_set(GTK_LABEL(w_current->middle_label),
  +                  _("none"));
  +    break;
  +#endif
  +		
  +    case(REPEAT):
  +    w_current->DONT_RESIZE = 1;
  +
  +    temp_string = g_strconcat (_("Repeat/"), string, NULL);
  +
  +    gtk_label_set(GTK_LABEL(w_current->middle_label),
  +                  temp_string);
  +    w_current->last_callback = func_ptr;
  +    free(temp_string);
  +    break;
  +
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void i_update_right_button(const char *string)
  +{
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void i_update_toolbar(TOPLEVEL *w_current)
  +{
  +  if (!w_current->toolbars) 
  +	return;
  +
  +  switch(w_current->event_state) {
  +    case(NONE):
  +    case(SELECT):
  +    case(STARTSELECT): 
  +    case(TEXTENTRY): 
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +				   w_current->toolbar_select), TRUE);
  +      break;
  +      
  +    case(DRAWNET): 
  +    case(STARTDRAWNET): 
  +    case(NETCONT): 
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +				   w_current->toolbar_net), TRUE);
  +      break;
  +      
  +    case(DRAWBUS): 
  +    case(STARTDRAWBUS): 
  +    case(BUSCONT): 
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +				   w_current->toolbar_bus), TRUE);
  +      break;
  +      
  +    case(DRAWCOMP): /*! \todo */
  +    case(DRAWLINE): /*! \todo */
  +    case(DRAWBOX): /*! \todo */
  +    case(DRAWPICTURE): /*! \todo */
  +    case(DRAWPIN): /*! \todo */
  +    case(DRAWCIRCLE): /*! \todo */
  +    case(DRAWARC): /*! \todo */
  +    case(MOVE): /*! \todo */
  +    case(COPY): /*! \todo */
  +    case(ZOOM): /*! \todo */
  +    case(PAN): /*! \todo */
  +    case(STARTPAN): /*! \todo */
  +    case(STARTCOPY): /*! \todo */
  +    case(STARTMOVE): /*! \todo */
  +    case(ENDCOPY): /*! \todo */
  +    case(ENDMOVE): /*! \todo */
  +    case(ENDLINE): /*! \todo */
  +    case(ENDBOX): /*! \todo */
  +    case(ENDPICTURE): /*! \todo */
  +    case(ENDCIRCLE): /*! \todo */
  +    case(ENDARC): /*! \todo */
  +    case(ENDPIN): /*! \todo */
  +    case(ENDCOMP): /*! \todo */
  +    case(DRAWATTRIB): /*! \todo */
  +    case(ENDATTRIB): /*! \todo */
  +    case(DRAWTEXT): /*! \todo */
  +    case(ENDTEXT): /*! \todo */
  +    case(ENDROTATEP): /*! \todo */
  +    case(ENDMIRROR): /*! \todo */
  +    case(ZOOMBOXSTART): /*! \todo */
  +    case(ZOOMBOXEND): /*! \todo */
  +    case(STARTROUTENET): /*! \todo */
  +    case(ENDROUTENET): /*! \todo */
  +    case(MOUSEPAN): /*! \todo */
  +    case(STARTPASTE): /*! \todo */
  +    case(ENDPASTE): /*! \todo */
  +    case(GRIPS): /*! \todo */
  +    case(MCOPY): /*! \todo */
  +    case(STARTMCOPY): /*! \todo */
  +    case(ENDMCOPY): /*! \todo */
  +    default:
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +				   w_current->toolbar_select), TRUE);
  +      break;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void i_update_menus(TOPLEVEL *w_current)
  +{
  +  /* 
  +   * This is very simplistic.  Right now it just disables all menu
  +   * items which get greyed out when a component is not selected.
  +   * Eventually what gets enabled/disabled
  +   * should be based on what is in the selection list 
  +   */
  +  
  +  if (o_selection_return_num(w_current->page_current->selection2_head)) {
  +    /* since one or more things are selected, we set these TRUE */
  +    /* These strings should NOT be internationalized */
  +    x_menus_sensitivity(w_current, "Edit/Edit...", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Edit Text...", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Copy Mode", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Move Mode", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Delete", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Rotate 90 Mode", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Mirror Mode", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Slot...", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Color...", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Lock", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Unlock", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Line Width & Type...", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Fill Type...", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Embed Component/Picture", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Unembed Component/Picture", TRUE);
  +    x_menus_sensitivity(w_current, "Edit/Update Component", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 1", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 2", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 3", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 4", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 5", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 1", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 2", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 3", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 4", TRUE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 5", TRUE);
  +    x_menus_sensitivity(w_current, "Hierarchy/Down Schematic", TRUE);
  +    x_menus_sensitivity(w_current, "Hierarchy/Down Symbol", TRUE);
  +    x_menus_sensitivity(w_current, "Hierarchy/Documentation", TRUE);
  +    x_menus_sensitivity(w_current, "Attributes/Attach", TRUE);
  +    x_menus_sensitivity(w_current, "Attributes/Detach", TRUE);
  +    x_menus_sensitivity(w_current, "Attributes/Show Value", TRUE);
  +    x_menus_sensitivity(w_current, "Attributes/Show Name", TRUE);
  +    x_menus_sensitivity(w_current, "Attributes/Show Both", TRUE);
  +    x_menus_sensitivity(w_current, "Attributes/Toggle Visibility", TRUE);
  +
  +    /*  Menu items for hierarchy added by SDB 1.9.2005.  */
  +    x_menus_popup_sensitivity(w_current, "/Down Schematic", TRUE);
  +    x_menus_popup_sensitivity(w_current, "/Down Symbol", TRUE);
  +    /* x_menus_popup_sensitivity(w_current, "/Up", TRUE); */
  +
  +  } else {
  +    /* Nothing is slected.  grey these out */
  +    /* These strings should NOT be internationalized */
  +    x_menus_sensitivity(w_current, "Edit/Edit...", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Edit Text...", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Copy Mode", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Move Mode", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Delete", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Rotate 90 Mode", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Mirror Mode", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Slot...", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Color...", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Lock", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Unlock", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Line Width & Type...", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Fill Type...", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Embed Component/Picture", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Unembed Component/Picture", FALSE);
  +    x_menus_sensitivity(w_current, "Edit/Update Component", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 1", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 2", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 3", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 4", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Copy into 5", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 1", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 2", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 3", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 4", FALSE);
  +    x_menus_sensitivity(w_current, "Buffer/Cut into 5", FALSE);
  +    x_menus_sensitivity(w_current, "Hierarchy/Down Schematic", FALSE);
  +    x_menus_sensitivity(w_current, "Hierarchy/Down Symbol", FALSE);
  +    x_menus_sensitivity(w_current, "Hierarchy/Documentation", FALSE);
  +    x_menus_sensitivity(w_current, "Attributes/Attach", FALSE);
  +    x_menus_sensitivity(w_current, "Attributes/Detach", FALSE);
  +    x_menus_sensitivity(w_current, "Attributes/Show Value", FALSE);
  +    x_menus_sensitivity(w_current, "Attributes/Show Name", FALSE);
  +    x_menus_sensitivity(w_current, "Attributes/Show Both", FALSE);
  +    x_menus_sensitivity(w_current, "Attributes/Toggle Visibility", FALSE);
  +
  +    /*  Menu items for hierarchy added by SDB 1.9.2005.  */
  +    x_menus_popup_sensitivity(w_current, "/Down Schematic", FALSE);
  +    x_menus_popup_sensitivity(w_current, "/Down Symbol", FALSE);
  +    /* x_menus_popup_sensitivity(w_current, "/Up", FALSE);	*/
  +  }
  +}
  + 
  +#if 0
  +/* This data is in X bitmap format, and can be created with the 'bitmap'
  +     utility. */
  +  #define cursor1_width 16
  +  #define cursor1_height 16
  +  static unsigned char cursor1_bits[] = {
  +   0x00, 0x00, 0x08, 0x38, 0x18, 0x08, 0x38, 0x18, 0x78, 0x08, 0xf8, 0x38,
  +   0xf8, 0x01, 0xf8, 0x03, 0xf8, 0x07, 0xf8, 0x00, 0xd8, 0x00, 0x88, 0x01,
  +   0x80, 0x01, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00};
  +
  +  static unsigned char cursor1mask_bits[] = {
  +   0x0c, 0x7c, 0x1c, 0x7c, 0x3c, 0x7c, 0x7c, 0x3c, 0xfc, 0x7c, 0xfc, 0x7d,
  +   0xfc, 0x7f, 0xfc, 0x07, 0xfc, 0x0f, 0xfc, 0x0f, 0xfc, 0x01, 0xdc, 0x03,
  +   0xcc, 0x03, 0x80, 0x07, 0x80, 0x07, 0x00, 0x03};
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void i_update_cursor(TOPLEVEL *w_current)
  +{
  +#if 0
  +  if (!w_current->cursors) 
  +	return;
  +#endif
  +
  +#if 0
  +  GdkCursor *cursor;
  +
  +  GdkPixmap *source, *mask;
  +  GdkColor fg = { 0, 0, 0, 0 }; /* Red. */
  +  GdkColor bg = { 0, 65535, 65535, 65535 }; /* Blue. */
  +    
  +  source = gdk_bitmap_create_from_data (NULL, cursor1_bits,
  +					cursor1_width, cursor1_height);
  +  mask = gdk_bitmap_create_from_data (NULL, cursor1mask_bits,
  +				      cursor1_width, cursor1_height);
  +  cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 3, 1);
  +  gdk_pixmap_unref (source);
  +  gdk_pixmap_unref (mask);
  +  
  +  gdk_window_set_cursor (w_current->window, cursor);
  +#endif
  +
  +
  +  GdkCursor* cursor;
  +  cursor = gdk_cursor_new(GDK_ARROW);
  +  gdk_window_set_cursor(w_current->window, cursor);
  +  gdk_cursor_destroy(cursor);
  +  
  +#if 0
  +  switch(w_current->event_state) {
  +    case(NONE):
  +    case(SELECT):
  +    case(STARTSELECT): 
  +    case(TEXTENTRY): 
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +				   w_current->toolbar_select), TRUE);
  +      break;
  +
  +    case(DRAWNET): 
  +    case(STARTDRAWNET): 
  +    case(NETCONT): 
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +				   w_current->toolbar_net), TRUE);
  +      break;
  +
  +    case(DRAWBUS): 
  +    case(STARTDRAWBUS): 
  +    case(BUSCONT): 
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +				   w_current->toolbar_bus), TRUE);
  +      break;
  +
  +    case(DRAWCOMP): /*! \todo */
  +    case(DRAWLINE): /*! \todo */
  +    case(DRAWBOX): /*! \todo */
  +    case(DRAWPICTURE): /*! \todo */
  +    case(DRAWPIN): /*! \todo */
  +    case(DRAWCIRCLE): /*! \todo */
  +    case(DRAWARC): /*! \todo */
  +    case(MOVE): /*! \todo */
  +    case(COPY): /*! \todo */
  +    case(ZOOM): /*! \todo */
  +    case(PAN): /*! \todo */
  +    case(STARTPAN): /*! \todo */
  +    case(STARTCOPY): /*! \todo */
  +    case(STARTMOVE): /*! \todo */
  +    case(ENDCOPY): /*! \todo */
  +    case(ENDMOVE): /*! \todo */
  +    case(ENDLINE): /*! \todo */
  +    case(ENDBOX): /*! \todo */
  +    case(ENDPICTURE): /*! \todo */
  +    case(ENDCIRCLE): /*! \todo */
  +    case(ENDARC): /*! \todo */
  +    case(ENDPIN): /*! \todo */
  +    case(ENDCOMP): /*! \todo */
  +    case(DRAWATTRIB): /*! \todo */
  +    case(ENDATTRIB): /*! \todo */
  +    case(DRAWTEXT): /*! \todo */
  +    case(ENDTEXT): /*! \todo */
  +    case(ENDROTATEP): /*! \todo */
  +    case(ENDMIRROR): /*! \todo */
  +    case(ZOOMBOXSTART): /*! \todo */
  +    case(ZOOMBOXEND): /*! \todo */
  +    case(STARTROUTENET): /*! \todo */
  +    case(ENDROUTENET): /*! \todo */
  +    case(MOUSEPAN): /*! \todo */
  +    case(STARTPASTE): /*! \todo */
  +    case(ENDPASTE): /*! \todo */
  +    case(GRIPS): /*! \todo */
  +    case(MCOPY): /*! \todo */
  +    case(MCOPYSTART): /*! \todo */
  +    case(MCOPYEND): /*! \todo */
  +    default:
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +				   w_current->toolbar_select), TRUE);
  +      break;
  +  }
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void i_set_filename(TOPLEVEL *w_current, const char *string)
  +{
  +  char trunc_string[41];
  +  int len;
  +  int i;
  +
  +  if (!w_current->filename_label) {
  +    return;
  +  }
  +
  +  if (string) {
  +    len = strlen(string);
  +    w_current->DONT_RESIZE = 1;
  +
  +    if (w_current->filename_label) {
  +      if (len > 40) {
  +
  +        trunc_string[0] = '.';
  +        trunc_string[1] = '.';
  +        trunc_string[2] = '.';
  +
  +        trunc_string[40] = '\0';
  +        for (i = 39 ; i > 2; i--) {
  +          if (len >= 0) {
  +            trunc_string[i] = string[len];
  +          } else {
  +            break;
  +          }
  +          len--;
  +        }
  +
  +        gtk_label_set(GTK_LABEL(w_current->
  +                                filename_label),
  +                      trunc_string);
  +
  +      } else {
  +
  +        gtk_label_set(GTK_LABEL(w_current->
  +                                filename_label),
  +                      (char *) string);
  +      }
  +    }
  +  }
  +}
  
  
  
  1.57      +2924 -1608eda/geda/gaf/gschem/src/i_callbacks.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: i_callbacks.c
  ===================================================================
  RCS file: i_callbacks.c
  diff -N i_callbacks.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ i_callbacks.c	14 Jul 2006 02:23:54 -0000	1.57
  @@ -0,0 +1,3767 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief */
  +#define DELIMITERS ", "
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Kazu Hirata <kazu@xxxxxxxx> on July 25, 1999 - Returns a pointer to
  + * the last '.' in the given string. If there is none, the function
  + * returns a pointer to the first null character in the string. If you
  + * want to change the extention using the return value of the
  + * function, you need to do pointer arithmetic, assuming your fname is
  + * defined as a constant. :-) Note that, if the only '.' appears as
  + * the first character, it is ignored. */
  +static const char *fnameext_get(const char* fname)
  +{
  +  const char *p = strrchr(fname, '.');
  +
  +  if((p == NULL) || (p == fname)) {
  +    p = &fname[strlen(fname)];
  +  }
  +  return p;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Kazu Hirata <kazu@xxxxxxxx> on July 25, 1999 - The function removes
  + * an extention including a '.' if any and returns the new string in a
  + * newly allocated memory. If there is no '.' after the first
  + * character, then the function simply returns a copy of fname. If
  + * memory allocation fails, the function returns NULL. */
  +static char *fnameext_remove(const char *fname)
  +{
  +  const char *p = fnameext_get(fname);
  +  char *fname_new;
  +  int len;
  +
  +  if(*p == '\0') {
  +    fname_new = g_strdup (p);
  +  } else {
  +    len = (p - fname); /*  + 1; this extra was causing grief */
  +    fname_new = (char *) malloc(sizeof(char) * (len + 1));
  +    if(fname_new == NULL) {
  +      return NULL;
  +    }
  +    strncpy(fname_new, fname, len);
  +    fname_new[len] = '\0';
  +  }
  +  return fname_new;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Kazu Hirata <kazu@xxxxxxxx> on July 25, 1999 - The function adds an
  + * extention and returns the new string in a newly allocated
  + * memory. ext must have '.'  as the first character. If memory
  + * allocation fails, the function returns NULL. */
  +static char *fnameext_add(const char *fname, const char* ext)
  +{
  +  return g_strconcat (fname, ext, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* Egil Kvaleberg <egil@xxxxxxxxxxxx> on October 7, 2002 - 
  + * Initiate the gschemdoc utility to provide the used with as much
  + * documentation on the symbol (i.e. component) as we can manage.
  + */
  +static void initiate_gschemdoc(const char* documentation,const char *device,
  +			       const char *value,
  +			       const char* symfile, const char *sympath)
  +{
  +
  +#ifndef __MINGW32__
  +
  +  int pid;
  +
  +  if (!documentation) documentation="";
  +  if (!device) device="";
  +  if (!value) value="";
  +  if (!symfile) symfile="";
  +  if (!sympath) sympath="";
  +
  +  s_log_message( _("Documentation for [%s,%s,%s,%s]\n"),
  +		    documentation,device,value,symfile);
  +
  +
  +  if ((pid = fork()) < 0) {
  +    fprintf(stderr, _("Could not fork\n"));
  +  } else if (pid == 0) {
  +    /* daughter process */
  +
  +    /* assume gschemdoc is part of path */
  +    char *gschemdoc = "gschemdoc";
  +
  +    execlp(gschemdoc, gschemdoc, documentation, device, value, symfile, sympath, NULL);
  +
  +    /* if we return, then nothing happened */
  +    fprintf(stderr, _("Could not invoke %s\n"), gschemdoc);
  +    _exit(0);
  +  }
  +#else
  +  s_log_message(_("Documentation commands not supported under MinGW.\n"));
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* evey i_callback functions have the same footprint */
  +#define DEFINE_I_CALLBACK(name)				\
  +	void i_callback_ ## name(gpointer data,		\
  +			         guint callback_action,	\
  +			         GtkWidget *widget)
  +
  +/*! \section callback-intro Callback Functions
  + * right now, all callbacks execpt for the ones on the File menu have
  + * the middle button shortcut. Let me (Ales) know if we should also
  + * shortcut the File button
  + */
  +
  +/*! \section file-menu File Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + *  \todo This should be renamed to page_new perhaps...
  + */
  +DEFINE_I_CALLBACK(file_new)
  +{
  +  TOPLEVEL *toplevel = (TOPLEVEL*)data;
  +  PAGE *page;
  +  gchar *filename;
  +
  +  exit_if_null (toplevel);
  +
  +  g_free (toplevel->cwd);
  +  toplevel->cwd = g_get_current_dir ();
  +#ifdef __MINGW32__
  +  u_basic_strip_trailing(toplevel->cwd, G_DIR_SEPARATOR);
  +#endif
  +  filename = g_strdup_printf ("%s%c%s_%d.sch",
  +                              toplevel->cwd,
  +                              G_DIR_SEPARATOR,
  +                              toplevel->series_name,
  +                              ++toplevel->num_untitled);
  +
  +  /* create a new page */
  +  page = s_page_new (toplevel, filename);
  +  /* change current page to page */
  +  s_page_goto (toplevel, page);
  +  g_free (filename);
  +
  +  s_log_message (_("New page created [%s]\n"),
  +                 toplevel->page_current->page_filename);
  +  
  +  x_pagesel_update (toplevel);
  +  i_update_menus (toplevel);
  +  i_set_filename (toplevel, toplevel->page_current->page_filename);
  +  x_manual_resize (toplevel);
  +  x_hscrollbar_update (toplevel);
  +  x_vscrollbar_update (toplevel);
  +  x_repaint_background (toplevel);
  +  o_undo_savestate (toplevel, UNDO_ALL);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + */
  +void i_callback_toolbar_file_new(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +    
  +  i_callback_file_new((TOPLEVEL*) data, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(file_new_window)
  +{
  +  TOPLEVEL *w_current;
  +       
  +  w_current = s_toplevel_new ();
  +  x_window_setup (w_current);
  +
  +  exit_if_null(w_current);
  +
  +  g_free (w_current->cwd);
  +  w_current->cwd = g_get_current_dir ();
  +#ifdef __MINGW32__
  +  u_basic_strip_trailing(w_current->cwd, G_DIR_SEPARATOR);
  +#endif
  +  g_free (w_current->page_current->page_filename);
  +  w_current->page_current->page_filename = g_strdup_printf (
  +    "%s%c%s_%d.sch",
  +    w_current->cwd,
  +    G_DIR_SEPARATOR,
  +    w_current->series_name,
  +    ++w_current->num_untitled);
  +
  +  s_log_message(_("New Window created\n"));
  +  i_set_filename(w_current, w_current->page_current->page_filename);
  +  x_repaint_background(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some
  + *  checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current)
  + *  \todo This should be renamed to page_open perhaps...
  + */
  +DEFINE_I_CALLBACK(file_open)
  +{
  +
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  x_fileselect_setup(w_current, FILESELECT, OPEN);
  +
  +#if 0 /* replaced by above */
  +  setup_open_file_selector(w_current);
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some
  + *  checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current)
  + *  \todo This should be renamed to page_open perhaps...
  + */
  +void i_callback_toolbar_file_open(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  i_callback_file_open((TOPLEVEL*) data, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(file_script)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  setup_script_selector(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some
  + *  checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current)
  + */
  +DEFINE_I_CALLBACK(file_save)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /*! \todo probably there should be a flag that says whether
  +   *   page_filename is derived from untitled_name or specified by
  +   *   a user. Some twisted people might name their files like
  +   *   untitled_name. :-)
  +   */
  +  if (strstr(w_current->page_current->page_filename,
  +             w_current->untitled_name)) {
  +    x_fileselect_setup(w_current, FILESELECT, SAVEAS_NONE);
  +#if 0 /* replaced with x_fileselect_setup */
  +    setup_saveas_file_selector(
  +                               w_current,
  +                               SAVEAS,
  +                               w_current->page_current->page_filename);
  +#endif
  +  } else {
  +
  +    if (f_save(w_current, w_current->page_current->page_filename) ) {
  +	    s_log_message(_("Saved [%s]\n"),w_current->page_current->page_filename);
  +	    /* don't know if should be kept going to select mode... */
  +	    w_current->page_current->CHANGED = 0;
  +	    i_set_state_msg(w_current, SELECT, _("Saved"));
  +	    i_update_toolbar(w_current);
  +            i_update_menus(w_current);
  +      x_pagesel_update (w_current);
  +    } else {
  +      	    s_log_message(_("Could NOT save [%s]\n"), w_current->page_current->page_filename);
  +
  +	    i_set_state_msg(w_current, SELECT, _("Error while trying to save"));
  +	    i_update_toolbar(w_current);
  +            i_update_menus(w_current);
  +    } 
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some
  + *  checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current)
  + *  \todo This should be renamed to page_open perhaps...
  + */
  +void i_callback_toolbar_file_save(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  i_callback_file_save((TOPLEVEL*) data, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current)
  + */
  +DEFINE_I_CALLBACK(file_save_all)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (s_page_save_all(w_current)) {
  +     i_set_state_msg(w_current, SELECT, _("Failed to Save All"));
  +  } else {
  +     i_set_state_msg(w_current, SELECT, _("Saved All"));
  +  }
  +
  +  i_update_toolbar(w_current);
  +  x_pagesel_update (w_current);
  +  i_update_menus(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(file_save_as)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  x_fileselect_setup(w_current, FILESELECT, SAVEAS_NONE);
  +
  +#if 0 /* replaced with above */
  +  setup_saveas_file_selector(w_current,
  +                             SAVEAS,
  +                             w_current->page_current->page_filename);
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(file_print)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  char *base=NULL;
  +  char *ps_filename=NULL;
  +  
  +  exit_if_null(w_current);
  +
  +  /* get the base file name */
  +  if (strcmp(fnameext_get(w_current->page_current->page_filename),
  +             ".sch") == 0) {
  +    /* the filename ends with .sch */
  +    base = fnameext_remove(w_current->page_current->page_filename);
  +  } else {
  +    /* the filename does not end with .sch */
  +    base = g_strdup (w_current->page_current->page_filename);
  +  }
  +  if(base == NULL) {
  +    /*! \todo do something */
  +  }
  +
  +  /* add ".ps" tp the base filename */
  +  ps_filename = fnameext_add(base, ".ps");
  +  free(base);
  +
  +  if (output_filename) {
  +    x_print_setup(w_current, output_filename);
  +  } else {
  +    x_print_setup(w_current, ps_filename);
  +  }
  +
  +  if (ps_filename) {
  +    free(ps_filename);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(file_write_png)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  char *base=NULL;
  +  char *img_filename=NULL;
  +
  +  exit_if_null(w_current);
  +
  +#if 0
  +#ifndef HAS_LIBGDGEDA
  +  /*! \todo integrate these to messages */
  +  fprintf(stderr,
  +          _("libgdgeda not installed or disabled, "
  +          "so this feature is disabled\n"));
  +  s_log_message(
  +		_("libgdgeda not installed or disabled, "
  +		"so this feature is disabled\n"));
  +  return;
  +#endif
  +#endif
  +  /* get the base file name */
  +  if (strcmp(fnameext_get(w_current->page_current->page_filename),
  +             ".sch") == 0) {
  +    /* the filename ends with .sch */
  +    base = fnameext_remove(w_current->page_current->page_filename);
  +  } else {
  +    /* the filename does not end with .sch */
  +    base = g_strdup (w_current->page_current->page_filename);
  +  }
  +  if(base == NULL) {
  +    /*! \todo do something */
  +  }
  +
  +  /* add ".png" tp the base filename */
  +  img_filename = fnameext_add(base, ".png");
  +  free(base);
  +
  +  if (output_filename) {
  +    x_image_setup(w_current, output_filename);
  +  } else {
  +    x_image_setup(w_current, img_filename);
  +  }
  +
  +  if (img_filename) {
  +    free(img_filename);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some
  + *  checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current)
  + *  this function closes a window
  + */
  +DEFINE_I_CALLBACK(file_close)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  s_log_message(_("Closing Window\n"));
  +  x_window_close(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function is called when you send a delete event to gschem
  + *
  + *  \note
  + *  Also DON'T ref the widget parameter since they can be null
  + *  \todo Need a cleaner way of doing this. This routine is used by the
  + *  delete event signals
  + */
  +int i_callback_close(gpointer data, guint callback_action, GtkWidget *widget)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  i_callback_file_close(w_current, 0, widget);
  +  return(FALSE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(file_quit)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  x_window_close_all(w_current);
  +}
  +
  +/*! \section edit-menu Edit Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_undo)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  w_current->DONT_REDRAW = 0;
  +  o_undo_callback(w_current, UNDO_ACTION);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + */
  +void i_callback_toolbar_edit_undo(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  i_callback_edit_undo((TOPLEVEL*) data, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_redo)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  w_current->DONT_REDRAW = 0;
  +  o_undo_callback(w_current, REDO_ACTION);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + */
  +void i_callback_toolbar_edit_redo(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  i_callback_edit_redo((TOPLEVEL*) data, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  Select also does not update the middle button shortcut.
  + */
  +DEFINE_I_CALLBACK(edit_select)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  o_redraw_cleanstates(w_current);	
  +
  +  /* this is probably the only place this should be */
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +  w_current->inside_action = 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + * since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + */
  +void i_callback_toolbar_edit_select(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  if (GTK_TOGGLE_BUTTON (widget)->active) {
  +    if (!o_erase_rubber(w_current)) {
  +      i_callback_cancel(w_current, 0, NULL);
  +    }
  +    i_callback_edit_select((TOPLEVEL*) data, 0, NULL);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_copy)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_copy, _("Copy"));
  +  if (o_select_return_first_object(w_current)) {
  +    i_set_state(w_current, STARTCOPY);
  +  } else {
  +    i_set_state_msg(w_current, SELECT, _("Select objs first"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_copy_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_copy_hotkey, _("Copy"));
  +  if (o_select_return_first_object(w_current)) {
  +    w_current->event_state = COPY; 
  +    o_redraw_cleanstates(w_current);	
  +    o_copy_start(w_current, mouse_x, mouse_y);
  +    w_current->event_state = ENDCOPY;
  +    w_current->inside_action = 1;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_mcopy)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_copy, _("Multiple Copy"));
  +  if (o_select_return_first_object(w_current)) {
  +    i_set_state(w_current, STARTMCOPY);
  +  } else {
  +    i_set_state_msg(w_current, SELECT, _("Select objs first"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_mcopy_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_mcopy_hotkey, _("Multiple Copy"));
  +  if (o_select_return_first_object(w_current)) {
  +    o_redraw_cleanstates(w_current);	
  +    w_current->event_state = MCOPY; 
  +    o_copy_start(w_current, mouse_x, mouse_y);
  +    w_current->event_state = ENDMCOPY;
  +    w_current->inside_action = 1;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_move)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_move, _("Move"));
  +  if (o_select_return_first_object(w_current)) {
  +    i_set_state(w_current, STARTMOVE);
  +  } else {
  +    i_set_state_msg(w_current, SELECT, _("Select objs first"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_move_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_move_hotkey, _("Move"));
  +  if (o_select_return_first_object(w_current)) {
  +    o_redraw_cleanstates(w_current);	
  +    o_move_start(w_current, mouse_x, mouse_y);
  +    w_current->event_state = ENDMOVE;
  +    w_current->inside_action = 1;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_delete)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_delete, _("Delete"));
  +
  +  if (o_select_return_first_object(w_current)) {
  +    o_redraw_cleanstates(w_current);	
  +    o_delete(w_current);
  +    /* if you delete the objects you must go into select
  +     * mode after the delete */
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    i_update_toolbar(w_current);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_edit)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_edit, _("Edit"));
  +  o_edit(w_current, w_current->page_current->selection2_head->next);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_text)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *object;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_text, _("Edit Text"));
  +  object = o_select_return_first_object(w_current);
  +  if (object) {
  +    if (object->type == OBJ_TEXT) {
  +      o_text_edit(w_current, object);
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_slot)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *object;
  +
  +  exit_if_null(w_current);
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_slot, _("Slot"));
  +  if (object) {
  +    o_slot_start(w_current, object);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_color)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_color, _("Color"));
  +
  +  color_edit_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function rotate all objects in the selection list by 90 degrees.
  + *
  + */
  +DEFINE_I_CALLBACK(edit_rotate_90)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_set_state(w_current, ENDROTATEP);
  +  i_update_middle_button(w_current, i_callback_edit_rotate_90, _("Rotate"));
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function rotate all objects in the selection list by 90 degrees.
  + *
  + */
  +DEFINE_I_CALLBACK(edit_rotate_90_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  SELECTION *s_current;
  +
  +  exit_if_null(w_current);
  +  o_redraw_cleanstates(w_current);	
  +
  +  if (w_current->page_current->selection2_head) {
  +    s_current = w_current->page_current->selection2_head->next;
  +    i_update_middle_button(w_current,
  +                           i_callback_edit_rotate_90_hotkey, _("Rotate"));
  +    /* Allow o_rotate_90 to redraw the objects */
  +    w_current->DONT_REDRAW = 0;
  +    o_rotate_90(w_current, s_current, mouse_x, mouse_y);
  +  }
  +
  +  w_current->event_state = SELECT;
  +  w_current->inside_action = 0;
  +  i_update_toolbar(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_mirror)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_set_state(w_current, ENDMIRROR);
  +  i_update_middle_button(w_current, i_callback_edit_mirror, _("Mirror"));
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_mirror_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *object;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  object = o_select_return_first_object(w_current);
  +
  +  if (object) {
  +    i_update_middle_button(w_current,
  +                           i_callback_edit_mirror_hotkey, _("Mirror"));
  +
  +    o_mirror(w_current, 
  +             w_current->page_current->selection2_head->next, 
  +             mouse_x, mouse_y);
  +  }
  +
  +  w_current->event_state = SELECT;
  +  w_current->inside_action = 0;
  +  i_update_toolbar(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function locks all objects in selection list.
  + *
  + */
  +DEFINE_I_CALLBACK(edit_lock)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_lock, _("Lock"));
  +
  +  if (o_select_return_first_object(w_current)) {
  +    o_lock(w_current);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  Thus function unlocks all objects in selection list.
  + */
  +DEFINE_I_CALLBACK(edit_unlock)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_unlock, _("Unlock"));
  +  if (o_select_return_first_object(w_current)) {
  +    o_unlock(w_current);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_translate)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current,
  +                         i_callback_edit_translate, _("Translate"));
  +
  +  if (w_current->snap == 0) {
  +    s_log_message(_("WARNING: Do not translate with snap off!\n"));
  +    s_log_message(_("WARNING: Turning snap on and continuing "
  +                  "with translate.\n"));
  +    w_current->snap = 1;
  +    i_show_state(w_current, NULL); /* update status on screen */
  +  }
  +
  +  if (w_current->snap_size != 100) {
  +    s_log_message(_("WARNING: Snap grid size is "
  +                  "not equal to 100!\n"));
  +    s_log_message(_("WARNING: If you are translating a symbol "
  +                  "to the origin, the snap grid size should be "
  +                  "set to 100\n"));
  +  }
  +
  +  translate_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function embedds all objects in selection list
  + *
  + */
  +DEFINE_I_CALLBACK(edit_embed)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_embed, _("Embed"));
  +  /* anything selected ? */
  +  if (o_select_selected(w_current)) {
  +    /* yes, embed each selected component */
  +    SELECTION *s_current =
  +      w_current->page_current->selection2_head->next;
  +
  +    while (s_current != NULL) {
  +      g_assert (s_current->selected_object != NULL);
  +      if ( (s_current->selected_object->type == OBJ_COMPLEX) ||
  +	   (s_current->selected_object->type == OBJ_PICTURE) ) {
  +        o_embed (w_current, s_current->selected_object);
  +      }
  +      s_current = s_current->next;
  +    }
  +  } else {
  +    /* nothing selected, go back to select state */
  +    o_redraw_cleanstates(w_current);	
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function unembedds all objects in selection list.
  + *
  + */
  +DEFINE_I_CALLBACK(edit_unembed)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_unembed, _("Unembed"));
  +  /* anything selected ? */
  +  if (o_select_selected(w_current)) {
  +    /* yes, unembed each selected component */
  +    SELECTION *s_current =
  +      w_current->page_current->selection2_head->next;
  +
  +    while (s_current != NULL) {
  +      g_assert (s_current->selected_object != NULL);
  +      if ( (s_current->selected_object->type == OBJ_COMPLEX) ||
  +           (s_current->selected_object->type == OBJ_PICTURE) ) {
  +        o_unembed (w_current, s_current->selected_object);
  +      }
  +      s_current = s_current->next;
  +    }
  +  } else {
  +    /* nothing selected, go back to select state */
  +    o_redraw_cleanstates(w_current);	
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function updates components
  + *
  + */
  +DEFINE_I_CALLBACK(edit_update)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_edit_update, _("Update"));
  +  /* anything selected ? */
  +  if (o_select_selected(w_current)) {
  +    /* yes, update each selected component */
  +    SELECTION *s_current =
  +      w_current->page_current->selection2_head->next;
  +
  +    while (s_current != NULL) {
  +      g_assert (s_current->selected_object != NULL);
  +      if (s_current->selected_object->type == OBJ_COMPLEX) {
  +        o_update_component (w_current,
  +                            s_current->selected_object);
  +      }
  +      s_current = s_current->next;
  +    }
  +  } else {
  +    /* nothing selected, go back to select state */
  +    o_redraw_cleanstates(w_current);	
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_show_hidden)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action)
  +    return;
  +
  +  i_update_middle_button(w_current,
  +                         i_callback_edit_show_hidden,
  +                         _("ShowHidden"));
  +
  +  o_edit_show_hidden(w_current, w_current->page_current->object_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_make_visible)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action)
  +    return;
  +
  +  i_update_middle_button(w_current,
  +                         i_callback_edit_make_visible,
  +                         _("MakeVisible"));
  +
  +  o_edit_make_visible(w_current, w_current->page_current->object_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_find)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action)
  +    return;
  +
  +  find_text_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_hide_text)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action)
  +    return;
  +
  +  hide_text_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_show_text)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action)
  +    return;
  +
  +  show_text_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_autonumber_text)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action)
  +    return;
  +
  +  autonumber_text_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_linetype)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* anything selected ? */
  +  if (o_select_selected(w_current)) {
  +    SELECTION *s_current =
  +      w_current->page_current->selection2_head->next;
  +    GList *objects = NULL;
  +
  +    /* yes, build a list of relevant objects */
  +    while (s_current != NULL) {
  +      OBJECT *o_current = s_current->selected_object;
  +          
  +      if (o_current->type == OBJ_LINE   ||
  +          o_current->type == OBJ_BOX    ||
  +          o_current->type == OBJ_CIRCLE ||
  +          o_current->type == OBJ_ARC) {
  +        objects = g_list_prepend (objects, o_current);
  +      }
  +
  +      s_current = s_current->next;
  +    }
  +
  +    if (objects != NULL) {
  +      /* at least one object in the list */
  +      i_update_middle_button(w_current,
  +                             i_callback_edit_color,
  +                             _("Edit Line Type"));
  +      /* enter edition of parameters of selected objects */
  +      line_type_dialog(w_current, objects);
  +    }
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(edit_filltype)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* anything selected ? */
  +  if (o_select_selected(w_current)) {
  +    SELECTION *s_current =
  +      w_current->page_current->selection2_head->next;
  +    GList *objects = NULL;
  +
  +    /* yes, build a list of relevant objects */
  +    while (s_current != NULL) {
  +      OBJECT *o_current = s_current->selected_object;
  +          
  +      if (o_current->type == OBJ_BOX ||
  +          o_current->type == OBJ_CIRCLE) {
  +        objects = g_list_prepend (objects, o_current);
  +      }
  +
  +      s_current = s_current->next;
  +    }
  +
  +    if (objects != NULL) {
  +      /* at least one object in the list */
  +      i_update_middle_button(w_current,
  +                             i_callback_edit_color,
  +                             _("Edit Fill Type"));
  +      /* enter edition of parameters of selected objects */
  +      fill_type_dialog(w_current, objects);
  +    }
  +  }
  +  
  +}
  +
  +/*! \section view-menu View Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat middle shortcut doesn't make sense on redraw, just hit right
  + *  button
  + */
  +DEFINE_I_CALLBACK(view_redraw)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  o_redraw_all(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat middle shortcut would get into the way of what user is try to do
  + */
  +DEFINE_I_CALLBACK(view_zoom_full)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* scroll bar stuff */
  +  a_zoom(w_current, ZOOM_FULL, DONTCARE, 0);
  +  o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat middle shortcut would get into the way of what user is try to do
  + */
  +DEFINE_I_CALLBACK(view_zoom_extents)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* scroll bar stuff */
  +  a_zoom_extents(w_current, w_current->page_current->object_head, 0);
  +  o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat middle shortcut would get into the way of what user is try to do
  + */
  +DEFINE_I_CALLBACK(view_zoom_box)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  w_current->inside_action = 0;
  +  i_allow_expose();
  +  i_set_state(w_current, ZOOMBOXSTART);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(view_zoom_box_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  a_zoom_box_start(w_current, mouse_x, mouse_y);
  +
  +  w_current->inside_action = 1;
  +  i_allow_expose();
  +  i_set_state(w_current, ZOOMBOXEND);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat middle shortcut would get into the way of what user is try to do
  + */
  +DEFINE_I_CALLBACK(view_zoom_in)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  a_zoom(w_current, ZOOM_IN, MENU, 0);
  +  o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat middle shortcut would get into the way of what user is try to do
  + */
  +DEFINE_I_CALLBACK(view_zoom_out)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  a_zoom(w_current, ZOOM_OUT, MENU, 0);
  +  o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat middle shortcut would get into the way of what user is try
  + *  to do
  + */
  +DEFINE_I_CALLBACK(view_zoom_in_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  a_zoom(w_current, ZOOM_IN, HOTKEY, 0);
  +  o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat middle shortcut would get into the way of what user is try to do
  + */
  +DEFINE_I_CALLBACK(view_zoom_out_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  a_zoom(w_current, ZOOM_OUT, HOTKEY, 0);
  +  o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(view_pan)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  w_current->inside_action = 0;
  +  i_set_state(w_current, STARTPAN);
  +
  +  /* I don't know if this would get in the way */
  +  i_update_middle_button(w_current, i_callback_view_pan, _("Pan"));
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(view_pan_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  /* I don't know if this would get in the way */
  +  i_update_middle_button(w_current, i_callback_view_pan_hotkey, _("Pan"));
  +
  +  /* I have NO idea what ramifications removing the next line has,
  +   * only that it makes the code work when drawing a net and panning
  +   * at the same time.  Jeff McNeal - 11-19-98
  +   * w_current->inside_action = 0;
  +   * I think it's okay - Ales 12/13/98 */
  +
  +  a_pan(w_current, mouse_x, mouse_y);
  +
  +  /* Jeff McNeal on Nov 19, 1998 - if we are drawing a net,
  +   * don't change the event state, because we want to continue
  +   * drawing a net. If we are just panning, then continue in
  +   * select mode.  */
  +  /* removed the limitations of the pan mode (werner) */
  +  /* if(!(w_current->event_state == DRAWNET ||
  +       w_current->event_state == NETCONT ||
  +       w_current->event_state == STARTDRAWNET )) {
  +    i_set_state(w_current, SELECT);
  +    i_update_toolbar(w_current);
  +    } */
  +  o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(view_update_cues)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  i_update_middle_button(w_current,
  +                         i_callback_view_update_cues, _("Update Cues"));
  +
  +  o_redraw_all(w_current);
  +}
  +
  +/*! \section page-menu Page Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(page_manager)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  x_pagesel_open (w_current);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(page_next)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL*)data;
  +  PAGE *p_current = w_current->page_current;
  +  PAGE *p_new;
  +
  +  exit_if_null(w_current);
  +
  +  if (p_current->next == NULL) {
  +    return;
  +  }
  +
  +  if (w_current->enforce_hierarchy) {
  +    p_new = s_hierarchy_find_next_page(p_current, 
  +                                       p_current->page_control);
  +  } else {
  +    p_new = p_current->next;
  +  }
  +
  +  if (p_new == NULL || p_new == p_current) {
  +    return;
  +  }
  +
  +  s_page_goto (w_current, p_new);
  +  
  +  i_set_filename(w_current, w_current->page_current->page_filename);
  +  x_scrollbars_update(w_current);
  +  o_redraw_all(w_current);
  +  x_pagesel_update (w_current);
  +  i_update_menus(w_current);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(page_prev)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL*)data;
  +  PAGE *p_current = w_current->page_current;
  +  PAGE *p_new;
  +
  +  exit_if_null(w_current);
  +
  +  if (p_current->prev == NULL || p_current->prev->pid == -1) {
  +    return;
  +  }
  +
  +  if (w_current->enforce_hierarchy == TRUE) {
  +    p_new = s_hierarchy_find_prev_page(p_current, 
  +                                       p_current->page_control);
  +  } else {
  +    p_new = p_current->prev;
  +  }
  +
  +  if (p_new == NULL || p_new == p_current) {
  +    return;
  +  }
  +
  +  s_page_goto (w_current, p_new);
  +  
  +  i_set_filename(w_current, w_current->page_current->page_filename);
  +  x_scrollbars_update(w_current);
  +  o_redraw_all(w_current);
  +  x_pagesel_update (w_current);
  +  i_update_menus(w_current);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(page_new)
  +{
  +  TOPLEVEL *toplevel = (TOPLEVEL*)data;
  +  PAGE *page;
  +  gchar *filename;
  +
  +  exit_if_null(toplevel);
  +
  +  g_free (toplevel->cwd);
  +  toplevel->cwd = g_get_current_dir ();
  +#ifdef __MINGW32__
  +  u_basic_strip_trailing(toplevel->cwd, G_DIR_SEPARATOR);
  +#endif
  +  filename = g_strdup_printf ("%s%c%s_%d.sch",
  +                              toplevel->cwd,
  +                              G_DIR_SEPARATOR,
  +                              toplevel->series_name,
  +                              ++toplevel->num_untitled);
  +
  +  /* create the new page */
  +  page = s_page_new (toplevel, filename);
  +  /* change current page to page */
  +  s_page_goto (toplevel, page);
  +  g_free (filename);
  +
  +  s_log_message(_("New Page created [%s]\n"),
  +                toplevel->page_current->page_filename);
  +  
  +  x_pagesel_update (toplevel);
  +  i_update_menus (toplevel);
  +  i_set_filename (toplevel, toplevel->page_current->page_filename);
  +  o_redraw_all (toplevel);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(page_close)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  PAGE *p_current;
  +  PAGE *p_save;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->CHANGED) {
  +    x_fileselect_setup(w_current, FILESELECT, SAVEAS_CLOSE);
  +    return;
  +  }
  +
  +  /* Can we go up in the hierarchy first? */
  +  p_current = s_hierarchy_find_page(w_current->page_head, 
  +                                    w_current->page_current->up);
  +  if (p_current) {
  +    s_log_message(_("Closing [%s]\n"),
  +                  w_current->page_current->page_filename);
  +    s_page_delete (w_current, w_current->page_current);
  +
  +    s_page_goto (w_current, p_current);
  +
  +    i_set_filename(w_current, w_current->page_current->page_filename);
  +    x_scrollbars_update(w_current);
  +    o_redraw_all(w_current);
  +    x_pagesel_update (w_current);
  +    i_update_menus(w_current);
  +    return;
  +  }
  +
  +  /* is there a page before current? */
  +  if (w_current->page_current->prev &&
  +      w_current->page_current->prev->pid != -1) {
  +        /* yes, change to previous page */
  +        p_current = w_current->page_current->prev;
  +        s_log_message(_("Closing [%s]\n"),
  +                      w_current->page_current->page_filename);
  +        s_page_delete (w_current, w_current->page_current);
  +        
  +        s_page_goto (w_current, p_current);
  +        
  +        i_set_filename(w_current, w_current->page_current->page_filename);
  +        x_scrollbars_update(w_current);
  +        o_redraw_all(w_current);
  +        x_pagesel_update (w_current);
  +        i_update_menus(w_current);
  +        return;
  +      }
  +
  +  /* is there a page after current? */
  +  if (w_current->page_current->next) {
  +    /* yes, change to next page */
  +    g_assert (w_current->page_current->next->pid != -1);
  +    
  +    p_current = w_current->page_current->next;
  +    s_log_message(_("Closing [%s]\n"),
  +                  w_current->page_current->page_filename);
  +    s_page_delete (w_current, w_current->page_current);
  +    
  +    s_page_goto (w_current, p_current);
  +    
  +    i_set_filename(w_current, w_current->page_current->page_filename);
  +    x_scrollbars_update(w_current);
  +    o_redraw_all(w_current);
  +    x_pagesel_update (w_current);
  +    i_update_menus(w_current);
  +    return;
  +  }
  +
  +  /* finally go here if you can't delete the page */
  +  /* because it's the last page being displayed */
  +  /* s_log_message("Cannot close current page\n");*/
  +  /* now the code creates a new page, and closes the old one */
  +  p_save = w_current->page_current;
  +  i_callback_page_new(w_current, 0, NULL);
  +  w_current->page_current = p_save;	
  +
  +  g_assert (w_current->page_current->next != NULL);
  +  g_assert (w_current->page_current->next->pid != -1);
  +  
  +  p_current = w_current->page_current->next;
  +  s_log_message(_("Closing [%s]\n"),
  +                w_current->page_current->page_filename);
  +  s_page_delete (w_current, w_current->page_current);
  +
  +  s_page_goto (w_current, p_current);
  +  
  +  i_set_filename(w_current, w_current->page_current->page_filename);
  +  x_scrollbars_update(w_current);
  +  o_redraw_all(w_current);
  +  x_pagesel_update (w_current);
  +  i_update_menus(w_current);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \bug may have memory leak?
  + */
  +DEFINE_I_CALLBACK(page_revert)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  PAGE *page;
  +  gchar *filename;
  +  int page_control;
  +  int up;
  +#ifdef HAS_GTK22
  +  int response;
  +  GtkWidget* dialog;
  +#endif
  +
  +  exit_if_null(w_current);
  +
  +#ifdef HAS_GTK22
  + dialog = gtk_message_dialog_new ((GtkWindow*) w_current->main_window,
  +                                  GTK_DIALOG_DESTROY_WITH_PARENT,
  +                                  GTK_MESSAGE_QUESTION,
  +                                  GTK_BUTTONS_YES_NO,
  +                                  _("Really revert page?"));
  + response = gtk_dialog_run (GTK_DIALOG (dialog));
  + gtk_widget_destroy (dialog);
  + 
  + switch (response) 
  + {
  +   case GTK_RESPONSE_NO:
  +     return; /* don't continue */
  +   break; 
  +
  +   case GTK_RESPONSE_YES:
  +   /* just fall through */
  +   break;
  + }
  +#endif
  +
  +  /* save this for later */
  +  filename = g_strdup (w_current->page_current->page_filename);
  +  page_control = w_current->page_current->page_control;
  +  up = w_current->page_current->up;
  +
  +  /* delete the page, create a new one and make it the new current */
  +  s_page_delete (w_current, w_current->page_current);
  +  page = s_page_new (w_current, filename);
  +  s_page_goto (w_current, page);
  +  g_free (filename);
  +
  +  /* now re open it */
  +  f_open(w_current, w_current->page_current->page_filename);
  +  i_set_filename(w_current, w_current->page_current->page_filename);
  +
  +  /* make sure we maintain the hierarchy info */
  +  w_current->page_current->page_control = page_control;
  +  w_current->page_current->up = up;
  +
  +  x_repaint_background(w_current);
  +  x_manual_resize(w_current);
  +  a_zoom_extents(w_current, w_current->page_current->object_head,
  +                A_PAN_DONT_REDRAW);
  +  o_undo_savestate(w_current, UNDO_ALL);
  +
  +  /* now update the scrollbars */
  +  x_hscrollbar_update(w_current);
  +  x_vscrollbar_update(w_current);
  +  x_pagesel_update (w_current);
  +  i_update_menus(w_current);
  +
  +  o_redraw_all(w_current);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(page_discard)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL*)data;
  +  PAGE *p_current;
  +  PAGE *p_save;
  +
  +  exit_if_null(w_current);
  +
  +  /* Can we go up in the hierarchy first? */
  +  p_current = s_hierarchy_find_page(w_current->page_head, 
  +                                    w_current->page_current->up);
  +  if (p_current) {
  +    s_log_message(_("Closing [%s]\n"),
  +                  w_current->page_current->page_filename);
  +    s_page_delete (w_current, w_current->page_current);
  +
  +    s_page_goto (w_current, p_current);
  +
  +    i_set_filename(w_current, w_current->page_current->page_filename);
  +    x_scrollbars_update(w_current);
  +    o_redraw_all(w_current);
  +    x_pagesel_update (w_current);
  +    i_update_menus(w_current);
  +    return;
  +  }
  +
  +  /* is there a page before current? */
  +  if (w_current->page_current->prev &&
  +      w_current->page_current->prev->pid != -1) {
  +        /* yes, change to previous page */
  +        p_current = w_current->page_current->prev;
  +        s_log_message(_("Discarding page [%s]\n"),
  +                      w_current->page_current->page_filename);
  +        s_page_delete (w_current, w_current->page_current);
  +
  +        s_page_goto (w_current, p_current);
  +        
  +        i_set_filename(w_current, w_current->page_current->page_filename);
  +        x_scrollbars_update(w_current);
  +        o_redraw_all(w_current);
  +        x_pagesel_update (w_current);
  +        i_update_menus(w_current);
  +        return;
  +      }
  +
  +  /* is there a page after current? */
  +  if (w_current->page_current->next) {
  +    /* yes, change to next page */
  +    g_assert (w_current->page_current->next->pid != -1);
  +
  +    p_current = w_current->page_current->next;
  +    s_log_message(_("Discarding page [%s]\n"),
  +                  w_current->page_current->page_filename);
  +    s_page_delete (w_current, w_current->page_current);
  +
  +    s_page_goto (w_current, p_current);
  +    
  +    i_set_filename(w_current, w_current->page_current->page_filename);
  +    x_scrollbars_update(w_current);
  +    o_redraw_all(w_current);
  +    x_pagesel_update (w_current);
  +    i_update_menus(w_current);
  +    return;
  +  }
  +
  +  /* finally go here if you can't delete the page */
  +  /* because it's the last page being displayed */
  +  /* s_log_message("Cannot close current page\n");*/
  +  /* now the code creates a new page, and closes the old one */
  +  p_save = w_current->page_current;
  +  i_callback_page_new(w_current, 0, NULL);
  +  w_current->page_current = p_save;	
  +
  +  g_assert (w_current->page_current->next != NULL);
  +  g_assert (w_current->page_current->next->pid != -1);
  +  
  +  p_current = w_current->page_current->next;
  +  s_log_message(_("Discarding page [%s]\n"),
  +                w_current->page_current->page_filename);
  +  s_page_delete (w_current, w_current->page_current);
  +
  +  s_page_goto (w_current, p_current);
  +
  +  i_set_filename(w_current, w_current->page_current->page_filename);
  +  x_scrollbars_update(w_current);
  +  o_redraw_all(w_current);
  +  x_pagesel_update (w_current);
  +  i_update_menus(w_current);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(page_print)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  s_page_print_all(w_current);
  +}
  +
  +/*! \section buffer-menu Buffer Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_copy1)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_copy1, _("Copy 1"));
  +  o_buffer_copy(w_current, 0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_copy2)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_copy2, _("Copy 2"));
  +  o_buffer_copy(w_current, 1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_copy3)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_copy3, _("Copy 3"));
  +  o_buffer_copy(w_current, 2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_copy4)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_copy4, _("Copy 4"));
  +  o_buffer_copy(w_current, 3);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_copy5)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_copy5, _("Copy 5"));
  +  o_buffer_copy(w_current, 4);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_cut1)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_cut1, _("Cut 1"));
  +  o_buffer_cut(w_current, 0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_cut2)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_cut2, _("Cut 2"));
  +  o_buffer_cut(w_current, 1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_cut3)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_cut3, _("Cut 3"));
  +  o_buffer_cut(w_current, 2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_cut4)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_cut4, _("Cut 4"));
  +  o_buffer_cut(w_current, 3);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_cut5)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->page_current->selection2_head->next == NULL)
  +  return;
  +
  +  i_update_middle_button(w_current, i_callback_buffer_cut5, _("Cut 5"));
  +  o_buffer_cut(w_current, 4);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste1)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_buffer_paste1, _("Paste 1"));
  +  if (object_buffer[0] != NULL) {
  +    if (object_buffer[0]->next != NULL) {
  +      o_redraw_cleanstates(w_current);	
  +      w_current->buffer_number = 0;
  +      w_current->inside_action = 1;
  +      i_set_state(w_current, STARTPASTE);
  +    }
  +  } else { 
  +    i_set_state_msg(w_current, SELECT, _("Empty buffer"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste2)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_buffer_paste2, _("Paste 2"));
  +  if (object_buffer[1] != NULL) {
  +    if (object_buffer[1]->next != NULL) {
  +      o_redraw_cleanstates(w_current);	
  +      w_current->buffer_number = 1;
  +      w_current->inside_action = 1;
  +      i_set_state(w_current, STARTPASTE);
  +    }
  +  } else {
  +    i_set_state_msg(w_current, SELECT, _("Empty buffer"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste3)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_buffer_paste3, _("Paste 3"));
  +  if (object_buffer[2] != NULL) {
  +    if (object_buffer[2]->next != NULL) {
  +      o_redraw_cleanstates(w_current);	
  +      w_current->buffer_number = 2;
  +      w_current->inside_action = 1;
  +      i_set_state(w_current, STARTPASTE);
  +    }
  +  } else { 
  +    i_set_state_msg(w_current, SELECT, _("Empty buffer"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste4)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_buffer_paste4, _("Paste 4"));
  +  if (object_buffer[3] != NULL) {
  +    if (object_buffer[3]->next != NULL) {
  +      o_redraw_cleanstates(w_current);	
  +      w_current->buffer_number = 3;
  +      w_current->inside_action = 1;
  +      i_set_state(w_current, STARTPASTE);
  +    }
  +  } else {
  +    i_set_state_msg(w_current, SELECT, _("Empty buffer"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste5)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_buffer_paste5, _("Paste 5"));
  +  if (object_buffer[4] != NULL) {
  +    if (object_buffer[4]->next != NULL) {
  +      o_redraw_cleanstates(w_current);	
  +      w_current->buffer_number = 4;
  +      w_current->inside_action = 1;
  +      i_set_state(w_current, STARTPASTE);
  +    }
  +  } else {
  +    i_set_state_msg(w_current, SELECT, _("Empty buffer"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste1_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (object_buffer[0] == NULL) {
  +    return;
  +  }
  +
  +  if (object_buffer[0]->next == NULL)  {
  +    return;
  +	
  +  }
  +	
  +  o_buffer_paste_start(w_current, mouse_x, mouse_y, 0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste2_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (object_buffer[1] == NULL) {
  +    return;
  +  }
  +
  +  if (object_buffer[1]->next == NULL)  {
  +    return;
  +	
  +  }
  +
  +  o_buffer_paste_start(w_current, mouse_x, mouse_y, 1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste3_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (object_buffer[2] == NULL) {
  +    return;
  +  }
  +
  +  if (object_buffer[2]->next == NULL)  {
  +    return;
  +	
  +  }
  +
  +  o_buffer_paste_start(w_current, mouse_x, mouse_y, 2);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste4_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (object_buffer[3] == NULL) {
  +    return;
  +  }
  +
  +  if (object_buffer[3]->next == NULL)  {
  +    return;
  +	
  +  }
  +
  +  o_buffer_paste_start(w_current, mouse_x, mouse_y, 3);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(buffer_paste5_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (object_buffer[4] == NULL) {
  +    return;
  +  }
  +
  +  if (object_buffer[4]->next == NULL)  {
  +    return;
  +	
  +  }
  +
  +  o_buffer_paste_start(w_current, mouse_x, mouse_y, 4);
  +}
  +
  +/*! \section add-menu Add Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_component)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  x_fileselect_setup(w_current, COMPSELECT, -1);
  +
  +#if 0 /* replaced by above */
  +  setup_place_file_selector(w_current);
  +#endif
  +  i_update_middle_button(w_current,
  +                         i_callback_add_component, _("Component"));
  +
  +  i_allow_expose();
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking... 
  + *  since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + */
  +void i_callback_toolbar_add_component(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  i_callback_add_component((TOPLEVEL*) data, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_attribute)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  attrib_edit_dialog(w_current, NULL, FROM_MENU);
  +  i_update_middle_button(w_current, i_callback_add_attribute,
  +                         _("Attribute"));
  +
  +  i_allow_expose();
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_attribute_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  attrib_edit_dialog(w_current, NULL, FROM_HOTKEY);
  +  i_update_middle_button(w_current, i_callback_add_attribute_hotkey,
  +                         _("Attribute"));
  +
  +  i_allow_expose();
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_net)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  /* need to click */
  +  i_update_middle_button(w_current, i_callback_add_net, _("Net"));
  +  i_allow_expose();
  +  i_set_state(w_current, STARTDRAWNET);
  +  i_update_toolbar(w_current);
  +  /* somewhere you need to nearest point locking... */
  +  w_current->inside_action = 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_net_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  /* need to click */
  +  i_update_middle_button(w_current, i_callback_add_net_hotkey, _("Net"));
  +  i_allow_expose();
  +  i_set_state(w_current, STARTDRAWNET);
  +  i_update_toolbar(w_current);
  +
  +  o_net_start(w_current, mouse_x, mouse_y);
  +
  +  w_current->event_state=DRAWNET;
  +  w_current->inside_action = 1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + */
  +void i_callback_toolbar_add_net(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  if (GTK_TOGGLE_BUTTON (widget)->active) {
  +    i_callback_add_net((TOPLEVEL*) data, 0, NULL);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_bus)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  /* need to click */
  +  i_update_middle_button(w_current, i_callback_add_bus, _("Bus"));
  +  i_allow_expose();
  +  i_set_state(w_current, STARTDRAWBUS);
  +  i_update_toolbar(w_current);
  +
  +  /* somewhere you need to nearest point locking... */
  +  w_current->inside_action = 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_bus_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  /* need to click */
  +  i_update_middle_button(w_current, i_callback_add_bus_hotkey, _("Bus"));
  +  i_allow_expose();
  +  i_set_state(w_current, STARTDRAWBUS);
  +  i_update_toolbar(w_current);
  +
  +  o_bus_start(w_current, mouse_x, mouse_y);
  +
  +  w_current->event_state=DRAWBUS;
  +  w_current->inside_action = 1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + */
  +void i_callback_toolbar_add_bus(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  if (GTK_TOGGLE_BUTTON (widget)->active) {
  +     i_callback_add_bus((TOPLEVEL*) data, 0, NULL);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_text)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  w_current->inside_action = 0;
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +
  +  text_input_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use the widget parameter on this function, or do some checking...
  + *  since there is a call: widget = NULL, data = 0 (will be w_current hack)
  + */
  +void i_callback_toolbar_add_text(GtkWidget* widget, gpointer data)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +  if (!w_current->window) return;
  +
  +  i_callback_add_text((TOPLEVEL*) data, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_line)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_line, _("Line"));
  +  i_allow_expose();
  +  i_set_state(w_current, DRAWLINE);
  +  w_current->inside_action = 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_line_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_line_hotkey, _("Line"));
  +
  +  o_line_start(w_current, mouse_x, mouse_y);
  +
  +  w_current->inside_action = 1;
  +  i_allow_expose();
  +  i_set_state(w_current, ENDLINE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_box)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_box, _("Box"));
  +  w_current->inside_action = 0;
  +  i_allow_expose();
  +  i_set_state(w_current, DRAWBOX);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_box_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_box_hotkey, _("Box"));
  +
  +  o_box_start(w_current, mouse_x, mouse_y);
  +
  +  w_current->inside_action = 1;
  +  i_allow_expose();
  +  i_set_state(w_current, ENDBOX);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_picture)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  w_current->inside_action = 0;
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +
  +  picture_selection_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_picture_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  /* If this function necessary? Yes, if you want the hotkey to work. */
  +  i_callback_add_picture(w_current, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_circle)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_circle, _("Circle"));
  +  w_current->inside_action = 0;
  +  i_allow_expose();
  +  i_set_state(w_current, DRAWCIRCLE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_circle_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_circle_hotkey,
  +                         _("Circle"));
  +
  +  o_circle_start(w_current, mouse_x, mouse_y);
  +
  +  w_current->inside_action = 1;
  +  i_allow_expose();
  +  i_set_state(w_current, ENDCIRCLE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_arc)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_arc, _("Arc"));
  +  w_current->inside_action = 0;
  +  i_allow_expose();
  +  i_set_state(w_current, DRAWARC);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_arc_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_arc_hotkey, _("Arc"));
  +
  +  o_arc_start(w_current, mouse_x, mouse_y);
  +
  +  w_current->inside_action = 1;
  +  i_allow_expose();
  +  i_set_state(w_current, ENDARC);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_pin)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_pin, _("Pin"));
  +  w_current->inside_action = 0;
  +  i_allow_expose();
  +  i_set_state(w_current, DRAWPIN);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(add_pin_hotkey)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  o_redraw_cleanstates(w_current);	
  +  o_erase_rubber(w_current);
  +
  +  i_update_middle_button(w_current, i_callback_add_pin_hotkey, _("Pin"));
  +
  +  o_pin_start(w_current, mouse_x, mouse_y);
  +
  +  w_current->inside_action = 1;
  +  i_allow_expose();
  +  i_set_state(w_current, ENDPIN);
  +}
  +
  +/*! \section hierarchy-menu Hierarchy Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(hierarchy_down_schematic)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  char *attrib=NULL;
  +  char *current_filename=NULL;
  +  int count=0;
  +  OBJECT *object=NULL;
  +  PAGE *save_first_page=NULL;
  +  PAGE *parent=NULL;
  +  int loaded_flag=FALSE;
  +  int page_control = 0;
  +  int saved_page_control = 0;
  +  int pcount = 0;
  +  int looking_inside=FALSE;
  +
  +  exit_if_null(w_current);
  +
  +  object = o_select_return_first_object(w_current);
  +  if (object != NULL) {
  +    /* only allow going into symbols */
  +    if (object->type == OBJ_COMPLEX) {
  +
  +      parent = w_current->page_current;
  +      attrib = o_attrib_search_name_single_count(object,
  +                                                 "source",
  +                                                 count);
  +
  +      /* if above is null, then look inside symbol */
  +      if (attrib == NULL) {
  +        attrib = o_attrib_search_name(object->
  +                                      complex->
  +                                      prim_objs,
  +                                      "source", 
  +                                      count);
  +        looking_inside = TRUE;
  +#if DEBUG
  +        printf("going to look inside now\n");
  +#endif
  +      }
  +
  +      while (attrib) {
  +
  +				/* look for source=filename,filename, ... */
  +        pcount = 0;
  +        
  +        current_filename = u_basic_breakup_string(attrib, ',', pcount);
  +
  +				/* loop over all filenames */
  +        while(current_filename != NULL) {
  +
  +          s_log_message(
  +                        _("Searching for source [%s]\n"), 
  +                        current_filename);
  +          saved_page_control = page_control;
  +          page_control = 
  +            s_hierarchy_down_schematic_single(
  +                                              w_current, 
  +                                              current_filename, 
  +                                              parent,
  +                                              page_control,
  +                                              HIERARCHY_NORMAL_LOAD);
  +
  +          if (page_control != -1)  {
  +            a_zoom_extents(w_current, 
  +                          w_current->
  +                          page_current->
  +                          object_head,
  +                          A_PAN_DONT_REDRAW);
  +            o_undo_savestate(w_current, 
  +                             UNDO_ALL);
  +          }
  +
  +
  +          /* save the first page */
  +          if (!loaded_flag && 
  +              page_control != -1 && 
  +              page_control != 0) {
  +            save_first_page = w_current->
  +              page_current;
  +          }
  +
  +          /* now do some error fixing */
  +          if (page_control == -1) {
  +            s_log_message(
  +                          _("Cannot find source [%s]\n"), 
  +                          current_filename);
  +            fprintf(stderr, 
  +                    _("Cannot find source [%s]\n"), 
  +                    current_filename); 
  +
  +            /* restore this for the next */
  +            /* page */
  +            page_control = 
  +              saved_page_control;
  +          } else {
  +            /* this only signifies that */
  +            /* we tried */
  +            loaded_flag = TRUE;
  +          }
  +
  +          free(current_filename);
  +          pcount++;
  +          current_filename = u_basic_breakup_string(attrib, ',', pcount);
  +        }
  +
  +        if (attrib) {
  +          free(attrib);
  +        }
  +
  +        if (current_filename) {
  +          free(current_filename);
  +        }
  +
  +        count++;
  +
  +				/* continue looking outside first */
  +        if (!looking_inside) {
  +          attrib = 
  +            o_attrib_search_name_single_count(object, "source", count);
  +        } 
  +
  +				/* okay we were looking outside and didn't */
  +				/* find anything, so now we need to look */
  +				/* inside the symbol */
  +        if (!looking_inside && attrib == NULL && !loaded_flag ) {
  +          looking_inside = TRUE;
  +#if DEBUG
  +          printf("switching to go to look inside\n");
  +#endif
  +        }
  +
  +        if (looking_inside) {
  +#if DEBUG
  +          printf("looking inside\n");
  +#endif
  +          attrib = o_attrib_search_name(
  +                                        object->complex->
  +                                        prim_objs,
  +                                        "source",
  +                                        count);
  +        }
  +      } 
  +
  +      if (loaded_flag) {
  +	
  +        if (save_first_page) {
  +          w_current->page_current = 
  +            save_first_page;
  +        }
  +        i_set_filename(w_current, w_current->
  +                       page_current->page_filename);
  +        a_zoom_extents(w_current, 
  +                      w_current->page_current->object_head,
  +                      A_PAN_DONT_REDRAW);
  +        o_redraw_all(w_current);
  +	x_scrollbars_update(w_current);
  +        x_pagesel_update (w_current);
  +        i_update_menus(w_current);
  +      }
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(hierarchy_down_symbol)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *object;
  +  char *filename;
  +
  +  exit_if_null(w_current);
  +
  +  object = o_select_return_first_object(w_current);
  +  if (object != NULL) {
  +    /* only allow going into symbols */
  +    if (object->type == OBJ_COMPLEX &&
  +        !o_complex_is_embedded (object)) {
  +      filename = g_strconcat (object->complex_clib, 
  +                              G_DIR_SEPARATOR_S,
  +                              object->complex_basename, NULL);
  +      s_log_message(_("Searching for symbol [%s]\n"), filename);
  +      s_hierarchy_down_symbol(w_current, filename, 
  +                              w_current->page_current);
  +      i_set_filename(w_current,
  +                     w_current->page_current->page_filename);
  +      a_zoom_extents(w_current, 
  +                    w_current->page_current->object_head,
  +                    A_PAN_DONT_REDRAW);
  +      x_scrollbars_update(w_current);
  +      o_undo_savestate(w_current, UNDO_ALL);
  +      o_redraw_all(w_current);
  +      x_pagesel_update (w_current);
  +      i_update_menus(w_current);
  +      free(filename);
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(hierarchy_up)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  
  +  exit_if_null(w_current);
  +  
  +  s_hierarchy_up(w_current, w_current->page_current->up);
  +  i_set_filename(w_current, w_current->page_current->page_filename);
  +  x_scrollbars_update(w_current);
  +  o_redraw_all(w_current);
  +  x_pagesel_update (w_current);
  +  i_update_menus(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  Egil Kvaleberg <egil@xxxxxxxxxxxx> on October 7, 2002 - 
  + *  Provide documentation for symbol (i.e. component)
  + */
  +DEFINE_I_CALLBACK(hierarchy_documentation)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  char *attrib_doc = NULL;
  +  char *attrib_device = NULL;
  +  char *attrib_value = NULL;
  +  OBJECT *object = NULL;
  +
  +  exit_if_null(w_current);
  +
  +  object = o_select_return_first_object(w_current);
  +  if (object != NULL) {
  +    /* only allow going into symbols */
  +    if (object->type == OBJ_COMPLEX) {
  +
  +      /* look for "documentation" first outside, then inside symbol */
  +      attrib_doc = o_attrib_search_name_single_count(object, "documentation", 0);
  +      if (!attrib_doc) {
  +	attrib_doc = o_attrib_search_name(object->complex->prim_objs,
  +								"documentation", 0);
  +      }
  +      /* look for "device" */
  +      attrib_device = o_attrib_search_name_single_count(object, "device", 0);
  +      if (!attrib_device) {
  +	attrib_device = o_attrib_search_name(object->complex->prim_objs,
  +								"device", 0);
  +      }
  +      /* look for "value" */
  +      attrib_value = o_attrib_search_name_single_count(object, "value", 0);
  +      if (!attrib_value) {
  +	attrib_value = o_attrib_search_name(object->complex->prim_objs,
  +								"value", 0);
  +      }
  +      initiate_gschemdoc(attrib_doc,
  +			attrib_device,
  +			attrib_value,
  +			object->complex_basename,
  +			object->complex_clib);
  +
  +      if (attrib_doc) free(attrib_doc);
  +      if (attrib_device) free(attrib_device);
  +      if (attrib_value) free(attrib_value);
  +    }
  +  }
  +}
  +
  +/*! \section attributes-menu Attributes Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(attributes_attach)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *first_object;
  +  SELECTION *s_current;
  +
  +  exit_if_null(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action) {
  +    return;
  +  }
  +
  +  /* do we want to update the shortcut outside of the ifs? */
  +  /* probably, if this fails the user may want to try again */
  +  i_update_middle_button(w_current, i_callback_attributes_attach,
  +                         _("Attach"));
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +  if (!s_current) {
  +    return;
  +  }
  +
  +  first_object = s_current->selected_object; 
  +  if (!first_object) {
  +    return;	
  +  }
  +
  +  /* skip over first object */
  +  s_current = s_current->next;
  +  while (s_current != NULL) {
  +    if (s_current->selected_object) {
  +      o_attrib_attach(w_current,
  +                      w_current->page_current->object_head,
  +                      s_current->selected_object,
  +                      first_object);
  +      w_current->page_current->CHANGED=1;
  +    }
  +    s_current = s_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(attributes_detach)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  SELECTION *s_current;
  +  OBJECT *o_current;
  +
  +  exit_if_null(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action) {
  +    return;
  +  }
  +
  +  /* same note as above on i_update_middle_button */
  +  i_update_middle_button(w_current, i_callback_attributes_detach,
  +                         _("Detach"));
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +  while (s_current != NULL) {
  +    o_current = s_current->selected_object;
  +    if (o_current) {
  +      if (o_current->attribs) {
  +        o_attrib_free_all(w_current, 
  +                          o_current->attribs);
  +        o_current->attribs = NULL;
  +        w_current->page_current->CHANGED=1;
  +      }
  +    }
  +    s_current = s_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(attributes_show_name)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *object;
  +
  +  exit_if_null(w_current);
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action) {
  +    return;
  +  }
  +
  +  i_update_middle_button(w_current, i_callback_attributes_show_name,
  +                         _("ShowN"));
  +
  +  if (object != NULL) {
  +    o_attrib_toggle_show_name_value(w_current, 
  +                                    w_current->page_current->
  +                                    selection2_head->next,
  +                                    SHOW_NAME);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(attributes_show_value)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *object;
  +
  +  exit_if_null(w_current);
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action) {
  +    return;
  +  }
  +
  +  i_update_middle_button(w_current, i_callback_attributes_show_value,
  +                         _("ShowV"));
  +
  +  if (object != NULL) {
  +    o_attrib_toggle_show_name_value(w_current, 
  +                                    w_current->page_current->
  +                                    selection2_head->next,
  +                                    SHOW_VALUE);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(attributes_show_both)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *object;
  +
  +  exit_if_null(w_current);
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action) {
  +    return;
  +  }
  +
  +  i_update_middle_button(w_current, i_callback_attributes_show_both,
  +                         _("ShowB"));
  +
  +  if (object != NULL) {
  +    o_attrib_toggle_show_name_value(w_current, 
  +                                    w_current->page_current->
  +                                    selection2_head->next,
  +                                    SHOW_NAME_VALUE);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(attributes_visibility_toggle)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *object;
  +
  +  exit_if_null(w_current);
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  /* This is a new addition 3/15 to prevent this from executing
  +   * inside an action */
  +  if (w_current->inside_action) {
  +    return;
  +  }
  +
  +  i_update_middle_button(w_current,
  +                         i_callback_attributes_visibility_toggle,
  +                         _("VisToggle"));
  +
  +  if (object != NULL) {
  +    o_attrib_toggle_visibility(w_current, 
  +                               w_current->page_current->
  +                               selection2_head->next);
  +  }
  +}
  +
  +/*! \section script-menu Script Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  not currently implemented
  + */
  +DEFINE_I_CALLBACK(script_console)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  printf(_("Sorry but this is a non-functioning menu option\n"));
  +}
  +
  +/*! \section layers-menu Layers Menu Callback Functions */
  +
  +/*! \section options-menu Options Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat last command doesn't make sense on options either??? (does it?)
  + */
  +DEFINE_I_CALLBACK(options_text_size)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  text_size_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(options_snap_size)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  snap_size_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  repeat last command doesn't make sense on options either??? (does
  + *  it?)
  + */
  +DEFINE_I_CALLBACK(options_afeedback)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->actionfeedback_mode == BOUNDINGBOX) {
  +    w_current->actionfeedback_mode = OUTLINE;
  +    s_log_message(_("Action feedback mode set to OUTLINE\n"));
  +  } else {
  +    w_current->actionfeedback_mode = BOUNDINGBOX;
  +    s_log_message(_("Action feedback mode set to BOUNDINGBOX\n"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(options_grid)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if (w_current->grid) {
  +    w_current->grid = 0;
  +    s_log_message(_("Grid OFF\n"));
  +  } else {
  +    w_current->grid = 1;
  +    s_log_message(_("Grid ON\n"));
  +  }
  +
  +  o_redraw_all(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(options_snap)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  if (w_current->snap) {
  +    w_current->snap = 0;
  +    s_log_message(_("Snap OFF (CAUTION!)\n"));
  +  } else {
  +    w_current->snap = 1;
  +    s_log_message(_("Snap ON\n"));
  +  }
  +  i_show_state(w_current, NULL); /* update status on screen */
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  Rubber band is cool !
  + *  Added on/off option from the pull down menu
  + *  Chris Ellec - January 2001
  + */
  +DEFINE_I_CALLBACK(options_rubberband)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  if (w_current->netconn_rubberband) {
  +    w_current->netconn_rubberband = 0;
  +    s_log_message(_("Rubber band OFF \n"));
  +  } else {
  +    w_current->netconn_rubberband = 1;
  +    s_log_message(_("Rubber band ON\n"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(options_show_log_window)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  x_log_open ();
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is Ales' catch all misc callback
  + */
  +DEFINE_I_CALLBACK(misc)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  s_tile_print(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is Ales' second catch all misc callback
  + */
  +DEFINE_I_CALLBACK(misc2)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  OBJECT *first = o_select_return_first_object(w_current);
  +
  +  if (first) {
  +    /*o_cue_draw_single(w_current, first);*/
  +    o_cue_undraw(w_current, first);
  +    s_conn_print(first->conn_list);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is Ales' third catch all misc callback
  + */
  +DEFINE_I_CALLBACK(misc3)
  +{
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  HACK: be sure that you don't use the widget parameter in this one,
  + *  since it is being called with a null, I suppose we should call it
  + *  with the right param.
  + */
  +DEFINE_I_CALLBACK(cancel)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +
  +  if ( (w_current->inside_action) && 
  +       (w_current->rotated_inside != 0)) {
  +    o_undo_callback(w_current, UNDO_ACTION);	 
  +    w_current->rotated_inside = 0;
  +  }
  +
  +  /* leave this on for now... but it might have to change */
  +  /* this is problematic since we don't know what the right mode */
  +  /* (when you cancel inside an action) should be */
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +
  +  /* clear the key guile command-sequence */
  +  scm_c_eval_string ("(set! current-command-sequence '())");
  +
  +  /* see above comment hack */
  +#if 0
  +  set_cursor_normal();
  +#endif
  +
  +  if (w_current->inside_action) { 
  +     o_redraw_all(w_current); 
  +  }
  +
  +  /* it is possible to cancel in the middle of a complex place
  +   * so lets be sure to clean up the complex_place_head
  +   * structure and also clean up the attrib_place_head.
  +   * remember these don't remove the head structure */
  +  o_list_delete_rest(w_current,
  +                     w_current->page_current->complex_place_head);
  +  o_list_delete_rest(w_current,
  +                     w_current->page_current->attrib_place_head);
  +
  +  /* also free internal current_attribute */
  +  o_attrib_free_current(w_current);
  +
  +  w_current->inside_action=0;
  +}
  +
  +/*! \section help-menu Help Menu Callback Functions */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(help_about)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  about_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(help_manual)
  +{
  +  initiate_gschemdoc("-m", NULL, NULL, NULL, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(help_hotkeys)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  x_dialog_hotkeys(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(options_show_coord_window)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  coord_dialog (w_current, mouse_x, mouse_y);
  +}
  +
  +#if 0 /* experimental */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +DEFINE_I_CALLBACK(preview)
  +{
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +
  +  exit_if_null(w_current);
  +  setup_preview(w_current);
  +}
  +#endif
  +
  +/* these is a special wrapper function which cannot use the above */
  +/* DEFINE_I_CALLBACK macro */
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  When invoked (via signal delete_event), closes the current window
  + *  if this is the last window, quit gschem
  + *  used when you click the close button on the window which sends a DELETE
  + *  signal to the app
  + */
  +void i_callback_close_wm ( GtkWidget *widget, GdkEvent *event, 
  +	                   gpointer data ) 
  +{
  +
  +  TOPLEVEL *w_current = (TOPLEVEL *) data;
  +  exit_if_null(w_current);
  +
  +  x_window_close(w_current);
  +}
  
  
  
  1.31      +145 -129  eda/geda/gaf/gschem/src/i_vars.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: i_vars.c
  ===================================================================
  RCS file: i_vars.c
  diff -N i_vars.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ i_vars.c	14 Jul 2006 02:23:54 -0000	1.31
  @@ -0,0 +1,248 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/x_states.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +int   default_graphic_color = GRAPHIC_COLOR;
  +int   default_text_color = TEXT_COLOR;
  +int   default_text_size = 10;
  +int   default_text_caps = LOWER;
  +int   default_attribute_color = ATTRIBUTE_COLOR;
  +int   default_detachattr_color = DETACHED_ATTRIBUTE_COLOR;
  +int   default_net_color = NET_COLOR;
  +int   default_bus_color = BUS_COLOR;
  +int   default_net_endpoint_color = NET_ENDPOINT_COLOR;
  +int   default_override_net_color = -1;
  +int   default_override_bus_color = -1;
  +int   default_override_pin_color = -1;
  +int   default_net_endpoint_mode = FILLEDBOX;
  +int   default_net_midpoint_mode = FILLED;
  +int   default_pin_color = PIN_COLOR;
  +int   default_pin_style = THICK;
  +int   default_net_style = THICK;
  +int   default_bus_style = THICK;
  +int   default_grid_color = GRID_COLOR;
  +int   default_background_color = BACKGROUND_COLOR;
  +int   default_select_color = SELECT_COLOR;
  +int   default_bb_color = BOUNDINGBOX_COLOR;
  +int   default_lock_color = LOCK_COLOR;
  +int   default_zoom_box_color = ZOOM_BOX_COLOR;
  +int   default_logic_bubble_color = LOGIC_BUBBLE_COLOR;
  +int   default_actionfeedback_mode = OUTLINE;
  +int   default_zoom_with_pan = TRUE;
  +int   default_object_clipping = TRUE;
  +int   default_do_logging = TRUE;
  +int   default_logging_dest = LOG_WINDOW;
  +int   default_embed_complex = FALSE;
  +int   default_include_complex = FALSE;
  +int   default_text_output = VECTOR_FONTS;
  +int   default_snap_size = 100;
  +int   default_stroke_color = STROKE_COLOR;
  +
  +int   default_paper_width = 11000; /* letter size */
  +int   default_paper_height = 85000;
  +int   default_scrollbars_flag = TRUE;
  +int   default_print_orientation = LANDSCAPE;
  +int   default_image_color = FALSE;
  +int   default_image_width = 800;
  +int   default_image_height = 600;
  +int   default_print_color = FALSE;
  +int   default_print_color_background = OUTPUT_BACKGROUND_COLOR;
  +int   default_print_output_type = EXTENTS;
  +int   default_print_output_capstyle = SQUARE_CAP;
  +int   default_log_window = MAP_ON_STARTUP;
  +int   default_log_window_type = DECORATED;
  +int   default_third_button = POPUP_ENABLED;
  +#ifdef HAS_LIBSTROKE
  +int   default_middle_button = STROKE;
  +#else
  +int   default_middle_button = REPEAT;
  +#endif
  +int   default_net_consolidate = TRUE;
  +int   default_file_preview = FALSE;
  +int   default_enforce_hierarchy = TRUE;
  +int   default_text_origin_marker = TRUE;
  +int   default_fast_mousepan = TRUE;
  +int   default_raise_dialog_boxes = FALSE;
  +int   default_attribute_promotion = TRUE;
  +int   default_promote_invisible = FALSE;
  +int   default_keep_invisible = FALSE;
  +int   default_continue_component_place = TRUE;
  +int   default_undo_levels = 20;
  +int   default_undo_control = TRUE;
  +int   default_undo_type = UNDO_DISK;
  +int   default_draw_grips = TRUE;
  +int   default_netconn_rubberband = FALSE;
  +int   default_sort_component_library = FALSE;
  +int   default_warp_cursor = TRUE;
  +int   default_toolbars = TRUE;
  +int   default_handleboxes = TRUE;
  +int   default_setpagedevice_orientation = FALSE;
  +int   default_setpagedevice_pagesize = FALSE;
  +int   default_bus_ripper_size = 200;
  +int   default_bus_ripper_type = COMP_BUS_RIPPER;
  +int   default_bus_ripper_rotation = NON_SYMMETRIC;
  +int   default_force_boundingbox = FALSE;
  +int   default_grid_dot_size = 1;
  +int   default_grid_mode = GRID_VARIABLE_MODE;
  +int   default_grid_fixed_threshold = 10;
  +int   default_print_vector_threshold = 3;
  +int   default_add_attribute_offset = 50;
  +
  +int   default_auto_save_interval = 120;
  +
  +int   default_drag_can_move = TRUE;
  +
  +int   default_width = 800;  /* these variables are used in x_window.c */
  +int   default_height = 600;
  +
  +/* default zoom_factor at which text is displayed completely */
  +int   default_text_display_zoomfactor = 30;
  +
  +int default_text_feedback = ONLY_WHEN_READABLE;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void i_vars_set(TOPLEVEL *w_current)
  +{
  +  i_vars_libgeda_set(w_current);
  +
  +  /* this will be false if logging cannot be enabled */
  +  if (do_logging != FALSE) {
  +    do_logging = default_do_logging;
  +  }
  +
  +  logging_dest = default_logging_dest;
  +
  +  w_current->graphic_color = default_graphic_color;
  +  w_current->text_color    = default_text_color;
  +  w_current->text_size     = default_text_size;
  +  w_current->text_caps     = default_text_caps;
  +
  +  w_current->attribute_color    = default_attribute_color;
  +  w_current->detachedattr_color = default_detachattr_color;
  +  w_current->logic_bubble_color = default_logic_bubble_color;
  +
  +  w_current->grid_color       = default_grid_color;
  +  w_current->background_color = default_background_color;
  +  w_current->select_color     = default_select_color;
  +  w_current->stroke_color     = default_stroke_color;
  +
  +  w_current->bb_color = default_bb_color;
  +  w_current->zoom_box_color = default_zoom_box_color;
  +  w_current->lock_color = default_lock_color;
  +
  +  w_current->net_color          = default_net_color;
  +  w_current->net_style          = default_net_style;
  +  w_current->net_endpoint_color = default_net_endpoint_color;
  +  w_current->net_endpoint_mode  = default_net_endpoint_mode;
  +  w_current->net_midpoint_mode  = default_net_midpoint_mode;
  +  w_current->override_net_color = default_override_net_color;
  +
  +  w_current->bus_color          = default_bus_color;
  +  w_current->bus_style          = default_bus_style;
  +  w_current->override_bus_color = default_override_bus_color;
  +
  +  w_current->pin_color          = default_pin_color;
  +  w_current->pin_style          = default_pin_style;
  +  w_current->override_pin_color = default_override_pin_color;
  +
  +  w_current->zoom_with_pan           = default_zoom_with_pan;
  +  w_current->actionfeedback_mode     = default_actionfeedback_mode;
  +  w_current->text_display_zoomfactor = default_text_display_zoomfactor;
  +  w_current->text_feedback           = default_text_feedback;
  +  w_current->scrollbars_flag         = default_scrollbars_flag;
  +
  +  w_current->object_clipping = default_object_clipping;
  +  w_current->embed_complex   = default_embed_complex;
  +  w_current->include_complex = default_include_complex;
  +  w_current->text_output     = default_text_output;
  +  w_current->snap_size       = default_snap_size;
  +  w_current->log_window      = default_log_window;
  +  w_current->log_window_type = default_log_window_type;
  +
  +  w_current->print_output_type      = default_print_output_type;
  +  w_current->print_output_capstyle  = default_print_output_capstyle;
  +  w_current->print_orientation      = default_print_orientation;
  +  w_current->print_color            = default_print_color;
  +  w_current->print_color_background = default_print_color_background;
  +  w_current->setpagedevice_orientation = default_setpagedevice_orientation;
  +  w_current->setpagedevice_pagesize = default_setpagedevice_pagesize;
  +
  +  w_current->image_color        = default_image_color;
  +  w_current->image_width        = default_image_width;
  +  w_current->image_height       = default_image_height;
  +  w_current->third_button       = default_third_button;
  +  w_current->middle_button      = default_middle_button;
  +  w_current->net_consolidate    = default_net_consolidate;
  +  w_current->file_preview       = default_file_preview;
  +  w_current->enforce_hierarchy  = default_enforce_hierarchy;
  +  w_current->text_origin_marker = default_text_origin_marker;
  +  w_current->fast_mousepan      = default_fast_mousepan;
  +  w_current->raise_dialog_boxes = default_raise_dialog_boxes;
  +  w_current->attribute_promotion = default_attribute_promotion;
  +  w_current->promote_invisible = default_promote_invisible;
  +  w_current->keep_invisible = default_keep_invisible;
  +  w_current->continue_component_place = default_continue_component_place;
  +  w_current->undo_levels = default_undo_levels;
  +  w_current->undo_control = default_undo_control;
  +  w_current->undo_type = default_undo_type;
  +
  +  w_current->draw_grips = default_draw_grips;
  +  w_current->netconn_rubberband = default_netconn_rubberband;
  +  w_current->sort_component_library = default_sort_component_library;
  +  w_current->warp_cursor = default_warp_cursor;
  +  w_current->toolbars = default_toolbars;
  +  w_current->handleboxes = default_handleboxes;
  +
  +  w_current->paper_width  = default_paper_width;
  +  w_current->paper_height = default_paper_height;
  +
  +  w_current->bus_ripper_size  = default_bus_ripper_size;
  +  w_current->bus_ripper_type  = default_bus_ripper_type;
  +  w_current->bus_ripper_rotation  = default_bus_ripper_rotation;
  +
  +  w_current->force_boundingbox  = default_force_boundingbox;
  +  w_current->grid_dot_size  = default_grid_dot_size;
  +  w_current->grid_mode  = default_grid_mode;
  +  w_current->grid_fixed_threshold  = default_grid_fixed_threshold;
  +  w_current->print_vector_threshold  = default_print_vector_threshold;
  +  w_current->add_attribute_offset  = default_add_attribute_offset;
  +
  +  w_current->drag_can_move = default_drag_can_move;
  +
  +  w_current->auto_save_interval = default_auto_save_interval;
  +  if (w_current->auto_save_interval != 0) {
  +    w_current->auto_save_timeout = g_timeout_add(w_current->auto_save_interval*1000,
  +						 (GSourceFunc) s_page_autosave,
  +						 w_current);
  +  }
  +}
  
  
  
  1.23      +1213 -626 eda/geda/gaf/gschem/src/o_arc.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_arc.c
  ===================================================================
  RCS file: o_arc.c
  diff -N o_arc.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_arc.c	14 Jul 2006 02:23:54 -0000	1.23
  @@ -0,0 +1,1372 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* Kazu on July 8, 1999 - added these macros to simplify the code */
  +/*! \brief */
  +#define GET_BOX_WIDTH(w)			\
  +	abs((w)->last_x - (w)->start_x)
  +/*! \brief */
  +#define GET_BOX_HEIGHT(w)			\
  +	abs((w)->last_y - (w)->start_y)
  +/*! \brief
  + *  \note pb20011011 - added this macro to compute distance
  + */
  +#define GET_DISTANCE(w)             \
  +    sqrt(pow((w)->last_x-(w)->start_x,2)+pow((w)->last_y-(w)->start_y,2))
  +
  +/*! \brief Draw an arc on the screen.
  + *  \par Function Description
  + *  This function is used to draw an arc on screen. The arc is described
  + *  in the object which is referred by <B>o_current</B>. The arc is displayed
  + *  according to the current state, described in the TOPLEVEL object
  + *  pointed by <B>w_current</B>.
  + *
  + *  It first checkes if the object is valid or not. If not it returns
  + *  and do not output anything. That should never happen though.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  The arc OBJECT to draw.
  + */
  +void o_arc_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int wleft, wright, wtop, wbottom;
  +  int x, y, radius, start_angle, end_angle;
  +  int arc_width;
  +  GdkCapStyle arc_end;
  +  GdkColor *color;
  +  void (*draw_func)() = NULL;
  +  int length, space;
  +
  +  if (o_current->arc == NULL) {
  +    return;
  +  }
  +
  +  /*
  +   * The function now recalculates the OBJECT as an arc. It involves
  +   * calculating every single dimensions according to the zoom factor
  +   * and position, dots.
  +   * It also recalculates the bounding box of the object and check
  +   * whether this object is visible or not. If not there is no reason
  +   * to draw it !
  +   */
  +  o_arc_recalc(w_current, o_current);
  +
  +  world_get_arc_bounds(w_current, o_current,
  +                       &wleft, &wtop, &wright, &wbottom);
  +
  +  if (!visible(w_current, wleft, wtop, wright, wbottom)) {
  +    return;
  +  }
  +
  +  /*
  +   * As an arc is definetely not a closed shape there is no need to
  +   * define and call any filling function. Another way to say that is
  +   * that an arc can not be filled. It simply draws the arc according
  +   * to the type line.
  +   *
  +   * The values describing the line type are extracted from the
  +   * <B>o_current</B> pointed structure. These are the width of the line,
  +   * the field called length and the field called space and the desired
  +   * end type for the arc.
  +   *
  +   * Depending on the type of line desired the appropriate function is
  +   * called. Values of space and length are adapted to the type of line.
  +   * The possible functions are the following : #o_arc_draw_solid(),
  +   * #o_arc_draw_dotted(), #o_arc_draw_dashed() and #o_arc_draw_phantom().
  +   *
  +   * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it
  +   * leads to an endless loop in function called after. If such a case is
  +   * encountered the arc is drawn as a solid arc independently of its
  +   * initial type.
  +   */
  +  x      = o_current->arc->screen_x;
  +  y      = o_current->arc->screen_y;
  +  radius = o_current->arc->screen_width / 2;
  +  start_angle = o_current->arc->start_angle;
  +  end_angle   = o_current->arc->end_angle;
  +
  +#if DEBUG 
  +  printf("drawing arc x: %d y: %d sa: %d ea: %d width: %d height: %d\n",
  +         o_current->arc->screen_x,
  +         o_current->arc->screen_y, 
  +         o_current->arc->start_angle, 
  +         o_current->arc->end_angle,
  +         o_current->arc->screen_width, 
  +         o_current->arc->screen_height);
  +#endif
  +
  +  if (w_current->override_color != -1 )
  +    color = x_get_color(w_current->override_color);
  +  else
  +    color = x_get_color(o_current->color);
  +
  +  if(o_current->screen_line_width > 0) {
  +    arc_width = o_current->screen_line_width;
  +  } else {
  +    arc_width = 1;
  +  }
  +	
  +  switch(o_current->line_end) {
  +  case END_NONE:   arc_end = GDK_CAP_BUTT;       break;
  +  case END_SQUARE: arc_end = GDK_CAP_PROJECTING; break;
  +  case END_ROUND:  arc_end = GDK_CAP_ROUND;      break;
  +  default: fprintf(stderr, _("Unknown end for arc (%d)\n"), o_current->line_end); 
  +    arc_end = GDK_CAP_BUTT; 
  +    break;
  +  }
  +
  +  length = o_current->screen_line_length;
  +  space = o_current->screen_line_space;
  +	
  +  switch(o_current->line_type) {
  +  case TYPE_SOLID:
  +    length = -1;
  +    space = -1;
  +    draw_func = (void *) o_arc_draw_solid;
  +    break;
  +			
  +  case TYPE_DOTTED:
  +    length = -1; /* AVH changed o_arc_draw_dotted to use */
  +    /* space parameter only */
  +    draw_func = (void *) o_arc_draw_dotted;
  +    break;
  +			
  +  case TYPE_DASHED:
  +    draw_func = (void *) o_arc_draw_dashed;
  +    break;
  +			
  +  case TYPE_CENTER:
  +    draw_func = (void *) o_arc_draw_center;
  +    break;
  +			
  +  case TYPE_PHANTOM:
  +    draw_func = (void *) o_arc_draw_phantom;
  +    break;
  +			
  +  case TYPE_ERASE:
  +    break;
  +			
  +  default:
  +    length = -1;
  +    space = -1;
  +    arc_width = 0; /* just to be careful */
  +    draw_func = (void *) o_arc_draw_solid;
  +    fprintf(stderr, _("Unknown type for arc !\n"));
  +    break;
  +  }
  +
  +  if((length == 0) || (space == 0))
  +    draw_func = (void *) o_arc_draw_solid;
  +
  +  (*draw_func)(w_current->window, w_current->gc, color,
  +               arc_end,
  +               x, y, radius, start_angle, end_angle,
  +               arc_width, length, space);
  +  (*draw_func)(w_current->backingstore, w_current->gc, color,
  +               arc_end,
  +               x, y, radius, start_angle, end_angle,
  +               arc_width, length, space);
  +
  +  
  +  if (o_current->draw_grips && w_current->draw_grips == TRUE) {	
  +
  +    /* pb29911903 - modified to use the new o_arc_[draw|erase]_grips() */
  +    if(!o_current->selected) {
  +      /* object is no more selected, erase the grips */
  +      o_current->draw_grips = FALSE;
  +      o_arc_erase_grips(w_current, o_current);
  +    } else {
  +      /* object is selected, draw the grips on the arc */
  +      o_arc_draw_grips(w_current, o_current);
  +    }
  +
  +  }
  +
  +
  +#if DEBUG
  +  printf("drawing arc\n");
  +#endif
  +}
  +
  +/*! \brief Draw an arc with a solid line type.
  + *  \par Function Description
  + *  This function draw an arc with a solid line type. The arc is defined
  + *  by two angle (start and end of arc) and the definition of a box by
  + *  which the arc is restricted by. The parameters <B>length</B> and
  + *  <B>space</B> are unused here.
  + *
  + *  The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and <B>arc_width</B>,
  + *  <B>space</B>, <B>length</B> is pixel.
  + *
  + *  <B>angle1</B> and <B>angle2</B> are in degrees.
  + *
  + *  The lines attributes are settled. Then it simply make a call to
  + *  the gdk original function.
  + *
  + *  \param [in] w          GdkWindow to draw in.
  + *  \param [in] gc         GdkGC graphics context to draw on.
  + *  \param [in] color      Arc line color.
  + *  \param [in] cap        Arc line end cap type (unused).
  + *  \param [in] x          Arc center x.
  + *  \param [in] y          Arc center y.
  + *  \param [in] radius     Arc radius.
  + *  \param [in] angle1     Start angle in degrees.
  + *  \param [in] angle2     End angle in degrees.
  + *  \param [in] arc_width  Width of arc line.
  + *  \param [in] length     (unused)
  + *  \param [in] space      (unused)
  + */
  +void o_arc_draw_solid(GdkWindow *w, GdkGC *gc,
  +		      GdkColor *color, GdkCapStyle cap,
  +		      gint x, gint y, gint radius,
  +		      gint angle1, gint angle2,
  +		      gint arc_width, gint length, gint space)
  +{
  +  gdk_gc_set_foreground(gc, color);
  +  /* Set the width, end type and join style of the line */
  +  gdk_gc_set_line_attributes(gc, arc_width, 
  +                             GDK_LINE_SOLID, cap, GDK_JOIN_MITER);
  +
  +  /* Draw the arc */
  +  gdk_draw_arc(w, gc, FALSE,
  +               x - radius, y - radius, 2 * radius, 2 * radius,
  +               angle1 * 64, angle2 * 64);
  +
  +}
  +
  +/*! \brief Draw an arch with a dotted line type.
  + *  \par Function Description
  + *  This functions draws an arc with a dotted line type. The parameter
  + *  <B>space</B> represents the distance between two of the dots. The
  + *  parameter <B>length</B> is unused. The diameter of the dots is given
  + *  by the width of the line given by <B>arc_width</B>.
  + *
  + *  The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and
  + *  <B>arc_width</B>, <B>space</B>, <B>length</B> is pixel.
  + *
  + *  <B>angle1</B> and <B>angle2</B> are in degrees.
  + *  A negative or null value for length leads to an endless loop.
  + *  length parameter is not used here.
  + *
  + *  \param [in] w          GdkWindow to draw in.
  + *  \param [in] gc         GdkGC graphics context to draw on.
  + *  \param [in] color      Arc line color.
  + *  \param [in] cap        Arc line end cap type (unused).
  + *  \param [in] x          Arc center x.
  + *  \param [in] y          Arc center y.
  + *  \param [in] radius     Arc radius.
  + *  \param [in] angle1     Start angle in degrees.
  + *  \param [in] angle2     End angle in degrees.
  + *  \param [in] arc_width  Width of arc line.
  + *  \param [in] length     (unused).
  + *  \param [in] space      Spacing between dots in pixels.
  + */
  +void o_arc_draw_dotted(GdkWindow *w, GdkGC *gc,
  +		       GdkColor *color, GdkCapStyle cap,
  +		       gint x, gint y, gint radius,
  +		       gint angle1, gint angle2,
  +		       gint arc_width, gint length, gint space)
  +{
  +  double xa, ya;
  +  int da, d;
  +
  +  gdk_gc_set_foreground(gc, color);
  +
  +  /*
  +   * It calculates the angle that match the length <B>space</B> as <B>da</B>.
  +   * If <B>da</B> is negative or null, the way the function uses it after
  +   * leads to an andless loop. In fact such a case occur when it is not
  +   * possible to distinguish a solid line from a dotted line because of
  +   * zoom factor. The arc is therefore drawn solid.
  +   */
  +  /* PB inverting angle2 if < 0 and changing angle1 accordingly */
  +  /* the loop test assume that da > 0 */
  +  if(angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +  da = (int) ((((double) space) * 180) / (M_PI * ((double) radius)));
  +
  +  /* If da or db too small for arc to be displayed as dotted,
  +     draw a solid arc */
  +  if(da <= 0) {
  +    gdk_draw_arc(w, gc, FALSE,
  +                 x + radius, y + radius, 2 * radius, 2 * radius,
  +                 angle1 * 64, angle2 * 64);
  +    return;
  +  }
  +  /*
  +   * It starts from <B>angle1</B> and increments <B>angle1</B> by <B>da</B> as
  +   * a loop until all the arc has been browsed. For each angle value a
  +   * dot is drawing after calculating back its coordinates from the angle.
  +   */
  +  d = angle1;
  +  while(d < (angle2 + angle1)) {
  +    xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
  +    ya = ((double) y) - ((double) radius) * sin(d * M_PI / 180);
  +
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a
  +     * different manner : if the real worl width is equal to 0, then the
  +     * width is translated to 1 in screen coordinates to be visible.
  +     * Drawing a circle with a 1-diameter and the GDK function
  +     * #gdk_draw_arc() is not possible. So we needs to test
  +     * whether the width is 1 or not.
  +     */
  +    if(arc_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - arc_width/2, 
  +		   ((int) ya) - arc_width/2,
  +		   arc_width, arc_width, 0, FULL_CIRCLE);
  +    }
  +
  +    d = d + da;
  +  }
  +
  +}
  +
  +/*! \brief Draw an arc with a dashed line type.
  + *  This functions draws an arc with a dashed line type. The parameter
  + *  <B>space</B> represents the distance between two of the dash. The
  + *  parameter <B>length</B> represents the length of the dash.
  + *
  + *  The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and
  + *  <B>arc_width</B>, <B>space</B>, <B>length</B> is pixel.
  + *
  + *  <B>angle1</B> and <B>angle2</B> are in degrees.
  + *
  + *  A negative or null value for <B>length</B> and <B>space</B> leads to an
  + *  endless loop.
  + *
  + *  \param [in] w          GdkWindow to draw in.
  + *  \param [in] gc         GdkGC graphics context to draw on.
  + *  \param [in] color      Arc line color.
  + *  \param [in] cap        Arc line end cap type (unused).
  + *  \param [in] x          Arc center x.
  + *  \param [in] y          Arc center y.
  + *  \param [in] radius     Arc radius.
  + *  \param [in] angle1     Start angle in degrees.
  + *  \param [in] angle2     End angle in degrees.
  + *  \param [in] arc_width  Width of arc line.
  + *  \param [in] length     Length of dash in pixels..
  + *  \param [in] space      Spacing between dashes in pixels.
  + */
  +void o_arc_draw_dashed(GdkWindow *w, GdkGC *gc,
  +		       GdkColor *color, GdkCapStyle cap,
  +		       gint x, gint y,
  +		       gint radius,
  +		       gint angle1, gint angle2,
  +		       gint arc_width, gint length, gint space)
  +{
  +  int da, db, a1, a2, d;
  +
  +  gdk_gc_set_foreground(gc, color);	
  +  gdk_gc_set_line_attributes(gc, arc_width, GDK_LINE_SOLID, cap, 
  +                             GDK_JOIN_MITER);
  +
  +  /*
  +   * The function first determines the radius and the center of the arc.
  +   *
  +   * The function determines the angular increments that match the
  +   * <B>length</B> and <B>space</B> parameter. These are <B>db</B> and <B>da</B>.
  +   * Whenever one or both of these variables are null or negative, the
  +   * line is drawn solid. It means that it is not possible to distinguish
  +   * a dashed line from a solid line because of current value of zoom.
  +   */
  +
  +  /* PB inverting angle2 if < 0 and changing angle1 accordingly */
  +  /* the loop test assume that da > 0 */
  +  if(angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +  da = (int) ((length * 180) / (M_PI * ((double) radius)));
  +  db = (int) ((space  * 180) / (M_PI * ((double) radius)));
  +
  +  /* If da or db too small for arc to be displayed as dotted,
  +     draw a solid arc */
  +  if((da <= 0) || (db <= 0)) {
  +    gdk_draw_arc(w, gc, FALSE,
  +                 x - radius, y - radius, 2 * radius, 2 * radius,
  +                 angle1 * 64, angle2 * 64);
  +    return;
  +  }
  +
  +  /*
  +   * It starts from <B>angle1</B> and increments <B>angle1</B> by <B>da</B> as a
  +   * loop until the whole arc has been browsed. At each position a dash
  +   * of length <B>length</B> - represented by the <B>da</B> increment - is drawn.
  +   *
  +   * It draws as many dashes of length <B>length</B> as possible.
  +   */
  +
  +  d = angle1;
  +  while((d + da + db) < (angle1 + angle2)) {
  +    a1 = d;
  +    d = d + da;
  +    gdk_draw_arc(w, gc, FALSE,
  +                 x - radius, y - radius, 2 * radius, 2 * radius,
  +                 a1 * 64, da * 64);
  +
  +    d = d + db;
  +		
  +  }
  +
  +  /*
  +   * When the above condition is no more satisfied, the it is possible
  +   * to draw a dash of length <B>length</B>. However it may be possible to
  +   * draw a shorter dash.
  +   */
  +
  +  if((d + da) < (angle1 + angle2)) {
  +    a1 = d;
  +    a2 = da;
  +  } else {
  +    a1 = d;
  +    a2 = (angle1 + angle2) - d;
  +  }
  +  gdk_draw_arc(w, gc, FALSE,
  +               x - radius, y - radius, 2 * radius, 2 * radius,
  +               a1 * 64, a2 * 64);
  +	
  +}
  +
  +
  +/*! \brief Draw arc with a centered line type.
  + *  \par Function Description
  + *  This functions draws an arc with a centered line type. The parameter
  + *  <B>space</B> represents the distance between a dot and the dash. The
  + *  parameter <B>length</B> represents the length of a dash.
  + *
  + *  The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and
  + *  <B>arc_width</B>, <B>space</B>, <B>length</B> is pixel.
  + *
  + *  <B>angle1</B> and <B>angle2</B> are in units of degrees.
  + *
  + *  A negative or null value for <B>length</B> and <B>space</B> leads to an
  + *  endless loop.
  + *
  + *  \param [in] w          GdkWindow to draw in.
  + *  \param [in] gc         GdkGC graphics context to draw on.
  + *  \param [in] color      Arc line color.
  + *  \param [in] cap        Arc line end cap type (unused).
  + *  \param [in] x          Arc center x.
  + *  \param [in] y          Arc center y.
  + *  \param [in] radius     Arc radius.
  + *  \param [in] angle1     Start angle in degrees.
  + *  \param [in] angle2     End angle in degrees.
  + *  \param [in] arc_width  Width of arc line.
  + *  \param [in] length     Length of dash in pixels..
  + *  \param [in] space      Spacing between dashes in pixels.
  + */
  +void o_arc_draw_center(GdkWindow *w, GdkGC *gc,
  +		       GdkColor *color, GdkCapStyle cap,
  +		       gint x, gint y,
  +		       gint radius,
  +		       gint angle1, gint angle2,
  +		       gint arc_width, gint length, gint space)
  +{
  +  double xa, ya; /* coordinate of center */
  +  int da, db, a1, a2, d;
  +
  +  gdk_gc_set_foreground(gc, color);	
  +  gdk_gc_set_line_attributes(gc, arc_width, 
  +                             GDK_LINE_SOLID, cap, GDK_JOIN_MITER);
  +
  +  /*
  +   * The function determines the angular increments that match the
  +   * <B>length</B> and <B>space</B> parameter. These are <B>db</B> and <B>da</B>.
  +   * Whenever one or both of these variables are null or negative, the
  +   * line is drawn solid. It means that it is not possible to distinguish
  +   * a dashed line from a solid line because of current value of zoom.
  +   */
  +
  +  /* PB inverting angle2 if < 0 and changing angle1 accordingly */
  +  /* the loop test assume that da > 0 */
  +  if(angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +  da = (int) ((length * 180) / (M_PI * ((double) radius)));
  +  db = (int) ((space  * 180) / (M_PI * ((double) radius)));
  +
  +  /* If da or db too small to be displayed, draw an arc */
  +  if((da <= 0) || (db <= 0)) {
  +    gdk_draw_arc(w, gc, FALSE,
  +                 x - radius, y - radius, 2* radius, 2 * radius,
  +                 angle1 * 64, angle2 * 64);
  +    return;
  +  }
  +
  +  /*
  +   * Starting from <B>angle1</B> and incrementing the position gives the
  +   * coordinates of every dots and dashes on the arc providing that the
  +   * second extremity is not exceeded. 
  +   *
  +   * It draws as many sets of 'dash of length <B>length</B> and dot' as possible.
  +   */
  +
  +  d = angle1;
  +  while((d + da + 2 * db) < (angle1 + angle2)) {
  +    a1 = d;
  +    d = d + da;
  +    gdk_draw_arc(w, gc, FALSE,
  +                 x - radius, y - radius, 2 * radius, 2 * radius,
  +                 a1 * 64, da * 64);
  +
  +    d = d + db;
  +    xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
  +    ya = ((double) y) - ((double) radius) * sin(d * M_PI / 180);
  +
  +
  +    if(arc_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - arc_width/2, 
  +		   ((int) ya) - arc_width/2,
  +		   arc_width, arc_width, 0, FULL_CIRCLE);
  +    }
  +
  +    /*
  +     * If the above condition is no more satisfied, it may still be possible
  +     * to continue drawing a part of the initial pattern. Here two cases are
  +     * possible :
  +     * <DL>
  +     *   <DT>*</DT><DD>it is possible to draw a dash and a dot.
  +     *   <DT>*</DT><DD>it is possible to draw a dash or at least
  +     *                 a part of the original dash.
  +     * </DL>
  +     */
  +
  +    d = d + db;
  +  }
  +
  +
  +  if((d + da) < (angle1 + angle2)) {
  +    a1 = d;
  +    a2 = da;
  +		
  +    d = d + da;
  +  } else {
  +    a1 = d;
  +    a2 = (angle1 + angle2) - d;
  +
  +    d = d + da;
  +  }
  +  gdk_draw_arc(w, gc, FALSE,
  +               x - radius, y - radius, 2 * radius, 2 * radius,
  +               a1 * 64, da * 64);
  +
  +  if((d + db) < (angle1 + angle2)) {
  +    xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
  +    ya = ((double) y) - ((double) radius) * sin(d * M_PI / 180);
  +
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a
  +     * different manner : if the real worl width is equal to 0, then the
  +     * width is translated to 1 in screen coordinates to be visible.
  +     * Drawing a circle with a 1-diameter and the GDK function
  +     * #gdk_draw_arc() is not possible. So we needs to test whether the
  +     * width is 1 or not.
  +     */
  +
  +    if(arc_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - arc_width/2, 
  +		   ((int) ya) - arc_width/2,
  +		   arc_width, arc_width, 0, FULL_CIRCLE);
  +    }
  +
  +
  +  }
  +	
  +}
  +
  +
  +/*! \brief Draw an arc with a phantom line type.
  + *  \par Function Description
  + *  This function draws an arc with a phantom line type. The parameter
  + *  <B>space</B> represents the distance between a dot and a dash. The
  + *  parameter <B>length</B> represents the length of a dash.
  + *
  + *  The unit of <B>x</B>, <B>y</B> and <B>width</B>, <B>height</B> and
  + *  <B>arc_width</B>, <B>space</B>, <B>length</B> is pixel.
  + *
  + *  <B>angle1</B> and <B>angle2</B> are in units of degrees.
  + *
  + *  A negative or null value for <B>length</B> and <B>space</B> leads to an
  + *  endless loop.
  + *
  + *  \param [in] w          GdkWindow to draw in.
  + *  \param [in] gc         GdkGC graphics context to draw on.
  + *  \param [in] color      Arc line color.
  + *  \param [in] cap        Arc line end cap type (unused).
  + *  \param [in] x          Arc center x.
  + *  \param [in] y          Arc center y.
  + *  \param [in] radius     Arc radius.
  + *  \param [in] angle1     Start angle in degrees.
  + *  \param [in] angle2     End angle in degrees.
  + *  \param [in] arc_width  Width of arc line.
  + *  \param [in] length     Length of dash in pixels.
  + *  \param [in] space      Spacing between dashes in pixels.
  + */
  +void o_arc_draw_phantom(GdkWindow *w, GdkGC *gc,
  +			GdkColor *color, GdkCapStyle cap,
  +			gint x, gint y,
  +			gint radius,
  +			gint angle1, gint angle2,
  +			gint arc_width, gint length, gint space)
  +{
  +  double xa, ya;
  +  int da, db, a1, a2, d;
  +
  +  gdk_gc_set_foreground(gc, color);	
  +  gdk_gc_set_line_attributes(gc, arc_width, 
  +                             GDK_LINE_SOLID, cap, GDK_JOIN_MITER);
  +
  +  /* The function determines the angular increments that match the
  +   * <B>length</B> and <B>space</B> parameters. These are <B>db</B> and <B>da</B>.
  +   * Whenever one or both of these variables are null or negative, the
  +   * line is drawn solid. It means that it is not possible to distinguish
  +   * a dashed line from a solid line because of current value of zoom.
  +   */
  +
  +  /* PB inverting angle2 if < 0 and changing angle1 accordingly */
  +  /* the loop test assume that da > 0 */
  +  if(angle2 < 0) {
  +    angle1 = angle1 + angle2;
  +    angle2 = -angle2;
  +  }
  +  da = (int) ((length * 180) / (M_PI * ((double) radius)));
  +  db = (int) ((space  * 180) / (M_PI * ((double) radius)));
  +
  +  /* If da or db too small for arc to be displayed as dotted,
  +     draw a solid arc */
  +  if((da <= 0) || (db <= 0)) {
  +    gdk_draw_arc(w, gc, FALSE,
  +                 x - radius, y - radius, 2 * radius, 2 * radius,
  +                 angle1 * 64, angle2 * 64);
  +    return;
  +  }
  +
  +  /*
  +   * Starting from <B>angle1</B> and incrementing the position gives the
  +   * coordinates of every dots and dashes on the arc providing that the
  +   * second extremity is not exceeded. 
  +   *
  +   * It draws as many sets of 'dash of length <B>length</B> and two dots'
  +   * as possible.
  +   */
  +
  +  d = angle1;
  +  while((d + da + 3 * db) < (angle1 + angle2)) {
  +    a1 = d;
  +    d = d + da;
  +    gdk_draw_arc(w, gc, FALSE,
  +                 x - radius, y - radius, 2 * radius, 2 * radius,
  +                 a1 * 64, da * 64);
  +
  +    d = d + db;
  +    xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
  +    ya = ((double) y) - ((double) radius) * sin(d * M_PI / 180);
  +
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a
  +     * different manner : if the real worl width is equal to 0, then the
  +     * width is translated to 1 in screen coordinates to be visible.
  +     * Drawing a circle with a 1-diameter and the GDK function
  +     * #gdk_draw_arc() is not possible. So we needs to test whether the
  +     * width is 1 or not.
  +     */
  +
  +    if(arc_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - arc_width/2, 
  +		   ((int) ya) - arc_width/2,
  +		   arc_width, arc_width, 0, FULL_CIRCLE);
  +    }
  +
  +
  +    d = d + db;
  +    xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
  +    ya = ((double) y) - ((double) radius) * sin(d * M_PI / 180);
  +
  +    
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a
  +     * different manner : if the real world width is equal to 0, then the
  +     * width is translated to 1 in screen coordinates to be visible. Drawing
  +     * a circle with a 1-diameter and the GDK function #gdk_draw_arc() is
  +     * not possible. So we needs to test whether the width is 1 or not.
  +     */
  +
  +    if(arc_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - arc_width/2, 
  +		   ((int) ya) - arc_width/2,
  +		   arc_width, arc_width, 0, FULL_CIRCLE);
  +    }
  +
  +
  +
  +    d = d + db;
  +  }
  +
  +  /*
  +   * If the above condition is no more satisfied, it may still be possible
  +   * to continue drawing a part of the original pattern. Here three cases
  +   * are possible :
  +   * <DL>
  +   *   <DT>*</DT><DD>it is possible to draw a dash and the two dots.
  +   *   <DT>*</DT><DD>it is possible to draw a dash and one of the two dots.
  +   *   <DT>*</DT><DD>it is possible to draw at least a part of the initial
  +   *                 dash.
  +   */
  +
  +  if((d + da) < (angle1 + angle2)) {
  +    a1 = d;
  +    a2 = da;
  +    d = d + da;
  +  } else {
  +    a1 = d;
  +    a2 = (angle1 + angle2) - d;
  +    d = d + da;
  +  }
  +  gdk_draw_arc(w, gc, FALSE,
  +               x - radius, y - radius, 2 * radius, 2 * radius,
  +               a1 * 64, a2 * 64);
  +
  +  if((d + db) < (angle1 + angle2)) {
  +    d = d + db;
  +
  +    xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
  +    ya = ((double) y) - ((double) radius) * sin(d * M_PI / 180);
  +		
  +    if(arc_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +                   ((int) xa) - arc_width/2, 
  +                   ((int) ya) - arc_width/2,
  +                   arc_width, arc_width, 0, FULL_CIRCLE);
  +    }
  +  }
  +
  +  if((d + db) < (angle1 + angle2)) {
  +    d = d + db;
  +
  +    xa = ((double) x) + ((double) radius) * cos(d * M_PI / 180);
  +    ya = ((double) y) - ((double) radius) * sin(d * M_PI / 180);
  +		
  +    if(arc_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +                   ((int) xa) - arc_width/2, 
  +                   ((int) ya) - arc_width/2,
  +                   arc_width, arc_width, 0, FULL_CIRCLE);
  +    }
  +  }
  +	
  +}
  +
  +
  +/*! \brief Erase arc described by OBJECT.
  + *  \par Function Description
  + *  This function erases the arc described in the <B>OBJECT</B> structure
  + *  pointed by <B>o_current</B>.
  + *
  + *  It makes a call to the #o_box_draw() function after setting the
  + *  special color. Therefore an arc is drawn with the background color
  + *  over the previous one.
  + */
  +void o_arc_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  w_current->override_color = w_current->background_color;
  +  o_arc_draw(w_current, o_current);
  +  w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_arc_eraserubber(TOPLEVEL *w_current)
  +{
  +  o_arc_rubberarc_xor(w_current);
  +}
  +
  +/*! \brief Draw an arc described by OBJECT with translation
  + *  \par Function Description
  + *  This function draws the arc object described by <B>*o_current</B>
  + *  translated by the vector (<B>dx</B>,<B>dy</B>) with an xor-function over
  + *  the current sheet.
  + *  The translation vector is in screen unit.
  + *
  + *  The arc is displayed with the color of the object.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] dx         Delta x coordinate for arc.
  + *  \param [in] dy         Delta y coordinate for arc.
  + *  \param [in] o_current  Arc OBJECT to draw.
  + */
  +void o_arc_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  +{
  +  int x, y, width, height, start_angle, end_angle;
  +  int color;
  +
  +  if (o_current->arc == NULL) {
  +    return;
  +  }
  +
  +  /* diameter */
  +  width       = o_current->arc->screen_width;
  +  /* height MUST be equal to width, just another name for diameter */
  +  height      = o_current->arc->screen_height;
  +  /* center */
  +  x           = o_current->arc->screen_x - (width  / 2);
  +  y           = o_current->arc->screen_y - (height / 2);
  +  /* start and end angles */
  +  start_angle = o_current->arc->start_angle;
  +  end_angle   = o_current->arc->end_angle;
  +
  +  /* check the size of the displayed arc */
  +  /* do not allow null diameter = arc always displayed */
  +  if (height < 1) {
  +    height = 1;
  +  }
  +  if (width < 1) {
  +    width = 1;
  +  }
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  gdk_gc_set_foreground(w_current->outline_xor_gc,
  +			x_get_darkcolor(color));
  +  /* better to set the line attributes here ? */
  +  gdk_draw_arc(w_current->window, w_current->outline_xor_gc, FALSE,
  +	       x + dx, y + dy, width, height,
  +	       start_angle * 64, end_angle * 64);
  +
  +  /* backing store? not appropriate here  */
  +
  +}
  +
  +/*! \brief Start process to input a new arc.
  + *  \par Function Description
  + *  This function starts the process to input a new arc. Parameters for
  + *  this arc are put into/extracted from the <B>w_current</B> toplevel structure.
  + *  <B>x</B> and <B>y</B> are current coordinates of the pointer in screen unit.
  + *
  + *  First step of the arc input is to set the radius of the arc. The center
  + *  of the arc is kept in (<B>w_current->start_x</B>,<B>w_current->start_y</B>).
  + *  The other point of the radius, i.e. on the arc, in
  + *  (<B>w_current->last_x</B>,<B>w_current->last_y</B>). The radius of the arc is
  + *  in <B>w_current->distance</B>.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_arc_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  /* set the center of the arc */
  +  w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +
  +  /* set the radius */
  +  w_current->distance = 0;
  +
  +  /* set the start and end angles */
  +  w_current->loc_x = w_current->loc_y = 0;
  +
  +  /* start the rubberbanding process of the radius */
  +  o_arc_rubberarc_xor(w_current);
  +  
  +}
  +
  +/*! \brief End the input of an arc.
  + *  \par Function Description
  + *  This function ends the input of the radius of the arc.
  + *  The (<B>x</B>,<B>y</B>) point is taken as the other end of the radius segment.
  + *  The distance between this point and the center is the radius of the arc.
  + *  <B>x</B> and <B>y</B> are in screen coords.
  + *
  + *  At the end of this function, the center of the arc is at
  + *  (<B>w_current->start_x</B>,<B>w_current->start_y</B>) and its radius is
  + *  <B>w_current->distance</B>.
  + *
  + *  The two angles needs to be input to fully define the arc.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_arc_end1(TOPLEVEL *w_current, int x, int y)
  +{
  +  int diff_x, diff_y;
  +	
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  /* erases the previous temporary radius segment */
  +  o_arc_rubberarc_xor(w_current);
  +
  +  w_current->last_x = fix_x(w_current, x);
  +  w_current->last_y = fix_y(w_current, y);
  +  /* compute the radius */
  +  diff_x = GET_BOX_WIDTH (w_current);
  +  diff_y = GET_BOX_HEIGHT(w_current);
  +  if (diff_x >= diff_y) {
  +    w_current->distance = diff_x;
  +  } else {
  +    w_current->distance = diff_y;
  +  }
  +
  +  /* ack! zero length radius */
  +  if (w_current->distance == 0) {
  +    return;
  +  }
  +
  +#if DEBUG
  +  printf("DIST: %d\n", w_current->distance);
  +#endif
  +
  +  /* open a dialog to input the start and end angle */
  +  arc_angle_dialog(w_current);
  +  
  +}
  +
  +/*! \brief Set the start angle of a temporary arc.
  + *  \par Function Description
  + *  This function sets the start angle of the temporary representation of
  + *  an arc. This angle is determined from the current mouse position
  + *  described by <B>x</B> and <B>y</B> in screen coords, and the arc center
  + *  previously set as (<B>w_current->start_x</B>,<B>w_current->start_y</B>).
  + *
  + *  The previous temporary arc is erased, the start angle is then updated
  + *  and finally, the temporary arc is drawn again.
  + *
  + *  This function is used when the input of an arc is fully interactive,
  + *  not through a dialog box.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_arc_end2(TOPLEVEL *w_current, int x, int y)
  +{
  +  double dx, dy, d, cos_a_, sin_a_, a;
  +  
  +  /* erase the previous temporary arc */
  +  o_arc_rubberarc_xor(w_current);
  +
  +  /* compute the start angle */
  +  dx =   ((double) x) - ((double) w_current->start_x);
  +  dy = - ((double) y) + ((double) w_current->start_y);
  +  d  = sqrt((dx * dx) + (dy * dy));
  +
  +  sin_a_ = dy / ((double) d);
  +  cos_a_ = dx / ((double) d);
  +  a = asin(sin_a_) * 180 / M_PI;
  +  if(a < 0) a *= -1;
  +
  +  /* find the right quadrant */
  +  if(sin_a_ >= 0) {
  +    if(cos_a_ >= 0) a = a;
  +    else            a = 180 - a;
  +  } else {
  +    if(cos_a_ >= 0) a = 360 - a;
  +    else            a = 180 + a;
  +  }
  +
  +  /* start angle in degree is in a */
  +  w_current->loc_x = (int) a;
  +
  +  /* draw the new temporary arc */
  +  o_arc_rubberarc_xor(w_current);
  +	
  +}
  +
  +/*! \brief Set the end angle during the input of a new arc object.
  + *  \par Function Description
  + *  This function sets the end angle during the input of a new arc object.
  + *  The angle is computed from the current mouse position in <B>x</B> and
  + *  <B>y</B> and the center of the arc. The arc is internally represented
  + *  with its center in (<B>w_current->start_x</B>,<B>w_current->start_y</B>),
  + *  its radius in <B>w_current->distance</B> and its start angle in
  + *  <B>w_current->loc_x</B>.
  + *
  + *  The temporary arc is erased, a new object is initialized and drawn.
  + *
  + *  This function is used when the input of an arc is fully interactive,
  + *  i.e. not through a dialog box.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current x coordinate of pointer in screen units.
  + */
  +void o_arc_end3(TOPLEVEL *w_current, int x, int y)
  +{
  +  double d, dx, dy, cos_a_, sin_a_, a;
  +  
  +  /* erase the previous temporary arc */
  +  o_arc_rubberarc_xor(w_current);
  +
  +  /* compute the end angle */
  +  dx =   ((double) x) - ((double) w_current->start_x);
  +  dy = - ((double) y) + ((double) w_current->start_y);
  +  d  = sqrt((dx * dx) + (dy * dy));
  +
  +  sin_a_ = dy / ((double) d);
  +  cos_a_ = dx / ((double) d);
  +  a = asin(sin_a_) * 180 / M_PI;
  +  if(a < 0) a *= -1;
  +
  +  /* find the right quadrant */
  +  if(sin_a_ >= 0) {
  +    if(cos_a_ >= 0) a = a;
  +    else            a = 180 - a;
  +  } else {
  +    if(cos_a_ >= 0) a = 360 - a;
  +    else            a = 180 + a;
  +  }
  +
  +  /* end angle in degree is in a */
  +  w_current->loc_y = (int) a;
  +
  +  /* create, initialize and link the new arc object */
  +  w_current->page_current->object_tail =
  +    o_arc_add(w_current, w_current->page_current->object_tail,
  +	      OBJ_ARC, w_current->graphic_color,
  +	      w_current->start_x, w_current->start_y,
  +	      w_current->distance,
  +	      w_current->loc_x, w_current->loc_y);
  +
  +  /* draw the new object */
  +  o_redraw_single(w_current, w_current->page_current->object_tail);
  +
  +  w_current->start_x  = (-1);
  +  w_current->start_y  = (-1);
  +  w_current->last_x   = (-1);
  +  w_current->last_y   = (-1);
  +  w_current->loc_x    = -1;
  +  w_current->loc_y    = -1;
  +  w_current->distance = -1;
  +
  +  w_current->page_current->CHANGED = 1;
  +  
  +  o_undo_savestate(w_current, UNDO_ALL);
  +	
  +}
  +
  +/*! \brief Ends the process of arc input.
  + *  \par Function Description
  + *  The #o_arc_end4() function ends the process of the input of an arc.
  + *  <B>start_angle</B> and <B>end_angle</B> are the start and end angle of the
  + *  arc in degrees. The partial internal representation of the arc, i.e.
  + *  the center and the radius of the arc, are converted in world units.
  + *  A new object is created and linked to the object list.
  + *
  + *  \param [in] w_current    The TOPLEVEL object.
  + *  \param [in] start_angle  Start of angle in degrees.
  + *  \param [in] end_angle    End of angle in degrees.
  + */
  +void o_arc_end4(TOPLEVEL *w_current, int start_angle, int end_angle)
  +{
  +  int x1, y1;
  +  int radius;
  +
  +  /* get the center in world coords */
  +  SCREENtoWORLD(w_current,
  +		w_current->start_x, w_current->start_y,
  +		&x1, &y1);
  +
  +  /* get the radius in world coords */
  +  radius = snap_grid(w_current, WORLDabs(w_current, w_current->distance));
  +
  +  /* create, initialize and link the new arc object */
  +  w_current->page_current->object_tail =
  +    o_arc_add(w_current, w_current->page_current->object_tail,
  +	      OBJ_ARC, w_current->graphic_color,
  +	      x1, y1, radius, start_angle, end_angle);
  +
  +  /* draw the new object */
  +  o_redraw_single(w_current, w_current->page_current->object_tail);
  +
  +  w_current->start_x  = (-1);
  +  w_current->start_y  = (-1);
  +  w_current->last_x   = (-1);
  +  w_current->last_y   = (-1);
  +  w_current->loc_x    = -1;
  +  w_current->loc_y    = -1;
  +  w_current->distance = -1;
  +
  +  w_current->page_current->CHANGED = 1;
  +  
  +  o_undo_savestate(w_current, UNDO_ALL);
  +	
  +}
  +
  +/*! \brief Draw an arc using one angle modification.
  + *  \par Function Description
  + *  This function draws an arc according to its internal representation
  + *  and allows the modification of one of its angle. The start or end
  + *  angle of the arc is updated according to <B>whichone</B> with the angle
  + *  that the current pointer and the arc center are making with the horizontal.
  + *
  + *  The previous temporary arc is erased, the angle is then computed
  + *  and updated and finally a new temporary arc with the new angle is drawn.
  + *
  + *  The arc is internally described by :
  + *  <DL>
  + *    <DT>*</DT><DD>(<B>w_current->start_x</B>,<B>w_current->start_y</B>) as
  + *                   its center.
  + *    <DT>*</DT><DD><B>w_current->distance</B> as its radius.
  + *    <DT>*</DT><DD><B>w_current->loc_x</B> and <B>w_current->loc_y</B> as its
  + *                  start and end angle respectively.
  + *  </DL>
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + *  \param [in] whichone   Which angle to change.
  + *
  + *  <B>whichone</B> can have one of the following values:
  + *  <DL>
  + *    <DT>*</DT><DD>ARC_START_ANGLE
  + *    <DT>*</DT><DD>ARC_END_ANGLE
  + *  </DL>
  + */
  +void o_arc_rubberarc(TOPLEVEL *w_current, int x, int y, int whichone)
  +{
  +  double  dx, dy, a;
  +  int diff_x, diff_y;
  +
  +  /* erase the previous temporary arc */
  +  o_arc_rubberarc_xor(w_current);
  +
  +  if(whichone == ARC_RADIUS) {
  +
  +    /*
  +     * The radius is taken as the biggest distance on the x and y
  +     * axis between the center of the arc and the mouse position.
  +     */		
  +    /* update the radius */
  +    w_current->last_x = fix_x(w_current, x);
  +    w_current->last_y = fix_y(w_current, y);
  +
  +    diff_x = GET_BOX_WIDTH (w_current);
  +    diff_y = GET_BOX_HEIGHT(w_current);
  +    if (diff_x >= diff_y) {
  +      w_current->distance = diff_x;
  +    } else {
  +      w_current->distance = diff_y;
  +    }
  +
  +  }
  +  else if((whichone == ARC_START_ANGLE) || (whichone == ARC_END_ANGLE)) {
  +		
  +    /* compute the angle */
  +    dx =   ((double) x) - ((double) w_current->start_x);
  +    dy = - ((double) y) + ((double) w_current->start_y);
  +    a = atan2(dy,dx) * 180 / M_PI;
  +
  +    /* set the start or end angle with this angle */
  +    switch(whichone) {
  +    case ARC_START_ANGLE:
  +      w_current->loc_x = ((int) a + 360) % 360;
  +      break;
  +	
  +    case ARC_END_ANGLE:
  +      w_current->loc_y = ((int) a - w_current->loc_x + 720) % 360;
  +      break;
  +	
  +    default:
  +      return;
  +    }
  +
  +  }
  +	
  +  /* draw the new temporary arc */
  +  o_arc_rubberarc_xor(w_current);
  +
  +}
  +
  +/*! \brief Draw arc from TOPLEVEL object.
  + *  \par Function Description
  + *  This function draws the arc from the variables in the toplevel
  + *  structure <B>*w_current</B>.
  + *  The center of the arc is at (<B>w_current->start_x</B>,
  + *  <B>w_current->start_y</B>), its radius equal to <B>w_current->radius</B>,
  + *  and the start and end angle are given by <B>w_current->loc_x</B> and
  + *  <B>w_current->loc_y</B>.
  + *
  + *  The arc is drawn with a xor function over the current sheet with the
  + *  selection color.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + */
  +void o_arc_rubberarc_xor(TOPLEVEL *w_current)
  +{
  +  double tmp;
  +  int x1, y1;
  +	
  +  gdk_gc_set_foreground(w_current->xor_gc, 
  +			x_get_darkcolor(w_current->select_color));
  +  gdk_gc_set_line_attributes(w_current->xor_gc, 0, 
  +			     GDK_LINE_SOLID, GDK_CAP_NOT_LAST, 
  +			     GDK_JOIN_MITER);
  +  /* draw the arc from the w_current variables */
  +  gdk_draw_arc(w_current->window, w_current->xor_gc, FALSE,
  +	       w_current->start_x - w_current->distance,
  +	       w_current->start_y - w_current->distance,
  +	       w_current->distance * 2,
  +	       w_current->distance * 2,
  +	       w_current->loc_x * 64,
  +	       w_current->loc_y * 64);
  +  /* draw the radius segment from the w_current variables */
  +  tmp = ((double) w_current->loc_x) * M_PI / 180;
  +  x1 = w_current->start_x + w_current->distance*cos(tmp);
  +  y1 = w_current->start_y - w_current->distance*sin(tmp);
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		w_current->start_x, w_current->start_y,
  +		x1, y1);
  +	
  +}
  +
  +/*! \brief Draw grip marks on arc.
  + *  \par Function Description
  + *  This function draws three grips on the center and on the ends of
  + *  the arc object described by <B>*o_current</B>.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Arc OBJECT to draw grip points on.
  + */
  +void o_arc_draw_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  int radius, x, y, start_angle, end_angle;
  +  int x1, y1, x2, y2;
  +
  +  if (w_current->draw_grips == FALSE)
  +    return;
  +
  +  /*
  +   * An arc has three grips:
  +   * <DL>
  +   *   <DT>*</DT><DD>one at the center that allows changes on the
  +   *                 radius - at (<B>x</B>,<B>y</B>).
  +   *   <DT>*</DT><DD>one at the start of the arc - at (<B>x1</B>,<B>y1</B>).
  +   *   <DT>*</DT><DD>one at the end of the arc - at (<B>x2</B>,<B>y2</B>).
  +   */
  +
  +  x           = o_current->arc->screen_x;
  +  y           = o_current->arc->screen_y;
  +  radius      = o_current->arc->screen_width / 2;
  +  start_angle = o_current->arc->start_angle;
  +  end_angle   = o_current->arc->end_angle;
  +
  +  x1 = x + radius * cos(((double) start_angle) * M_PI / 180);
  +  y1 = y - radius * sin(((double) start_angle  ) * M_PI / 180);
  +  x2 = x + radius * cos(((double) (start_angle + end_angle)) * M_PI / 180);
  +  y2 = y - radius * sin(((double) (start_angle + end_angle)) * M_PI / 180);
  +
  +  /* draw the grip at the center */
  +  o_grips_draw(w_current,  x,  y);
  +
  +  /* draw the grip at the start_angle end of the arc */
  +  o_grips_draw(w_current, x1, y1);
  +
  +  /* draw the grip at the end_angle end of the arc */
  +  o_grips_draw(w_current, x2, y2);
  +
  +}
  +
  +/*! \brief Erase grip marks from arc.
  + *  \par Function Description
  + *  This function erases the three grips displayed on the <B>o_current</B>
  + *  arc object. These grips are on the center of the arc and on each end
  + *  of the arc.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Arc OBJECT to remove grip marks from.
  + */
  +void o_arc_erase_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  int radius, x, y, start_angle, end_angle;
  +  int x1, y1, x2, y2;
  +
  +  if (w_current->draw_grips == FALSE)
  +    return;
  +
  +  /*
  +   * The coordinates of the three grips are determined by the parameters
  +   * of the arc. The grips are centered at (<B>x</B>,<B>y</B>), (<B>x1</B>,<B>y1</B>)
  +   * and (<B>x2</B>,<B>y2</B>).
  +   */
  +
  +  x           = o_current->arc->screen_x;
  +  y           = o_current->arc->screen_y;
  +  radius      = o_current->arc->screen_width / 2;
  +  start_angle = o_current->arc->start_angle;
  +  end_angle   = o_current->arc->end_angle;
  +
  +  x1 = x + radius * cos(((double) start_angle) * M_PI / 180);
  +  y1 = y - radius * sin(((double) start_angle) * M_PI / 180);
  +  x2 = x + radius * cos(((double) start_angle + end_angle) * M_PI / 180);
  +  y2 = y - radius * sin(((double) start_angle + end_angle) * M_PI / 180);
  +
  +  /* erase the grip at the center */
  +  o_grips_erase(w_current,  x,  y);
  +
  +  /* erase the grip at the start_angle end of the arc */
  +  o_grips_erase(w_current, x1, y1);
  +
  +  /* erase the grip at the end_angle end of the arc */
  +  o_grips_erase(w_current, x2, y2);
  +
  +}
  
  
  
  1.24      +415 -343  eda/geda/gaf/gschem/src/o_attrib.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_attrib.c
  ===================================================================
  RCS file: o_attrib.c
  diff -N o_attrib.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_attrib.c	14 Jul 2006 02:23:54 -0000	1.24
  @@ -0,0 +1,496 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* No special type for attributes */
  +/* You can only edit text attributes */
  +
  +/* be sure in o_copy o_move o_delete you maintain the attributes */
  +/* delete is a bare, because you will have to unattach the other end */
  +/* and in o_save o_read as well */
  +/* and in o_select when selecting objects, select the attributes */
  +
  +/* there needs to be a modifier (in struct.h, such as a flag) which
  + * signifies that this is an attribute */
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  Copy all attributes select to the selection list.
  + *
  + *  \todo get a better name
  + */
  +void o_attrib_add_selected(TOPLEVEL *w_current, SELECTION* selection_list,
  +			   OBJECT *selected)
  +{
  +  ATTRIB *a_current;
  +
  +  if (!selection_list) return;
  +
  +  /* deal with attributes here? */
  +  if (selected->attribs != NULL) {
  +    /* first node is head */
  +    a_current = selected->attribs->next;
  +
  +    while (a_current != NULL) {
  +
  +      if (a_current->object) {
  +
  +				/* make sure object isn't selected already */
  +        if (a_current->object->saved_color == -1) {
  +          o_selection_add(selection_list,
  +                          /* w_current->page_current->
  +                             selection2_head,*/
  +                          a_current->object);
  +          o_redraw_single(w_current, a_current->object);
  +        }
  +
  +      }
  +
  +      a_current = a_current->next;
  +    }
  +  }
  +
  +  return;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_attrib_toggle_visibility(TOPLEVEL *w_current, SELECTION *list)
  +{
  +  SELECTION *s_current = NULL;
  +  OBJECT *object = NULL;
  +
  +  if (list == NULL) {
  +    return;
  +  }
  +
  +  s_current = list;
  +
  +  while(s_current != NULL) {
  +    object = s_current->selected_object;
  +    if (object == NULL) {
  +      fprintf(stderr, _("Got NULL in o_attrib_toggle_visibility\n"));
  +      exit(-1);
  +    }
  +
  +    if (object->type == OBJ_TEXT) {
  +      if (object->visibility == VISIBLE) {
  +
  +        /* only erase if we are not showing hidden text */
  +        if (!w_current->show_hidden_text) {
  +          o_text_erase(w_current, object);
  +        }
  +        
  +        object->visibility = INVISIBLE;
  +
  +        if (w_current->show_hidden_text) {
  +          /* draw text so that little I is drawn */
  +          o_text_draw(w_current, object); 
  +        }
  +
  +        w_current->page_current->CHANGED=1;
  +      } else {
  +        /* if we are in the special show hidden mode, then erase text first */
  +        /* to get rid of the little I */
  +        if (w_current->show_hidden_text) {
  +          o_text_erase(w_current, object);
  +        }
  +
  +        object->visibility = VISIBLE;
  +        
  +        /* you must do this since real->text->complex */
  +        /* might be null when text is invisible */
  +        if (object->text->prim_objs == NULL)
  +          o_text_recreate(w_current, object);
  +
  +        
  +        o_text_draw(w_current, object);
  +        w_current->page_current->CHANGED = 1;
  +      }
  +    }
  +    s_current = s_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_attrib_toggle_show_name_value(TOPLEVEL *w_current, 
  +				     SELECTION *list, int new_show_name_value)
  +{
  +  SELECTION *s_current = NULL;
  +  OBJECT *object = NULL;
  +
  +  if (list == NULL) {
  +    return;
  +  }
  +
  +  s_current = list;
  +
  +  while(s_current != NULL) {
  +    object = s_current->selected_object;
  +
  +    if (object == NULL) {
  +      fprintf(stderr, _("Got NULL in o_attrib_toggle_show_name_value\n"));
  +      exit(-1);
  +    }
  +
  +    if (object->type == OBJ_TEXT) {
  +      o_text_erase(w_current, object);
  +      object->show_name_value = new_show_name_value;
  +      o_text_recreate(w_current, object);
  +      o_text_draw(w_current, object);
  +      w_current->page_current->CHANGED=1;
  +    }
  +    s_current = s_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_attrib_start(TOPLEVEL *w_current, int screen_x, int screen_y)
  +{
  +  int x, y;
  +  char *value;
  +
  +  w_current->last_x = w_current->start_x = fix_x(w_current, screen_x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, screen_y);
  +
  +  w_current->last_drawb_mode = -1;
  +
  +  /* make sure list is null first, so that you don't have a mem leak */
  +  SCREENtoWORLD(w_current,
  +                w_current->start_x,
  +                w_current->start_y,
  +                &x,
  +                &y);
  +
  +  /* remove the old attrib list if it exists */
  +  /* without killing the head structure */
  +  o_list_delete_rest(w_current,
  +                     w_current->page_current->attrib_place_head);
  +
  +  /*! \todo change this so that it only changes the value not the
  +   * whole thing */
  +  /* attribute names are case sensitive */
  +
  +  value = strstr(w_current->current_attribute, "=");
  +
  +  if (value == NULL) {
  +    fprintf(stderr,
  +            _("ERROR! you can't get an attribute without an ='s\n"));
  +    exit(-1);
  +  }
  +
  +  switch(w_current->text_caps) {
  +    case(LOWER):
  +    string_tolower(value, value);
  +    break;
  +
  +    case(UPPER):
  +    string_toupper(value, value);
  +    break;
  +
  +    case(BOTH):
  +    default:
  +    /* do nothing */
  +    break;
  +  }
  +
  +  /* here you need to add OBJ_TEXT when it's done */
  +  w_current->page_current->attrib_place_tail = (OBJECT *)
  +  o_text_add(
  +             w_current,
  +             w_current->page_current->attrib_place_head,
  +             /* type changed from TEXT to TEXT */
  +             OBJ_TEXT, w_current->detachedattr_color,
  +             x,
  +             y,
  +             LOWER_LEFT,
  +             0, /* zero is angle */
  +             w_current->current_attribute,
  +             w_current->text_size,
  +             /* has to be visible so you can place it */
  +             /* visibility is set when you create the object */
  +             VISIBLE, w_current->current_show);
  +
  +  o_drawbounding(w_current,
  +                 w_current->page_current->attrib_place_head->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_attrib_end(TOPLEVEL *w_current)
  +{
  +  int world_x, world_y; /* get consistant names hack */
  +  OBJECT *object;
  +
  +  SCREENtoWORLD(w_current,
  +                w_current->last_x,
  +                w_current->last_y,
  +                &world_x,
  +                &world_y);
  +
  +  world_x = snap_grid(w_current, world_x);
  +  world_y = snap_grid(w_current, world_y);
  +
  +  /* here you need to add OBJ_TEXT when it's done */
  +  /* make this VIS and SHOW default configurable hack */
  +  w_current->page_current->object_tail =
  +  o_text_add(w_current, w_current->page_current->object_tail,
  +				/* type changed from TEXT to TEXT */
  +             OBJ_TEXT, w_current->detachedattr_color,
  +             world_x,
  +             world_y,
  +             LOWER_LEFT,
  +             0, /* zero is angle */
  +             w_current->current_attribute,
  +             w_current->text_size,
  +             w_current->current_visible,
  +             w_current->current_show);
  +
  +  /* if the attribute is invisible then you need to erase the
  +   * outline left by the place */
  +  if (w_current->current_visible == INVISIBLE) {
  +
  +    o_drawbounding(w_current,
  +                   w_current->page_current->
  +                   attrib_place_head->next,
  +                   NULL,
  +                   x_get_darkcolor(w_current->bb_color), FALSE);
  +  }
  +
  +  /*! \todo you need to erase the bounding box if have that mode
  +   * set!!! hack */
  +  /* erase the old bounding box / outline */
  +  if (w_current->actionfeedback_mode == OUTLINE) {
  +    o_drawbounding(w_current,
  +                   w_current->page_current->
  +                   attrib_place_head->next,
  +                   NULL,
  +                   x_get_color(w_current->text_color), FALSE);
  +  } else {
  +    o_drawbounding(w_current,
  +                   w_current->page_current->
  +                   attrib_place_head->next,
  +                   NULL,
  +                   x_get_darkcolor(w_current->select_color), FALSE);
  +  }
  +
  +  w_current->override_color = -1;
  +
  +  (*w_current->page_current->
  +   object_tail->draw_func)(w_current, w_current->page_current->object_tail);
  +
  +  w_current->page_current->CHANGED = 1;
  +
  +  /* here is where you attach the stuff */
  +  /* if an object is selected, else just place it */
  +  /* selection_head should never be null since it has a head struct */
  +  object = o_select_return_first_object(w_current);
  +  if (object != NULL) {
  +    /* should attribute be selected? probably */
  +    /* this is probably okay, NEWSEL, since tail is a single obj */
  +    o_attrib_attach(w_current,
  +                    w_current->page_current->object_head,
  +                    w_current->page_current->object_tail,
  +                    object);
  +  }
  +
  +  o_selection_add(w_current->page_current->selection2_head,
  +                  w_current->page_current->object_tail);
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_attrib_rubberattrib(TOPLEVEL *w_current)
  +{
  +  o_drawbounding(w_current,
  +                 w_current->page_current->attrib_place_head->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), FALSE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* This function no longer returns NULL, but will always return the new */
  +/* text item */
  +OBJECT *o_attrib_add_attrib(TOPLEVEL *w_current,
  +			    char *text_string, int visibility, 
  +			    int show_name_value, OBJECT *object)
  +{
  +  int world_x = - 1, world_y = -1;
  +  int color; 
  +  int left, right, top, bottom;
  +  OBJECT *o_current;
  +
  +  color = w_current->detachedattr_color;
  +
  +  o_current = object;
  +
  +  /* creating a toplevel or unattached attribute */
  +  if (o_current) {
  +    /* get coordinates of where to place the text object */
  +    switch(o_current->type) {
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        world_x = o_current->complex->x;
  +        world_y = o_current->complex->y;
  +        color = w_current->attribute_color;
  +        break;
  +
  +      case(OBJ_ARC):
  +        world_x = o_current->arc->x;
  +        world_y = o_current->arc->y;
  +        color = w_current->attribute_color;
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        world_x = o_current->circle->center_x;
  +        world_y = o_current->circle->center_y;
  +        color = w_current->attribute_color;
  +        break;
  +
  +      case(OBJ_BOX):
  +        world_x = o_current->box->upper_x;
  +        world_y = o_current->box->upper_y;
  +        color = w_current->attribute_color;
  +        break;
  +
  +      case(OBJ_LINE):
  +      case(OBJ_NET):
  +      case(OBJ_PIN):
  +      case(OBJ_BUS):
  +        world_x = o_current->line->x[0];
  +        world_y = o_current->line->y[0];
  +        color = w_current->attribute_color;
  +        break;
  +
  +      case(OBJ_TEXT):
  +
  +        world_x = o_current->text->x;
  +        world_y = o_current->text->y;
  +			
  +        color = w_current->detachedattr_color;
  +        o_current = NULL;	
  +			
  +#if 0 /* don't error out, instead treat text like another OBJECT, but */
  +        /* don't attach it anywhere */
  +        /* s_log_message("Cannot attach attribute to text item\n");*/
  +        /* return(NULL);*/
  +#endif
  +        break;
  +    }
  +  } else {
  +    world_get_complex_bounds(w_current, 
  +                             w_current->page_current->object_head,
  +                             &left, &top, &right, &bottom);
  +	
  +    /* this really is the lower left hand corner */	
  +    world_x = left; 
  +    world_y = top;  
  +
  +    /* printf("%d %d\n", world_x, world_y); */
  +    color = w_current->detachedattr_color;
  +  }
  +
  +  /* first create text item */
  +  w_current->page_current->object_tail =
  +  o_text_add(w_current, w_current->page_current->object_tail,
  +             OBJ_TEXT, color,
  +             world_x,
  +             world_y,
  +             LOWER_LEFT,
  +             0, /* zero is angle */
  +             text_string,
  +             w_current->text_size,  /* current text size */ 
  +             visibility, show_name_value);
  +
  +  /* now w_current->page_current->object_tail contains new text item */
  +
  +  /* now attach the attribute to the object (if o_current is not NULL) */
  +  /* remember that o_current contains the object to get the attribute */
  +  if (o_current) {
  +    o_attrib_attach(w_current, w_current->page_current->object_head,
  +                    w_current->page_current->object_tail,
  +                    o_current);
  +  }
  +
  +  o_selection_add(w_current->page_current->selection2_head,
  +                  w_current->page_current->object_tail);
  +
  +  o_text_erase(w_current, w_current->page_current->object_tail); 
  +  o_text_draw(w_current, w_current->page_current->object_tail);
  +
  +  /* handle slot= attribute, it's a special case */
  +  if (g_ascii_strncasecmp (text_string, "slot=", 5) == 0) {
  +    o_slot_end (w_current, text_string, strlen (text_string));
  +  }
  +
  +  /* Run the add attribute hook */
  +  if (scm_hook_empty_p(add_attribute_hook) == SCM_BOOL_F &&
  +      object != NULL) {
  +	scm_run_hook(add_attribute_hook,
  +		     scm_cons(g_make_object_smob(w_current, 
  +						 o_current),
  +			      SCM_EOL));
  +      }
  +  
  +  w_current->page_current->CHANGED = 1;
  +
  +  return(w_current->page_current->object_tail);
  +}
  
  
  
  1.19      +722 -450  eda/geda/gaf/gschem/src/o_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_basic.c
  ===================================================================
  RCS file: o_basic.c
  diff -N o_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_basic.c	14 Jul 2006 02:23:54 -0000	1.19
  @@ -0,0 +1,829 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +
  +/* instrumentation code */
  +#if 0
  +#include <sys/time.h>
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/x_states.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Lots of Gross code... needs lots of cleanup - mainly
  + * readability issues
  + */
  +
  +/* Kazu on July 16, 1999 - Added these macros to simplify the code */
  +#define GET_BOX_WIDTH(w)			\
  +	abs((w)->last_x - (w)->start_x)
  +#define GET_BOX_HEIGHT(w)			\
  +	abs((w)->last_y - (w)->start_y)
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_redraw_all(TOPLEVEL *w_current)
  +{
  +#if 0
  +  struct timeval tv1;
  +  struct timeval tv2;
  +#endif
  +
  +  if (!w_current->DONT_REDRAW) {
  +    x_repaint_background(w_current);
  +  }
  +
  +#if 0
  +  gettimeofday(&tv1, NULL);
  +#endif
  +
  +  o_recalc(w_current, w_current->page_current->object_head);
  +
  +  if (!w_current->DONT_REDRAW) {
  +    o_redraw(w_current, w_current->page_current->complex_place_head->next);
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    o_cue_redraw_all(w_current,
  +                     w_current->page_current->object_head);
  +  }
  +
  +#if 0
  +  gettimeofday(&tv2, NULL);
  +  printf("secs: %d\n", tv2.tv_sec - tv1.tv_sec);
  +  printf("usecs: %d\n\n", tv2.tv_usec - tv1.tv_usec);
  +#endif
  +
  +  if (w_current->inside_action) {
  +    switch(w_current->event_state) {
  +      case(MOVE):
  +      case(ENDMOVE):
  +	o_erase_selected(w_current);	
  +	/* continue */
  +      case(ENDCOPY):
  +      case(ENDMCOPY):
  +	o_drawbounding(w_current, NULL,
  +                       w_current->page_current->selection2_head->next,
  +                       x_get_darkcolor(w_current->bb_color), FALSE);
  +
  +        break;
  +
  +      case(DRAWCOMP):
  +      case(ENDCOMP):
  +        o_drawbounding(w_current, 
  +		       w_current->page_current->complex_place_head->next,
  +                       NULL,
  +                       x_get_darkcolor(w_current->bb_color), FALSE);
  +        break;
  +
  +      case(DRAWATTRIB):
  +      case(ENDATTRIB):
  +      case(DRAWTEXT):
  +      case(ENDTEXT):
  +        o_drawbounding(w_current, w_current->
  +                       page_current->
  +                       attrib_place_head->next,
  +                       NULL,
  +                       x_get_darkcolor(w_current->bb_color), FALSE);
  +        break;
  +      case (GRIPS):
  +	o_erase_selected(w_current);	
  +	break;
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* basically like above but doesn't do the o_conn_disconnect_update */
  +void o_redraw_all_fast(TOPLEVEL *w_current)
  +{
  +  if (!w_current->DONT_REDRAW) {
  +    x_repaint_background(w_current);
  +  }
  +
  +  o_recalc(w_current, w_current->page_current->object_head);
  +
  +  if (!w_current->DONT_REDRAW) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    o_cue_redraw_all(w_current,
  +                     w_current->page_current->object_head);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_redraw(TOPLEVEL *w_current, OBJECT *object_list)
  +{
  +  OBJECT *o_current = object_list;
  +
  +  while (o_current != NULL) {
  +    if ((o_current->draw_func != NULL) &&
  +        (o_current->type != OBJ_HEAD)) {
  +      w_current->inside_redraw = 1;
  +      (*o_current->draw_func)(w_current, o_current);
  +      w_current->inside_redraw = 0;
  +    }
  +
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_unselect_all(TOPLEVEL *w_current)
  +{
  +  if (!w_current->SHIFTKEY) {
  +    o_select_run_hooks(w_current, NULL, 2);
  +    o_selection_remove_most(w_current, w_current->page_current->
  +                            selection2_head); 
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_draw_list(TOPLEVEL *w_current, GList* list)
  +{
  +  OBJECT* o_current;
  +  GList *l_current;
  +
  +  if (w_current->inside_redraw) {
  +    return;
  +  }
  +
  +  l_current = list;
  +  while (l_current != NULL) {
  +
  +    o_current = (OBJECT *) l_current->data;
  +
  +    if (o_current) {
  +      o_redraw_single(w_current, o_current);
  +    }
  +    
  +    l_current = l_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_draw_selected(TOPLEVEL *w_current)
  +{
  +  SELECTION* s_current;
  +  OBJECT* o_current;
  +  if (w_current->inside_redraw) {
  +    return;
  +  }
  +
  +  s_current = w_current->page_current->selection2_head->next;
  +  while (s_current != NULL) {
  +    o_current=s_current->selected_object;
  +
  +    if (o_current) {
  +      o_redraw_single(w_current, o_current);
  +    }
  +    
  +    s_current=s_current->next;
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_erase_selected(TOPLEVEL *w_current)
  +{
  +  SELECTION* s_current;
  +  OBJECT* o_current;
  +  if (w_current->inside_redraw) {
  +    return;
  +  }
  +
  +  s_current = w_current->page_current->selection2_head->next;
  +  while (s_current != NULL) {
  +    o_current=s_current->selected_object;
  +
  +    if (o_current) {
  +      o_cue_erase_single(w_current, o_current);
  +      o_erase_single(w_current, o_current);
  +    }
  +    
  +    s_current=s_current->next;
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_erase_single(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  OBJECT *o_current;
  +
  +  if (w_current->inside_redraw) {
  +    return;
  +  }
  +
  +  o_current = object;
  +
  +  w_current->DONT_DRAW_CONN = 1;
  +  w_current->override_color = w_current->background_color;
  +  if (o_current != NULL) {
  +    if (o_current->draw_func &&
  +        o_current->type != OBJ_HEAD) {
  +      (*o_current->draw_func)(w_current, o_current);
  +    }
  +  }
  +  w_current->override_color = -1;
  +  w_current->DONT_DRAW_CONN = 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* both outline and boundingbox work! */
  +/* name is blah */
  +void o_drawbounding(TOPLEVEL *w_current, OBJECT *o_list, SELECTION *s_list, 
  +		    GdkColor *color, int firsttime)
  +{
  +  int diff_x, diff_y;
  +  int test_x, test_y;
  +
  +  /* static is highly temp */	
  +  /* you have to make these static... for the once mode */
  +  static int rleft, rtop, rbottom, rright;
  +
  +  if (!o_list && !s_list) {
  +    return;
  +  }
  +
  +  if ((w_current->last_drawb_mode == OUTLINE) &&
  +      (w_current->actionfeedback_mode == BOUNDINGBOX)) {
  +#if DEBUG
  +    printf("going to bounding\n");
  +#endif
  +
  +    diff_x = w_current->last_x - w_current->start_x;
  +    diff_y = w_current->last_y - w_current->start_y;
  +
  +    gdk_gc_set_foreground(w_current->bounding_xor_gc,
  +                          x_get_color(
  +                                      w_current->background_color));
  +    if (o_list) {
  +      o_complex_translate_display(w_current,
  +                                  diff_x,
  +                                  diff_y,
  +                                  o_list);
  +    } else if (s_list) { 
  +      o_complex_translate_display_selection(w_current,
  +					    diff_x,
  +					    diff_y,
  +					    s_list);
  +    }
  +
  +    gdk_gc_set_foreground(w_current->bounding_xor_gc, color);
  +
  +    if (o_list) {
  +      get_complex_bounds(w_current, o_list,
  +                         &rleft  ,
  +                         &rtop   ,
  +                         &rright ,
  +                         &rbottom);
  +    } else if (s_list) {
  +      get_complex_bounds_selection(w_current, s_list,
  +				   &rleft  ,
  +				   &rtop   ,
  +				   &rright ,
  +				   &rbottom);
  +    }
  +
  +    gdk_draw_rectangle(w_current->window,
  +                       w_current->bounding_xor_gc, FALSE,
  +                       rleft + diff_x,
  +                       rtop  + diff_y,
  +                       rright  - rleft,
  +                       rbottom - rtop);
  +
  +  }
  +
  +  if ((w_current->last_drawb_mode == BOUNDINGBOX) &&
  +      (w_current->actionfeedback_mode == OUTLINE)) {
  +#if DEBUG
  +        printf("going to outline\n");
  +#endif
  +
  +        if (o_list) {
  +          get_complex_bounds(w_current, o_list,
  +                             &rleft  ,
  +                             &rtop   ,
  +                             &rright ,
  +                             &rbottom);
  +        } else if (s_list) {
  +          get_complex_bounds_selection(w_current, s_list,
  +                                       &rleft  ,
  +                                       &rtop   ,
  +                                       &rright ,
  +                                       &rbottom);
  +        }
  +
  +        diff_x = w_current->last_x - w_current->start_x;
  +        diff_y = w_current->last_y - w_current->start_y;
  +        gdk_gc_set_foreground(w_current->gc,
  +                              x_get_color(
  +                                          w_current->background_color) );
  +        gdk_draw_rectangle(w_current->window,
  +                           w_current->gc, FALSE,
  +                           rleft   + diff_x,
  +                           rtop    + diff_y,
  +                           rright  - rleft ,
  +                           rbottom - rtop  );
  +
  +        if (o_list) {
  +          o_complex_translate_display(w_current,
  +                                      diff_x,
  +                                      diff_y,
  +                                      o_list);
  +        } else if (s_list) { 
  +          o_complex_translate_display_selection(w_current,
  +                                                diff_x,
  +                                                diff_y,
  +                                                s_list);
  +        }
  +      }
  +
  +  w_current->last_drawb_mode = w_current->actionfeedback_mode;
  +
  +  /* everything above is okay */
  +
  +  /*! \todo much replicated code... this is the behaviour we need, but
  +   * we need to clean it up !!!
  +   */
  +
  +  /* erase old outline */
  +  /* going to constrained from free */
  +  if ( (w_current->CONTROLKEY) &&
  +       (w_current->drawbounding_action_mode == FREE)) {
  +    diff_x = w_current->last_x - w_current->start_x;
  +    diff_y = w_current->last_y - w_current->start_y;
  +#if 0
  +    printf("switching to contrained\n");
  +#endif
  +    w_current->drawbounding_action_mode = CONSTRAINED;
  +
  +    if (w_current->actionfeedback_mode == OUTLINE) {
  +      if (o_list) {
  +        o_complex_translate_display(w_current,
  +                                    diff_x,
  +                                    diff_y,
  +                                    o_list);
  +      } else if (s_list) { 
  +        o_complex_translate_display_selection(w_current,
  +                                              diff_x,
  +                                              diff_y,
  +                                              s_list);
  +      }
  +    } else {
  +      if (o_list) {
  +        get_complex_bounds(w_current, o_list,
  +                           &rleft  ,
  +                           &rtop   ,
  +                           &rright ,
  +                           &rbottom);
  +      } else if (s_list) {
  +        get_complex_bounds_selection(w_current, s_list,
  +                                     &rleft  ,
  +                                     &rtop   ,
  +                                     &rright ,
  +                                     &rbottom);
  +      }
  +
  +      gdk_gc_set_foreground(w_current->bounding_xor_gc,
  +                            color);
  +      gdk_draw_rectangle(w_current->window,
  +                         w_current->bounding_xor_gc, FALSE,
  +                         rleft + diff_x,
  +                         rtop  + diff_y,
  +                         rright  - rleft,
  +                         rbottom - rtop);
  +    }
  +
  +    test_x = GET_BOX_WIDTH (w_current);
  +    test_y = GET_BOX_HEIGHT(w_current);
  +    if (test_x >= test_y) {
  +      w_current->last_y = w_current->start_y;
  +    } else {
  +      w_current->last_x = w_current->start_x;
  +    }
  +
  +    diff_x = w_current->last_x - w_current->start_x;
  +    diff_y = w_current->last_y - w_current->start_y;
  +
  +    if (w_current->actionfeedback_mode == OUTLINE) {
  +      if (o_list) {
  +        o_complex_translate_display(w_current,
  +                                    diff_x,
  +                                    diff_y,
  +                                    o_list);
  +      } else if (s_list) { 
  +        o_complex_translate_display_selection(w_current,
  +                                              diff_x,
  +                                              diff_y,
  +                                              s_list);
  +      }
  +    } else {
  +      if (o_list) {
  +        get_complex_bounds(w_current, o_list,
  +                           &rleft  ,
  +                           &rtop   ,
  +                           &rright ,
  +                           &rbottom);
  +      } else if (s_list) {
  +        get_complex_bounds_selection(w_current, s_list,
  +                                     &rleft  ,
  +                                     &rtop   ,
  +                                     &rright ,
  +                                     &rbottom);
  +      }
  +      gdk_gc_set_foreground(w_current->bounding_xor_gc,
  +                            color);
  +      gdk_draw_rectangle(w_current->window,
  +                         w_current->bounding_xor_gc,
  +                         FALSE,
  +                         rleft   + diff_x,
  +                         rtop    + diff_y,
  +                         rright  - rleft,
  +                         rbottom - rtop);
  +    }
  +
  +    if (w_current->netconn_rubberband) {
  +      o_move_stretch_rubberband(w_current);
  +      o_move_stretch_rubberband(w_current);
  +    }
  +  }
  +
  +  /* erase old outline */
  +  /* going to free from constrained */
  +  if ((!w_current->CONTROLKEY) &&
  +      (w_current->drawbounding_action_mode == CONSTRAINED)) {
  +#if 0
  +        printf("switching to free\n");
  +#endif
  +        diff_x = w_current->last_x - w_current->start_x;
  +        diff_y = w_current->last_y - w_current->start_y;
  +        w_current->drawbounding_action_mode = FREE;
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          /* do it twice to get rid of old outline */
  +          if (o_list) {
  +            o_complex_translate_display(w_current,
  +                                        diff_x,
  +                                        diff_y,
  +                                        o_list);
  +            o_complex_translate_display(w_current,
  +                                        diff_x,
  +                                        diff_y,
  +                                        o_list);
  +          } else if (s_list) { 
  +            o_complex_translate_display_selection(w_current,
  +                                                  diff_x,
  +                                                  diff_y,
  +                                                  s_list);
  +            o_complex_translate_display_selection(w_current,
  +                                                  diff_x,
  +                                                  diff_y,
  +                                                  s_list);
  +          }
  +        } else {
  +          /*! \todo why are we doing this here...?
  +           * probably a reason */
  +          if (o_list) {
  +            get_complex_bounds(w_current, o_list,
  +                               &rleft  ,
  +                               &rtop   ,
  +                               &rright ,
  +                               &rbottom);
  +          } else if (s_list) {
  +            get_complex_bounds_selection(w_current, s_list,
  +                                         &rleft  ,
  +                                         &rtop   ,
  +                                         &rright ,
  +                                         &rbottom);
  +          }
  +        }
  +        if (w_current->netconn_rubberband) {
  +          o_move_stretch_rubberband(w_current);
  +          o_move_stretch_rubberband(w_current);
  +        }
  +      }
  +
  +  if (w_current->CONTROLKEY) {
  +    test_x = GET_BOX_WIDTH (w_current);
  +    test_y = GET_BOX_HEIGHT(w_current);
  +    if (test_x >= test_y) {
  +      w_current->last_y = w_current->start_y;
  +    } else {
  +      w_current->last_x = w_current->start_x;
  +    }
  +  }
  +
  +  if (w_current->actionfeedback_mode == BOUNDINGBOX) {
  +
  +    if (firsttime == TRUE) {
  +      if (o_list) {
  +        get_complex_bounds(w_current, o_list,
  +                           &rleft  ,
  +                           &rtop   ,
  +                           &rright ,
  +                           &rbottom);
  +      } else if (s_list) {
  +        get_complex_bounds_selection(w_current, s_list,
  +                                     &rleft  ,
  +                                     &rtop   ,
  +                                     &rright ,
  +                                     &rbottom);
  +      }
  +      /*printf("once\n");*/
  +    
  +    }
  +    diff_x = w_current->last_x - w_current->start_x;
  +    diff_y = w_current->last_y - w_current->start_y;
  +    gdk_gc_set_foreground(w_current->bounding_xor_gc, color);
  +    gdk_draw_rectangle(w_current->window,
  +                       w_current->bounding_xor_gc, FALSE,
  +                       rleft   + diff_x,
  +                       rtop    + diff_y,
  +                       rright  - rleft,
  +                       rbottom - rtop);
  +
  +    return;
  +  }
  +
  +  diff_x = w_current->last_x - w_current->start_x;
  +  diff_y = w_current->last_y - w_current->start_y;
  +
  +  /*! \todo have I mentioned how temp this is? Make this general
  +   * so that all lists can be moved ...
  +   */
  +  if (o_list) {
  +    o_complex_translate2(w_current, diff_x, diff_y, o_list);
  +  } else if (s_list) {
  +    o_complex_translate_selection(w_current, diff_x, diff_y, 
  +                                  s_list);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_erasebounding(TOPLEVEL *w_current, OBJECT *o_list, SELECTION *s_list)
  +{
  +  int diff_x, diff_y;
  +  int rleft, rtop, rright, rbottom;
  +
  +  if (o_list == NULL) {
  +    /* this is an error condition */
  +    w_current->event_state = SELECT;
  +    w_current->inside_action = 0;
  +    return;
  +  }
  +
  +  if (w_current->actionfeedback_mode == OUTLINE) {
  +    return;
  +  }
  +
  +  if (o_list) {
  +    get_complex_bounds(w_current, o_list,
  +                       &rleft  ,
  +                       &rtop   ,
  +                       &rright ,
  +                       &rbottom);
  +  } else if (s_list) {
  +    get_complex_bounds_selection(w_current, s_list,
  +                                 &rleft  ,
  +                                 &rtop   ,
  +                                 &rright ,
  +                                 &rbottom);
  +  }
  +
  +  diff_x = w_current->last_x - w_current->start_x;
  +  diff_y = w_current->last_y - w_current->start_y;
  +
  +  gdk_gc_set_foreground(w_current->gc,
  +                        x_get_color(w_current->background_color) );
  +  gdk_draw_rectangle(w_current->window, w_current->gc, FALSE,
  +                     rleft   + diff_x,
  +                     rtop    + diff_y,
  +                     rright  - rleft ,
  +                     rbottom - rtop  );
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_erase_rubber(TOPLEVEL *w_current)
  +{
  +   /* return FALSE if it did not erase anything */
  + 
  +   if (!w_current->inside_action)
  +     return(FALSE);
  +
  +   switch(w_current->event_state) {
  +
  +     case(STARTDRAWBUS):
  +     case(DRAWBUS):
  +     case(BUSCONT):
  +        o_bus_eraserubber(w_current);
  +     break;
  +
  +     case(STARTDRAWNET):
  +     case(DRAWNET):
  +     case(NETCONT):
  +        o_net_eraserubber(w_current);
  +     break;
  +
  +     case(DRAWPIN):
  +     case(ENDPIN):
  +        o_pin_eraserubber(w_current);
  +     break;
  +
  +     case(DRAWLINE):
  +     case(ENDLINE):
  +        o_line_eraserubber(w_current);
  +     break;
  +
  +     case(DRAWBOX):
  +     case(ENDBOX):
  +        o_box_eraserubber(w_current);
  +     break;
  +
  +     case(DRAWPICTURE):
  +     case(ENDPICTURE):
  +#ifndef HAS_GTK12
  +        o_picture_eraserubber(w_current);
  +#endif
  +     break;
  +
  +     case(DRAWCIRCLE):
  +     case(ENDCIRCLE):
  +        o_circle_eraserubber(w_current);
  +     break;
  +
  +     case(DRAWARC):
  +     case(ENDARC):
  +        o_arc_eraserubber(w_current);
  +     break;
  +
  +     default:
  + 	return(FALSE);
  +     break;
  +   }
  +
  +   return(TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function is neccesary to make jumps between event_states.
  + *  If we are inside an drawing action that created something on the dc, 
  + *  e.g. if we are drawing a box and then jump to line drawing without 
  + *  leaving the box drawing mode, there will remain some rubberbands on the
  + *  screen. 
  + *  Usually a intermediate select state would clean (redraw) the screen.
  + */
  +int o_redraw_cleanstates(TOPLEVEL *w_current)
  +{
  +  /* returns FALSE if the function was'nt nessecary */
  +  if (w_current->inside_action == 0) {
  +    return FALSE;
  +  }
  +
  +  switch (w_current->event_state) {
  +    /* all states with something on the dc */
  +    case(COPY): 
  +    case(MCOPY): 
  +    case(DRAWBUS): 
  +    case(DRAWCOMP): 
  +    case(DRAWNET):   
  +    case(ENDARC): 
  +    case(ENDATTRIB):
  +    case(ENDBOX): 
  +    case(ENDCIRCLE): 
  +    case(ENDCOMP): 
  +    case(ENDCOPY):
  +    case(ENDMCOPY): 
  +    case(ENDLINE): 
  +    case(ENDMOVE): 
  +    case(ENDPASTE): 
  +    case(ENDPIN): 
  +    case(ENDTEXT): 
  +    case(GRIPS): 
  +    case(MOVE): 
  +    case(NETCONT): 
  +    case(ZOOMBOXEND): 
  +      /* reset all rubberband variables and touch the select state */
  +      w_current->start_x = w_current->second_x = w_current->last_x = -1;
  +      w_current->start_y = w_current->second_y = w_current->last_y = -1;
  +      w_current->loc_x = w_current->loc_y = w_current->distance = -1;
  +      i_set_state(w_current, SELECT);
  +
  +      /* from i_callback_cancel() */
  +      o_redraw_all(w_current);
  +      /* it is possible to cancel in the middle of a complex place
  +       * so lets be sure to clean up the complex_place_head
  +       * structure and also clean up the attrib_place_head.
  +       * remember these don't remove the head structure */
  +      o_list_delete_rest(w_current,
  +			 w_current->page_current->complex_place_head);
  +      o_list_delete_rest(w_current,
  +			 w_current->page_current->attrib_place_head);
  + 
  +      /* also free internal current_attribute */
  +      o_attrib_free_current(w_current);     
  +      w_current->inside_action = 0;
  +      return TRUE;
  +
  +    /* all remaining states without dc changes */
  +    case(NONE): 
  +    case(SELECT): 
  +    case(DRAWLINE): 
  +    case(DRAWBOX): 
  +    case(DRAWCIRCLE): 
  +    case(ZOOM):
  +    case(PAN): 
  +    case(BUSCONT): 
  +    case(DRAWARC): 
  +    case(DRAWATTRIB): 
  +    case(DRAWPICTURE): 
  +    case(DRAWPIN): 
  +    case(DRAWTEXT): 
  +    case(ENDMIRROR): 
  +    case(ENDPICTURE):
  +    case(ENDROTATEP): 
  +    case(ENDROUTENET): 
  +    case(MOUSEPAN): 
  +    case(SBOX): 
  +    case(STARTCOPY): 
  +    case(STARTMCOPY):
  +    case(STARTDRAWBUS): 
  +    case(STARTDRAWNET): 
  +    case(STARTMOVE): 
  +    case(STARTPAN): 
  +    case(STARTPASTE): 
  +    case(STARTROUTENET): 
  +    case(STARTSELECT): 
  +    case(TEXTENTRY): 
  +    case(ZOOMBOXSTART): 
  +      return FALSE;
  +  }
  +
  +  return FALSE;
  +}
  
  
  
  1.21      +1065 -701 eda/geda/gaf/gschem/src/o_box.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_box.c
  ===================================================================
  RCS file: o_box.c
  diff -N o_box.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_box.c	14 Jul 2006 02:23:54 -0000	1.21
  @@ -0,0 +1,1152 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +#include <math.h>
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* Kazu on July 16, 1999 - Added these macros to simplify the code */
  +#define GET_BOX_WIDTH(w)			\
  +	abs((w)->last_x - (w)->start_x)
  +#define GET_BOX_HEIGHT(w)			\
  +	abs((w)->last_y - (w)->start_y)
  +#define GET_BOX_LEFT(w)				\
  +	min((w)->start_x, (w)->last_x);
  +#define GET_BOX_TOP(w)				\
  +	min((w)->start_y, (w)->last_y);
  +
  +/*! \brief Draw a box on the screen.
  + *  \par Function Description
  + *  This function is used to draw a box on screen. The box is described in
  + *  the OBJECT which is referred by <B>o_current</B>. The box is displayed
  + *  according to the current state, described in the TOPLEVEL object
  + *  pointed by <B>w_current</B>.
  + *
  + *  It first checks if the OBJECT pointed is valid or not. If not it
  + *  returns and do not output anything. That should never happen though.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  BOX OBJECT to draw.
  + */
  +void o_box_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int wleft, wright, wtop, wbottom; /* world bounds */
  +  int line_width, length, space;
  +  int fill_width, angle1, pitch1, angle2, pitch2;
  +  GdkCapStyle box_end;
  +  GdkColor *color;
  +  void (*draw_func)() = NULL;
  +  void (*fill_func)();
  +
  +  if (o_current->box == NULL) {
  +    return;
  +  }
  +
  +  /*
  +   * The function now recalculates the OBJECT as a box. It involves
  +   * calculating every single dimensions according to the zoom factor
  +   * the position, @dots{}. It also recalculates the bounding box of the
  +   * object and check whether this object is visible or not. If not there
  +   * is no reason to draw it!
  +   */
  +  o_box_recalc(w_current, o_current);
  +
  +	/* Get read to check for visibility of this line by using it's
  +	 * bounding box */
  +  world_get_box_bounds(w_current, o_current->box,
  +                       &wleft, &wtop, &wright, &wbottom);
  +	
  +  if (!visible(w_current, wleft, wtop, wright, wbottom)) {
  +    return;
  +  }
  +	
  +#if DEBUG
  +  printf("drawing box\n\n");
  +	
  +  printf("drawing box: %d %d %d %d\n",
  +         o_current->box->screen_upper_x,
  +         o_current->box->screen_upper_y,
  +         o_current->box->screen_upper_x +
  +         abs(o_current->box->screen_lower_x -
  +             o_current->box->screen_upper_x),
  +         o_current->box->screen_upper_y +
  +         abs(o_current->box->screen_lower_y -
  +             o_current->box->screen_upper_y));
  +#endif
  +
  +  /*
  +   * The drawing of the box is divided in two steps : first step is to
  +   * draw the outline, the second is to draw the filling pattern inside
  +   * (if any). Finally the function takes care of the grips.
  +   */
  +  if (w_current->override_color != -1 ) {  /* Override */
  +    color = x_get_color(w_current->override_color);
  +  } else {
  +    color = x_get_color(o_current->color);
  +  }
  +
  +  /*
  +   * The values describing the line type are extracted from the <B>o_current</B>
  +   * pointed structure. These are the width of the line, the field called
  +   * length and the field called space and the desired end type for the line.
  +   *
  +   * Depending on the type of the line that has to be used to draw the box
  +   * the appropriate function is called. Values of space and length are
  +   * adapted to the type of line. The possible functions are the following :
  +   * #o_box_draw_solid(), #o_box_draw_dotted(), #o_box_draw_dashed() and
  +   * #o_box_draw_phantom().
  +   *
  +   * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it
  +   * lead to an endless loop in function called after. If such a case is
  +   * encountered the box is drawn as a solid box independently of its
  +   * initial type.
  +   */
  +  if(o_current->screen_line_width > 0) {
  +    line_width = o_current->screen_line_width;
  +  } else {
  +    line_width = 1;
  +  }
  +
  +  switch(o_current->line_end) {
  +    case END_NONE:   box_end = GDK_CAP_BUTT;       break;
  +    case END_SQUARE: box_end = GDK_CAP_PROJECTING; break;
  +    case END_ROUND:  box_end = GDK_CAP_ROUND;      break;
  +    default: fprintf(stderr, _("Unknown end for box (%d)\n"), o_current->line_end);
  +    box_end = GDK_CAP_BUTT;
  +    break;
  +  }
  +	
  +  length = o_current->screen_line_length;
  +  space = o_current->screen_line_space;
  +	
  +  switch(o_current->line_type) {
  +    case TYPE_SOLID:
  +      length = -1;
  +      space = -1;
  +      draw_func = (void *) o_box_draw_solid;
  +      break;
  +
  +    case TYPE_DOTTED:
  +      length = -1; /* ..._draw_dotted only space is used */
  +      draw_func = (void *) o_box_draw_dotted;
  +      break;
  +
  +    case TYPE_DASHED:
  +      draw_func = (void *) o_box_draw_dashed;
  +      break;
  +
  +    case TYPE_CENTER:
  +      draw_func = (void *) o_box_draw_center;
  +      break;
  +
  +    case TYPE_PHANTOM:
  +      draw_func = (void *) o_box_draw_phantom;
  +      break;
  +
  +    case TYPE_ERASE:
  +      break;
  +			
  +    default:
  +      length = -1;
  +      space = -1;
  +      line_width = 0; /* just to be careful */
  +      draw_func = (void *) o_box_draw_solid;
  +      fprintf(stderr, _("Unknown type for box !\n"));
  +      break;
  +  }
  +
  +  if((length == 0) || (space == 0))
  +  draw_func = (void *) o_box_draw_solid;
  +	
  +  (*draw_func)(w_current->window, w_current->gc, color, box_end,
  +               FALSE,
  +               o_current->box->screen_upper_x,
  +               o_current->box->screen_upper_y,
  +               abs(o_current->box->screen_lower_x -
  +                   o_current->box->screen_upper_x),
  +               abs(o_current->box->screen_lower_y -
  +                   o_current->box->screen_upper_y),
  +               line_width, length, space);
  +  (*draw_func)(w_current->backingstore, w_current->gc, color, box_end,
  +               FALSE,
  +               o_current->box->screen_upper_x,
  +               o_current->box->screen_upper_y,
  +               abs(o_current->box->screen_lower_x -
  +                   o_current->box->screen_upper_x),
  +               abs(o_current->box->screen_lower_y -
  +                   o_current->box->screen_upper_y),
  +               line_width, length, space);
  +
  +  /*
  +   * The values needed for the fill operation are taken from the
  +   * <B>o_current</B> pointed OBJECT. It include the type of fill required,
  +   * the width of the lines (if the fill use line) and angles and pitchs
  +   * for hatch based filling.
  +   *
  +   * Once again the width of the line is important as if it is equal to
  +   * 0 it may not be displayed. That is definetely not what we are looking for.
  +   *
  +   * Depending on the type of fill that has to be used inside the box the
  +   * appropriate function is called. Values of <B>angle1</B>,
  +   * <B>angle2</B>, <B>pitch1</B> and <B>pitch2</B> are adapted to the type of
  +   * filling. The possible functions are the following :
  +   * #o_box_fill_hollow(), #o_box_fill_fill(), #o_box_fill_mesh() and
  +   * #o_box_fill_hatch().
  +   *
  +   * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as
  +   * it lead to an endless loop in function called after. It happens when
  +   * the zoom factor is too small for two lines separated by the pitch
  +   * to be distinct. If such a case is encountered the circle is filled
  +   * hollow (e.q. not filled).
  +   */
  +  if(o_current->screen_fill_width > 0) {
  +    fill_width = o_current->screen_fill_width;
  +  } else {
  +    fill_width = 1;
  +  }
  +	
  +  angle1 = o_current->fill_angle1;
  +  pitch1 = o_current->screen_fill_pitch1;
  +  angle2 = o_current->fill_angle2;
  +  pitch2 = o_current->screen_fill_pitch2;
  +	
  +  switch(o_current->fill_type) {
  +    case FILLING_HOLLOW:
  +      angle1 = -1; angle2 = -1;
  +      pitch1 = 1; pitch2 = 1;
  +      /* this function is empty ! however if it do not use it we have to add
  +       * a test before the call. Simply putting a return here instead is not
  +       * possible as it would prevent any hollow box from having its grips
  +       * drawn
  +       */
  +      fill_func = (void *) o_box_fill_hollow;
  +      break;
  +		
  +    case FILLING_FILL:
  +      angle1 = -1; angle2 = -1;
  +      pitch1 = 1; pitch2 = 1;
  +      fill_func = (void *) o_box_fill_fill;
  +      break;
  +			
  +    case FILLING_MESH:
  +      fill_func = (void *) o_box_fill_mesh;
  +      break;
  +
  +    case FILLING_HATCH:
  +      angle2 = -1;
  +      pitch2 = 1;
  +      fill_func = (void *) o_box_fill_hatch;
  +      break;
  +			
  +    case FILLING_VOID:
  +    default:
  +      angle1 = -1; angle2 = -1;
  +      pitch1 = 1; pitch2 = 1;
  +      fill_func = (void *) o_box_fill_hollow;
  +      fprintf(stderr, _("Unknown type for box (fill)!\n"));
  +  }
  +
  +  if((pitch1 <= 0) || (pitch2 <= 0)) {
  +    fill_func = (void *) o_box_fill_fill;
  +  }
  +
  +  (*fill_func)(w_current->window, w_current->gc, color,
  +               o_current->box->screen_upper_x,
  +               o_current->box->screen_upper_y,
  +               abs(o_current->box->screen_lower_x -
  +                   o_current->box->screen_upper_x),
  +               abs(o_current->box->screen_lower_y -
  +                   o_current->box->screen_upper_y),
  +               fill_width, angle1, pitch1, angle2, pitch2);
  +  (*fill_func)(w_current->backingstore, w_current->gc, color,
  +               o_current->box->screen_upper_x,
  +               o_current->box->screen_upper_y,
  +               abs(o_current->box->screen_lower_x -
  +                   o_current->box->screen_upper_x),
  +               abs(o_current->box->screen_lower_y -
  +                   o_current->box->screen_upper_y),
  +               fill_width, angle1, pitch1, angle2, pitch2);
  +
  +  if ((o_current->draw_grips == TRUE) && (w_current->draw_grips == TRUE)) {
  +    /* pb20011003 - modified to use the new o_box_[draw|erase]_grips() */
  +    if (!o_current->selected) {
  +      /* object is no more selected, erase the grips */
  +      o_current->draw_grips = FALSE;
  +      o_box_erase_grips(w_current, o_current);
  +    } else {
  +      /* object is selected, draw the grips on the box */
  +      o_box_draw_grips(w_current, o_current);
  +    } 
  +  }
  +}
  +
  +/*! \brief Draw a box with a solid line type.
  + *  \par Function Description
  + *  This function draws a box with a solid line type. The length and space
  + *  parameters are not used by this function.
  + *
  + *  The function uses the functions previously defined in #o_line.c. It is
  + *  called four times for each of the side of the box. Therefore note that
  + *  the cap parameter is significant here even if it is a box (i.e. a closed
  + *  shape).
  + *
  + *  The box is defined in the same way as it is in GDK : one point and
  + *  the width and height of the box.
  + *
  + *  The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
  + *  <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box line color.
  + *  \param [in] cap         Box line end cap type (unused).
  + *  \param [in] filled      (unused)
  + *  \param [in] x           Box upper x.
  + *  \param [in] y           Box upper y.
  + *  \param [in] width       Box width.
  + *  \param [in] height      Box height
  + *  \param [in] line_width  Width of line to draw box.
  + *  \param [in] length      (unused)
  + *  \param [in] space       (unused)
  + */
  +void o_box_draw_solid(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +		      GdkCapStyle cap, gint filled, gint x, gint y, gint width,
  +		      gint height, gint line_width, gint length, gint space)
  +{
  +  o_line_draw_solid(w, gc, color, cap,
  +                    x, y, x + width, y, line_width, length, space);
  +  o_line_draw_solid(w, gc, color, cap,
  +                    x + width, y, x + width, y + height, line_width, 
  +                    length, space);
  +  o_line_draw_solid(w, gc, color, cap,
  +                    x + width, y + height, x, y + height, line_width, 
  +                    length, space);
  +  o_line_draw_solid(w, gc, color, cap,
  +                    x, y + height, x, y, line_width, length, space);
  +}
  +
  +/*! \brief Draw a box with a dotted line type.
  + *  \par Function Description
  + *  This function draws a box with a dotted line type. The parameter
  + *  <B>space</B> represents the distance between two of the dots. The
  + *  parameter <B>length</B> is unused. The diameter of the dots is given by
  + *  the width of the line given by <B>width</B>.
  + *
  + *  The function uses the functions previously defined in #o_line.c. It is
  + *  called four times for each of the side of the box.
  + *
  + *  The box is defined in the same way as it is in GDK : one point and
  + *  the width and height of the box.
  + *
  + *  The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
  + *  <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
  + *
  + *  A negative or null value for <B>space</B> leads to an endless loop
  + *  in #o_line_draw_dotted().
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box line color.
  + *  \param [in] cap         Box line end cap type (unused).
  + *  \param [in] filled      (unused)
  + *  \param [in] x           Box upper x.
  + *  \param [in] y           Box upper y.
  + *  \param [in] width       Box width.
  + *  \param [in] height      Box height
  + *  \param [in] line_width  Width of line to draw box.
  + *  \param [in] length      (unused)
  + *  \param [in] space       Space in pixels between dots.
  + */
  +
  +void o_box_draw_dotted(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +		       GdkCapStyle cap, gint filled, gint x, gint y,
  +		       gint width, gint height, gint line_width,
  +		       gint length, gint space)
  +{
  +  o_line_draw_dotted(w, gc, color, cap,
  +                     x, y, x + width, y, line_width, length, space);
  +  o_line_draw_dotted(w, gc, color, cap,
  +                     x + width, y, x + width, y + height, 
  +                     line_width, length, space);
  +  o_line_draw_dotted(w, gc, color, cap,
  +                     x + width, y + height, x, y+height, 
  +                     line_width, length, space);
  +  o_line_draw_dotted(w, gc, color, cap,
  +                     x, y + height, x, y, line_width, length, space);
  +	
  +}
  +
  +/*! \brief Draw a box with a dashed line type.
  + *  \par Function Description
  + *  This function draws a box with a dashed line type. The parameter
  + *  <B>space</B> represents the distance between two of the dash. The
  + *  parameter <B>length</B> represents the length of a dash.
  + *
  + *  The function uses the functions previously defined in #o_line.c. It is
  + *  called four times for each of the side of the box.
  + *
  + *  The box is defined in the same way as it is in GDK : one point and
  + *  the width and height of the box.
  + *
  + *  The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
  + *  <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
  + *
  + *  A negative or null value for length or space leads to an endless
  + *  loop in #o_line_draw_dashed().
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box line color.
  + *  \param [in] cap         Box line end cap type (unused).
  + *  \param [in] filled      (unused)
  + *  \param [in] x           Box upper x.
  + *  \param [in] y           Box upper y.
  + *  \param [in] width       Box width.
  + *  \param [in] height      Box height
  + *  \param [in] line_width  Width of line to draw box.
  + *  \param [in] length      Length of dash in pixels.
  + *  \param [in] space       Space between dashes in pixels.
  + */
  +void o_box_draw_dashed(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +		       GdkCapStyle cap, gint filled, gint x, gint y,
  +		       gint width, gint height, gint line_width,
  +		       gint length, gint space)
  +{
  +  o_line_draw_dashed(w, gc, color, cap,
  +                     x, y, x + width, y, line_width, length, space);
  +  o_line_draw_dashed(w, gc, color, cap,
  +                     x + width, y, x + width, y + height, 
  +                     line_width, length, space);
  +  o_line_draw_dashed(w, gc, color, cap,
  +                     x + width, y + height, x, y+height, 
  +                     line_width, length, space);
  +  o_line_draw_dashed(w, gc, color, cap,
  +                     x, y + height, x, y, line_width, length, space);
  +}
  +
  +/*! \brief Draw a box with a centered line type.
  + *  \par Function Description
  + *  This function draws a box with a centered line type. The parameter
  + *  <B>space</B> represents the distance between a dot and the dash. The
  + *  parameter <B>length</B> represents the length of a dash.
  + *
  + *  The function uses the functions previously defined in #o_line.c. It is
  + *  called four times for each of the side of the box.
  + *
  + *  The box is defined in the same way as it is in GDK : one point and the
  + *  width and height of the box.
  + *
  + *  The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
  + *  <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
  + *
  + *  A negative or null value for length or space leads to an endless
  + *  loop in #o_line_draw_center().
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box line color.
  + *  \param [in] cap         Box line end cap type (unused).
  + *  \param [in] filled      (unused)
  + *  \param [in] x           Box upper x.
  + *  \param [in] y           Box upper y.
  + *  \param [in] width       Box width.
  + *  \param [in] height      Box height
  + *  \param [in] line_width  Width of line to draw box.
  + *  \param [in] length      (unused)?
  + *  \param [in] space       (unused)?
  + */
  +void o_box_draw_center(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +		       GdkCapStyle cap, gint filled, gint x, gint y,
  +		       gint width, gint height, gint line_width,
  +		       gint length, gint space)
  +{
  +  o_line_draw_center(w, gc, color, cap,
  +                     x, y, x + width, y, line_width, length, space);
  +  o_line_draw_center(w, gc, color, cap,
  +                     x + width, y, x + width, y + height, 
  +                     line_width, length, space);
  +  o_line_draw_center(w, gc, color, cap,
  +                     x + width, y + height, x, y+height, 
  +                     line_width, length, space);
  +  o_line_draw_center(w, gc, color, cap,
  +                     x, y + height, x, y, line_width, length, space);
  +}
  +
  +/*! \brief Draw a box with a phantom line type.
  + *  \par Function Description
  + *  This function draws a box with a phantom line type. The parameter
  + *  <B>space</B> represents the distance between a dot and a dash.
  + *  The parameter <B>length</B> represents the length of a dash.
  + *
  + *  The function uses the functions previously defined in #o_line.c.
  + *  It is called four times for each of the side of the box.
  + *
  + *  The box is defined in the same way as it is in GDK : one point and the
  + *  width and height of the box.
  + *
  + *  The unit of <B>x</B>, <B>y</B>, <B>width</B>, <B>height</B>,
  + *  <B>line_width</B>, <B>length</B> and <B>space</B> is pixel.
  + *
  + *  A negative or null value for length or space leads to an endless loop
  + *  in #o_line_draw_phantom().
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box line color.
  + *  \param [in] cap         Box line end cap type (unused).
  + *  \param [in] filled      (unused)
  + *  \param [in] x           Box upper x.
  + *  \param [in] y           Box upper y.
  + *  \param [in] width       Box width.
  + *  \param [in] height      Box height
  + *  \param [in] line_width  Width of line to draw box.
  + *  \param [in] length      (unused)?
  + *  \param [in] space       (unused)?
  + */
  +void o_box_draw_phantom(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +			GdkCapStyle cap, gint filled, gint x, gint y,
  +			gint width, gint height, gint line_width,
  +			gint length, gint space)
  +{
  +  o_line_draw_phantom(w, gc, color, cap,
  +                      x, y, x + width, y, line_width, length, space);
  +  o_line_draw_phantom(w, gc, color, cap,
  +                      x + width, y, x + width, y+height, 
  +                      line_width, length, space);
  +  o_line_draw_phantom(w, gc, color, cap,
  +                      x + width, y + height, x, y+height, 
  +                      line_width, length, space);
  +  o_line_draw_phantom(w, gc, color, cap,
  +                      x, y + height, x, y, line_width, length, space);
  +}
  +
  +/*! \brief Placeholder filling function.
  + *  \par Function Description
  + *  This function does nothing. It has the same prototype as all the
  + *  filling functions. It prevent from making a difference between filling
  + *  in function #o_box_draw().
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box fill color. 
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] fill_width  BOX pattern fill width.
  + *  \param [in] angle1      1st angle for pattern.
  + *  \param [in] pitch1      1st pitch for pattern.
  + *  \param [in] angle2      2nd angle for pattern.
  + *  \param [in] pitch2      2nd pitch for pattern.
  + */
  +void o_box_fill_hollow(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +		       gint x, gint y,
  +		       gint width, gint height,
  +		       gint fill_width,
  +		       gint angle1, gint pitch1,
  +		       gint angle2, gint pitch2)
  +{
  +  
  +}
  +
  +/*! \brief Fill inside of box with a solid pattern.
  + *  \par Function Description
  + *  This function fills the inside of the box with a solid pattern.
  + *  Parameters <B>angle1</B>, <B>pitch1</B> and <B>angle2</B>,
  + *  <B>pitch2</B> and <B>fill_width</B> are unused here but kept for compatibility
  + *  with other box filling functions.
  + *
  + *  The box is defined in the same way as it is in GDK : one point and
  + *  the width and height of the box.
  + *
  + *  All parameters are given in pixel.
  + *
  + *  The solid fill is done with the #gdk_draw_rectangle() function and
  + *  its parameters <B>filled</B> set. The box is filled with the color
  + *  <B>color</B> given as a parameter to the function.
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box fill color. 
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] fill_width  BOX pattern fill width.
  + *  \param [in] angle1      (unused)
  + *  \param [in] pitch1      (unused)
  + *  \param [in] angle2      (unused)
  + *  \param [in] pitch2      (unused)
  + */
  +void o_box_fill_fill(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +		     gint x, gint y,
  +		     gint width, gint height,
  +		     gint fill_width,
  +		     gint angle1, gint pitch1, gint angle2, gint pitch2)
  +{
  +  gdk_gc_set_foreground(gc, color);
  +  gdk_gc_set_line_attributes(gc, 1, GDK_LINE_SOLID,
  +                             GDK_CAP_BUTT, GDK_JOIN_MITER);
  +
  +  gdk_draw_rectangle(w, gc, TRUE, x, y, width, height);
  +	
  +}
  +
  +/*! \brief Fill inside of box with single line pattern.
  + *  \par Function Description
  + *  This function fills the inside of the box with a pattern made of lines.
  + *  The lines are drawn inside the box with an angle <B>angle1</B> from the
  + *  horizontal. The distance between two of these lines is given by
  + *  <B>pitch1</B> and their width by <B>fill_width</B>.
  + *  Parameters <B>angle2</B> and <B>pitch2</B> are unused here but kept for
  + *  compatbility with other box filling functions.
  + *
  + *  The box is defined in the same way as it is in GDK : one point and the
  + *  width and height of the box.
  + *
  + *  All parameters are given in pixel.
  + *
  + *  Negative or null values for <B>pitch1</B> are not allowed as it leads to
  + *  an endless loop.
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box fill color. 
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] fill_width  BOX pattern fill width.
  + *  \param [in] angle1      1st angle for pattern.
  + *  \param [in] pitch1      1st pitch for pattern.
  + *  \param [in] angle2      (unused)
  + *  \param [in] pitch2      (unused)
  + */
  +void o_box_fill_hatch(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +		      gint x, gint y,
  +		      gint width, gint height,
  +		      gint fill_width,
  +		      gint angle1, gint pitch1, gint angle2, gint pitch2)
  +{
  +  int x3, y3, x4, y4;
  +  double cos_a_, sin_a_;
  +  double x0, y0, r;
  +  double x1, y1, x2, y2;
  +  double amin, amax, a[4], min1, min2, max1, max2;
  +
  +  gdk_gc_set_line_attributes(gc, fill_width, GDK_LINE_SOLID,
  +                             GDK_CAP_BUTT, GDK_JOIN_MITER);
  +
  +  /*
  +   * The function uses a matrix. Its elements are obtained from the sinus
  +   * and the cosinus of the angle <B>angle1</B>. It represents the rotation
  +   * matrix that when applied to a point, rotate it of <B>angle1</B>.
  +   */
  +  cos_a_ = cos(((double) angle1) * M_PI/180);
  +  sin_a_ = sin(((double) angle1) * M_PI/180);
  +
  +  /*
  +   * The function considers the smallest circle around the box. Its radius
  +   * is given by the following relation. Its center is given by the point
  +   * a the middle of the box horizontally and vertically (intersection of
  +   * its two diagonals.
  +   */
  +  r = sqrt((double) (pow(width, 2) + pow(height, 2))) / 2;
  +
  +  /*
  +   * When drawing a line in a circle there is two intersections. With the
  +   * previously described circle, these intersections are out of the box.
  +   * They can be easily calculated, the first by resolution of an equation
  +   * and the second one by symetry in relation to the vertical axis going
  +   * through the center of the circle.
  +   *
  +   * These two points are then rotated of angle <B>angle1</B> using the matrix
  +   * previously mentionned.
  +   */
  +  y0 = 0;
  +  while(y0 < r) {
  +    x0 = pow(r, 2) - pow(y0, 2);
  +    x0 = sqrt(x0);
  +    
  +    x1 = (x0*cos_a_ - y0*sin_a_);
  +    y1 = (x0*sin_a_ + y0*cos_a_);
  +    x2 = ((-x0)*cos_a_ - y0*sin_a_);
  +    y2 = ((-x0)*sin_a_ + y0*cos_a_);
  +    
  +    /*
  +     * It now parametrizes the segment : first intersection is given
  +     * the value of 0 and the second is given the value of 1. The four
  +     * values for each intersection of the segment and the four
  +     * sides (vertical or horizontal) of the box are given by the
  +     * following relations :
  +     */
  +    if((int) (x2 - x1) != 0) {
  +      a[0] = ((-width/2) - x1) / (x2 - x1);
  +      a[1] = ((width/2)  - x1) / (x2 - x1);
  +    } else {
  +      a[0] = 0; a[1] = 1;
  +    }
  +    
  +    if((int) (y2 - y1) != 0) {
  +      a[2] = ((-height/2) - y1) / (y2 - y1);
  +      a[3] = ((height/2)  - y1) / (y2 - y1);
  +    } else {
  +      a[2] = 0; a[3] = 1;
  +    }
  +    /*
  +     * It now has to check which of these four values are for
  +     * intersections with the sides of the box (some values may be
  +     * for intersections out of the box). This is made by a min/max
  +     * function.
  +     */
  +    if(a[0] < a[1]) {
  +      min1 = a[0]; max1 = a[1];
  +    } else {
  +      min1 = a[1]; max1 = a[0];
  +    }
  +    
  +    if(a[2] < a[3]) {
  +      min2 = a[2]; max2 = a[3];
  +    } else {
  +      min2 = a[3]; max2 = a[2];
  +    }
  +    
  +    amin = (min1 < min2) ? min2 : min1;
  +    amin = (amin < 0) ? 0 : amin;
  +    
  +    amax = (max1 < max2) ? max1 : max2;
  +    amax = (amax < 1) ? amax : 1;
  +    
  +    /*
  +     * If the segment really go through the box it draws the line.
  +     * It also take the opportunity of the symetry in the box in
  +     * relation to its center to draw the second line at the same time.
  +     *
  +     * If there is no intersection of the segment with any of the sides,
  +     * then there is no need to continue : there would be no more
  +     * segment in the box to draw.
  +     */
  +    
  +    if((amax > amin) && (amax != 1) && (amin != 0)) {
  +      /* There is intersection between the line and the box edges */
  +      x3 = (int) (x1 + amin*(x2 - x1));
  +      y3 = (int) (y1 + amin*(y2 - y1));
  +      
  +      x4 = (int) (x1 + amax*(x2 - x1));
  +      y4 = (int) (y1 + amax*(y2 - y1));
  +      
  +      gdk_draw_line(w, gc, x3 + (x + width/2),
  +		    (y + height/2) - y3, x4 + (x + width/2),
  +		    (y + height/2) - y4);
  +      
  +      gdk_draw_line(w, gc, -x3 + (x + width/2),
  +		    +y3 + (y + height/2), -x4 + (x + width/2),
  +		    +y4 + (y + height/2));
  +      
  +    } else {
  +      break;
  +    }
  +    
  +    y0 = y0 + pitch1;
  +    
  +  }
  +}
  +  
  +/*! \brief Fill inside of box with mesh pattern.
  + *  \par Function Description
  + *  This function fills the inside of the box with a pattern made of two
  + *  sets of parallel lines in two directions. The first set is drawn inside
  + *  the box with an angle <B>angle1</B> from the horizontal. The distance
  + *  between two of these lines is given by <B>pitch1</B>.
  + *  The second set is drawn inside the box with an angle <B>angle2</B> from
  + *  the horizontal. The distance between two of these lines is given
  + *  by <B>pitch2</B>.
  + *  Every lines have the same width given be <B>fill_width</B>.
  + *
  + *  This function simply makes two successive calls to the function
  + *  #o_box_fill_hatch() respectively with <B>angle1</B>, <B>pitch1</B> and
  + *  <B>angle2</B>, <B>pitch2</B> for parameters.
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Box fill color. 
  + *  \param [in] x           Upper x coordinate of BOX.
  + *  \param [in] y           Upper y coordinate of BOX.
  + *  \param [in] width       Width of BOX.
  + *  \param [in] height      Height of BOX.
  + *  \param [in] fill_width  BOX pattern fill width.
  + *  \param [in] angle1      1st angle for pattern.
  + *  \param [in] pitch1      1st pitch for pattern.
  + *  \param [in] angle2      2nd angle for pattern.
  + *  \param [in] pitch2      2nd pitch for pattern.
  + */
  +void o_box_fill_mesh(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +		     gint x, gint y,
  +		     gint width, gint height,
  +		     gint fill_width,
  +		     gint angle1, gint pitch1,
  +		     gint angle2, gint pitch2)
  +{
  +  o_box_fill_hatch(w, gc, color, x, y, width, height,
  +		   fill_width, angle1, pitch1, -1, -1);
  +  o_box_fill_hatch(w, gc, color, x, y, width, height,
  +	  	   fill_width, angle2, pitch2, -1, -1);
  +}
  +
  +
  +/*! \brief Erase a box described by OBJECT.
  + *  \par Function Description
  + *  This function erases a box, described in a <B>OBJECT</B> structure pointed
  + *  by <B>o_current</B>.
  + *
  + *  It makes a call to the function #o_box_draw() after setting the special
  + *  color. Therefore a box is drawn with background color over the previous
  + *  one.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Box OBJECT to erase.
  + */
  +void o_box_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +    w_current->override_color = w_current->background_color;
  +    o_box_draw(w_current, o_current);
  +    w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief 
  + *  \par Function Description
  + * 
  + *  \note
  + *  used in button cancel code in x_events.c
  + */
  +void o_box_eraserubber(TOPLEVEL *w_current)
  +{
  +  o_box_rubberbox_xor(w_current);
  +}
  +
  +/*! \brief Draw a box described by OBJECT with translation
  + *  \par Function Description
  + *  This function daws the box object described by <B>*o_current</B> translated
  + *  by the vector (<B>dx</B>,<B>dy</B>) with an xor-function over the current sheet.
  + *  The translation vector is in screen unit.
  + *
  + *  The box is displayed with the color of the object.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] dx         Delta x coordinate for box.
  + *  \param [in] dy         Delta y coordinate for box.
  + *  \param [in] o_current  Box OBJECT to draw.
  + */
  +void o_box_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1;
  +  int screen_x2, screen_y2;
  +  int color;
  +
  +  if (o_current->box == NULL) {
  +    return;
  +  }
  +
  +  screen_x1 = o_current->box->screen_upper_x;
  +  screen_y1 = o_current->box->screen_upper_y;
  +  screen_x2 = o_current->box->screen_lower_x;
  +  screen_y2 = o_current->box->screen_lower_y;
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  gdk_gc_set_foreground(w_current->outline_xor_gc,
  +                        x_get_darkcolor(color));
  +  gdk_draw_rectangle(w_current->window,
  +                     w_current->outline_xor_gc, FALSE,
  +                     screen_x1 + dx,
  +                     screen_y1 + dy,
  +                     abs(screen_x2 - screen_x1),
  +                     abs(screen_y2 - screen_y1));
  +}
  +
  +/*! \brief Start process to input a new box.
  + *  \par Function Description
  + *  This function starts the process to input a new box. Parameters for this
  + *  box are put into/extracted from the <B>w_current</B> toplevel structure.
  + *  <B>x</B> and <B>y</B> are current coordinates of the pointer in screen
  + *  coordinates.
  + *
  + *  The first step is to input one corner of the box. This corner is
  + *  (<B>x</B>,<B>y</B>) snapped to the grid and saved in <B>w_current->start_x</B>
  + *  and <B>w_current->start_y</B>.
  + *
  + *  The other corner will be saved in (<B>w_current->last_x</B>,
  + *  <B>w_current->last_y</B>).
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_box_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  /* init start_[x|y], last_[x|y] to describe box */
  +  w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +
  +  /* start to draw the box */
  +  o_box_rubberbox_xor(w_current);
  +  
  +}
  +
  +/*! \brief End the input of a box.
  + *  \par Function Description
  + *  This function ends the input of the second corner of a box.
  + *  The (<B>x</B>,<B>y</B>) point is set to be this second corner. The box is
  + *  then defined by (<B>w_current->start_x</B>,<B>w_current->start_y</B> and
  + *  (<B>w_current->last_x</B>,<B>w_current->last_y</B> that is a snapped version
  + *  of (<B>x</B>,<B>y</B>).
  + *  <B>x</B> and <B>y</B> are in screen unit.
  + *
  + *  The temporary box is erased ; a new box object is allocated, initialized
  + *  and linked to the object list ; The object is finally drawn on the
  + *  current sheet.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_box_end(TOPLEVEL *w_current, int x, int y)
  +{
  +  int x1, y1;
  +  int x2, y2;
  +  int box_width, box_height;
  +  int box_left, box_top;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  /* get the last coords of the pointer */
  +  w_current->last_x = fix_x(w_current, x);
  +  w_current->last_y = fix_y(w_current, y);
  +
  +  /* erase the temporary box */
  +  o_box_rubberbox_xor(w_current);
  +  
  +  box_width  = GET_BOX_WIDTH (w_current);
  +  box_height = GET_BOX_HEIGHT(w_current);
  +  box_left   = GET_BOX_LEFT  (w_current);
  +  box_top    = GET_BOX_TOP   (w_current);
  +
  +  /* boxes with null width and height are not allowed */
  +  if ((box_width == 0) && (box_height == 0)) {
  +	  /* cancel the object creation */
  +	  w_current->start_x = (-1);
  +	  w_current->start_y = (-1);
  +	  w_current->last_x  = (-1);
  +	  w_current->last_y  = (-1);
  +	  return;
  +  }
  +
  +  /* calculate the world coords of the upper left and lower right corners */
  +  SCREENtoWORLD(w_current, box_left, box_top, &x1, &y1);
  +  SCREENtoWORLD(w_current,
  +                box_left + box_width, box_top  + box_height, &x2, &y2);
  +  x1 = snap_grid(w_current, x1);
  +  y1 = snap_grid(w_current, y1);
  +  x2 = snap_grid(w_current, x2);
  +  y2 = snap_grid(w_current, y2);
  +
  +  /* create the object */
  +  w_current->page_current->object_tail = 
  +  o_box_add(w_current,
  +            w_current->page_current->object_tail,
  +            OBJ_BOX, w_current->graphic_color, x1, y1, x2, y2);
  +
  +  /* draw it */
  +  o_redraw_single(w_current, w_current->page_current->object_tail);
  +  
  +#if DEBUG
  +  printf("coords: %d %d %d %d\n", x1, y2, x2, y2);
  +#endif
  +	
  +  w_current->start_x = (-1);
  +  w_current->start_y = (-1);
  +  w_current->last_x  = (-1);
  +  w_current->last_y  = (-1);
  +	
  +  w_current->page_current->CHANGED = 1;
  +
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \brief Draw temporary box while dragging edge.
  + *  \par Function Description
  + *  This function is used to draw the box while dragging one of its edge or
  + *  angle. It erases the previous temporary box drawn before, and draws a new
  + *  updated one. <B>x</B> and <B>y</B> are the new position of the mobile point,
  + *  ie the mouse.
  + *
  + *  The old values are inside the <B>w_current</B> pointed structure. Old width,
  + *  height and left and top values are recomputed by the corresponding macros.
  + *  The box is then erased by performing a xor-drawing over the box.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_box_rubberbox(TOPLEVEL *w_current, int x, int y)
  +{
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  /* erase the previous temporary box */
  +  o_box_rubberbox_xor(w_current);
  +
  +  /*
  +   * New values are fixed according to the <B>x</B> and <B>y</B> parameters.
  +   * These are saved in <B>w_current</B> pointed structure as new temporary
  +   * values. The new box is then drawn.
  +   */
  +
  +  /* update the coords of the corner */
  +  w_current->last_x = fix_x(w_current, x);
  +  w_current->last_y = fix_y(w_current, y);
  +
  +  /* draw the new temporary box */
  +  o_box_rubberbox_xor(w_current);
  +  
  +}
  +
  +/*! \brief Draw box from TOPLEVEL object.
  + *  \par Function Description
  + *  This function draws the box from the variables in the toplevel
  + *  structure <B>*w_current</B>.
  + *  One corner of the box is at (<B>w_current->start_x</B>,
  + *  <B>w_current->start_y</B>) and the second corner is at
  + *  (<B>w_current->last_x</B>,<B>w_current->last_y</B>.
  + *
  + *  The box is drawn with a xor-function over the current sheet with the
  + *  selection color.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + */
  +void o_box_rubberbox_xor(TOPLEVEL *w_current)
  +{
  +	int box_width, box_height, box_left, box_top;
  +
  +	/* get the width/height and the upper left corner of the box */
  +	box_width  = GET_BOX_WIDTH (w_current);
  +	box_height = GET_BOX_HEIGHT(w_current);
  +	box_left   = GET_BOX_LEFT  (w_current);
  +	box_top    = GET_BOX_TOP   (w_current);
  +
  +	/* draw the box from the previous variables */
  +	gdk_gc_set_foreground(w_current->xor_gc, 
  +			      x_get_darkcolor(w_current->select_color));
  +	gdk_gc_set_line_attributes(w_current->xor_gc, 0, 
  +				   GDK_LINE_SOLID, GDK_CAP_NOT_LAST, 
  +				   GDK_JOIN_MITER);
  +	gdk_draw_rectangle(w_current->window, w_current->xor_gc,
  +			   FALSE, box_left, box_top, box_width, box_height);
  +	
  +}
  +
  +/*! \brief Draw grip marks on box.
  + *  \par Function Description
  + *  This function draws four grips on the corners of the box described
  + *  by <B>*o_current</B>.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Box OBJECT to draw grip points on.
  + *
  + *  \par Author's note
  + *  p20011003 - modified the prototype : removed parameter 'GdkWindow *w'
  + */
  +void o_box_draw_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  if (w_current->draw_grips == FALSE)
  +	  return;
  +
  +  /* grip on upper left corner (whichone = BOX_UPPER_LEFT) */
  +  o_grips_draw(w_current,
  +			   o_current->box->screen_upper_x,
  +			   o_current->box->screen_upper_y);
  +
  +  /* grip on upper right corner (whichone = BOX_UPPER_RIGHT) */
  +  o_grips_draw(w_current,
  +			   o_current->box->screen_lower_x,
  +			   o_current->box->screen_upper_y);
  +  
  +  /* grip on lower left corner (whichone = BOX_LOWER_LEFT) */
  +  o_grips_draw(w_current,
  +			   o_current->box->screen_upper_x,
  +			   o_current->box->screen_lower_y);
  +
  +  /* grip on lower right corner (whichone = BOX_LOWER_RIGHT) */
  +  o_grips_draw(w_current,
  +			   o_current->box->screen_lower_x,
  +			   o_current->box->screen_lower_y);
  +
  +}
  +
  +/*! \brief Erase grip marks from box.
  + *  \par Function Description
  + *  This function erases the four grips displayed on the <B>*o_current</B>
  + *  box object. These grips are on each of the corner.
  + * 
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Box OBJECT to erase grip marks from.
  + */
  +void o_box_erase_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  if (w_current->draw_grips == FALSE)
  +	  return;
  +
  +  /* grip on upper left corner (whichone = BOX_UPPER_LEFT) */
  +  o_grips_erase(w_current,
  +				o_current->box->screen_upper_x,
  +				o_current->box->screen_upper_y);
  +
  +  /* grip on upper right corner (whichone = BOX_UPPER_RIGHT) */
  +  o_grips_erase(w_current,
  +				o_current->box->screen_lower_x,
  +				o_current->box->screen_upper_y);
  +  
  +  /* grip on lower left corner (whichone = BOX_LOWER_LEFT) */
  +  o_grips_erase(w_current,
  +				o_current->box->screen_upper_x,
  +				o_current->box->screen_lower_y);
  +
  +  /* grip on lower right corner (whichone = BOX_LOWER_RIGHT) */
  +  o_grips_erase(w_current,
  +				o_current->box->screen_lower_x,
  +				o_current->box->screen_lower_y);
  +  
  +}
  
  
  
  1.7       +226 -197  eda/geda/gaf/gschem/src/o_buffer.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_buffer.c
  ===================================================================
  RCS file: o_buffer.c
  diff -N o_buffer.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_buffer.c	14 Jul 2006 02:23:54 -0000	1.7
  @@ -0,0 +1,288 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_buffer_copy(TOPLEVEL *w_current, int buf_num)
  +{
  +  SELECTION *s_current = NULL;
  +
  +  if (buf_num < 0 || buf_num > MAX_BUFFERS) {
  +    fprintf(stderr, _("Got an invalid buffer_number [o_buffer_copy]\n"));
  +    return;
  +  }
  +
  +  s_current = w_current->page_current->selection2_head->next;
  +
  +  if (object_buffer[buf_num] == NULL) {
  +    object_buffer[buf_num] = s_basic_init_object("buffer0_head");
  +    object_buffer[buf_num]->type = OBJ_HEAD;
  +  } else {
  +    o_list_delete_rest(w_current, object_buffer[buf_num]);
  +    object_buffer[buf_num]->next = NULL;
  +  }
  +
  +  w_current->ADDING_SEL = 1;
  +  o_list_copy_all_selection2(w_current, s_current, 
  +                             object_buffer[buf_num], SELECTION_FLAG);
  +  w_current->ADDING_SEL = 0;
  +        
  +#if DEBUG
  +  o_current = object_buffer[buf_num];
  +  while(o_current != NULL) {
  +    printf("- %s\n", o_current->name);
  +    o_current = o_current->next;
  +  }
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_buffer_cut(TOPLEVEL *w_current, int buf_num)
  +{
  +  SELECTION *s_current = NULL;
  +
  +  if (buf_num < 0 || buf_num > MAX_BUFFERS) {
  +    fprintf(stderr, _("Got an invalid buffer_number [o_buffer_cut]\n"));
  +    return;
  +  }
  +
  +  s_current = w_current->page_current->selection2_head->next;
  +
  +  if (object_buffer[buf_num] == NULL) {
  +    object_buffer[buf_num] = s_basic_init_object("buffer0_head");
  +    object_buffer[buf_num]->type = OBJ_HEAD;
  +  } else {
  +    o_list_delete_rest(w_current, object_buffer[buf_num]);
  +    object_buffer[buf_num]->next = NULL;
  +  }
  +        
  +  w_current->ADDING_SEL = 1;
  +  o_list_copy_all_selection2(w_current, s_current, 
  +                             object_buffer[buf_num], SELECTION_FLAG);
  +  w_current->ADDING_SEL = 0;
  +  o_delete(w_current);
  +
  +#if DEBUG
  +  o_current = object_buffer[buf_num];
  +  while(o_current != NULL) {
  +    printf("- %s\n", o_current->name);
  +    o_current = o_current->next;
  +  }
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_buffer_paste_start(TOPLEVEL *w_current, int screen_x, int screen_y, 
  +			  int buf_num)
  +{
  +  int rleft, rtop, rbottom, rright;
  +  int x, y;
  +
  +  if (buf_num < 0 || buf_num > MAX_BUFFERS) {
  +    fprintf(stderr, _("Got an invalid buffer_number [o_buffer_paste_start]\n"));
  +    return;
  +  }
  +
  +  world_get_complex_bounds(w_current, object_buffer[buf_num], 
  +                           &rleft, &rtop, 
  +                           &rright, &rbottom);
  +
  +  /* snap x and y to the grid, pointed out by Martin Benes */
  +  x = snap_grid(w_current, rleft);
  +  y = snap_grid(w_current, rtop);
  +
  +  w_current->ADDING_SEL = 1;
  +  o_complex_world_translate(w_current, -x, -y, object_buffer[buf_num]);
  +  w_current->ADDING_SEL = 0;
  +
  +  /* now translate selection to current position */
  +  SCREENtoWORLD(w_current, screen_x, screen_y, &x, &y);
  +  w_current->ADDING_SEL = 1;
  +  o_complex_world_translate(w_current, x, y, object_buffer[buf_num]);
  +  w_current->ADDING_SEL = 0;
  +
  +  w_current->last_x = w_current->start_x = fix_x(w_current, screen_x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, screen_y);
  +  w_current->event_state = ENDPASTE;
  +
  +  /* store the buffer number for future use */
  +  w_current->buffer_number = buf_num;
  +
  +  o_drawbounding(w_current,
  +                 object_buffer[buf_num]->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_buffer_paste_end(TOPLEVEL *w_current, int screen_x, int screen_y, 
  +			int buf_num)
  +{
  +  int w_x, w_y;
  +  int w_start_x, w_start_y;
  +  int w_diff_x, w_diff_y;
  +  OBJECT *o_current;
  +  OBJECT *o_saved;
  +  SELECTION *temp_list;
  +  PAGE *p_current;
  +  GList *connected_objects = NULL;
  +
  +  if (buf_num < 0 || buf_num > MAX_BUFFERS) {
  +    fprintf(stderr, _("Got an invalid buffer_number [o_buffer_paste_end]\n"));
  +    return;
  +  }
  +
  +  /* erase old image */
  +  o_drawbounding(w_current,
  +                 object_buffer[buf_num]->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), FALSE);
  +
  +  /* get the location where we ended */
  +  SCREENtoWORLD(w_current, screen_x, screen_y, &w_x, &w_y);
  +  SCREENtoWORLD(w_current, w_current->start_x, w_current->start_y, 
  +                &w_start_x, &w_start_y);
  +
  +#if DEBUG 
  +  printf("%d %d\n", w_x - w_start_x,  w_y - w_start_y);
  +#endif
  +  /* calc and translate objects to their final position */
  +  w_diff_x = w_x - w_start_x;
  +  w_diff_y = w_y - w_start_y;
  +  w_current->ADDING_SEL = 1;
  +  o_complex_world_translate(w_current, w_diff_x, w_diff_y, 
  +                            object_buffer[buf_num]);
  +  w_current->ADDING_SEL = 0;
  +
  +  o_current = object_buffer[buf_num]->next;
  +  p_current = w_current->page_current;
  +
  +  o_saved = p_current->object_tail;	
  +  o_list_copy_all(w_current, o_current, p_current->object_tail, 
  +                  NORMAL_FLAG);
  +
  +  p_current->object_tail = return_tail(p_current->object_head);
  +  o_current = o_saved->next;
  +  temp_list = o_selection_new_head();
  +
  +  /* now add new objects to the selection list */
  +  while (o_current != NULL) {
  +    o_selection_add(temp_list, o_current);
  +    s_conn_update_object(w_current, o_current);
  +    if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
  +      connected_objects = s_conn_return_complex_others(
  +                                                       connected_objects,
  +                                                       o_current);
  +    } else {
  +      connected_objects = s_conn_return_others(connected_objects,
  +                                               o_current);
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +  o_cue_redraw_all(w_current, o_saved->next);
  +  o_cue_undraw_list(w_current, connected_objects);
  +  o_cue_draw_list(w_current, connected_objects);
  +  g_list_free(connected_objects);
  +  connected_objects = NULL;
  +    
  +  o_select_run_hooks(w_current, NULL, 2); 
  +  o_selection_remove_most(w_current,
  +                          w_current->page_current->selection2_head);
  +  o_selection_destroy_head(w_current->page_current->selection2_head);
  +  w_current->page_current->selection2_head = temp_list;
  +  w_current->page_current->selection2_tail = o_selection_return_tail(
  +                                                                     temp_list);
  +
  +  w_current->page_current->CHANGED = 1;
  +  o_redraw(w_current, o_saved->next); /* only redraw new objects */
  +  o_undo_savestate(w_current, UNDO_ALL);
  +  i_update_menus(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_buffer_paste_rubberpaste(TOPLEVEL *w_current, int buf_num)
  +{
  +  o_drawbounding(w_current,
  +                 object_buffer[buf_num]->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), FALSE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_buffer_init(void)
  +{
  +	int i;
  +
  +	for (i = 0 ; i < MAX_BUFFERS; i++) {
  +		object_buffer[i] = NULL;
  +	}
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_buffer_free(TOPLEVEL *w_current)
  +{
  +  int i;
  +
  +  for (i = 0 ; i < MAX_BUFFERS; i++) {
  +    if (object_buffer[i]) {
  +      s_delete_list_fromstart(w_current, 
  +                              object_buffer[i]);
  +      object_buffer[i] = NULL;
  +    }
  +  }
  +}
  
  
  
  1.19      +510 -468  eda/geda/gaf/gschem/src/o_bus.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_bus.c
  ===================================================================
  RCS file: o_bus.c
  diff -N o_bus.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_bus.c	14 Jul 2006 02:23:54 -0000	1.19
  @@ -0,0 +1,619 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_bus_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int size;
  +  int x1, y1, x2, y2; /* screen coords */
  +
  +  if (o_current == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  o_bus_recalc(w_current, o_current);
  +
  +  /* reuse line's routine */
  +  if (!o_line_visible(w_current, o_current->line, &x1, &y1, &x2, &y2)) {
  +    return;
  +  }
  +
  +#if DEBUG
  +  printf("drawing bus\n\n");
  +#endif
  +
  +  if (w_current->bus_style == THICK ) {
  +    size = SCREENabs(w_current, BUS_WIDTH);
  +
  +    if (size < 0)
  +      size=0;
  +
  +    gdk_gc_set_line_attributes(w_current->gc, size, GDK_LINE_SOLID,
  +                               GDK_CAP_BUTT,
  +                               GDK_CAP_NOT_LAST);
  +  }
  +
  +  if (w_current->override_color != -1 ) {
  +    gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(w_current->override_color));
  +    gdk_draw_line(w_current->window, w_current->gc,
  +                  x1, y1, x2, y2);
  +    gdk_draw_line(w_current->backingstore, w_current->gc,
  +                  x1, y1, x2, y2);
  +  } else {
  +    gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(o_current->color));
  +    gdk_draw_line(w_current->window, w_current->gc,
  +                  x1, y1, x2, y2);
  +    gdk_draw_line(w_current->backingstore, w_current->gc,
  +                  x1, y1, x2, y2);
  +  }
  +
  +  /* yes zero is right for the width -> use hardware lines */
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->gc, 0, GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +#if DEBUG
  +  printf("drawing bus\n");
  +#endif
  +
  +  if (o_current->draw_grips && w_current->draw_grips == TRUE) {	
  +    /* pb20011109 - modified to use the new o_line_[draw|erase]_grips() */
  +    /*              reuse the line functions */
  +    if (!o_current->selected) {
  +      /* object is no more selected, erase the grips */
  +      o_current->draw_grips = FALSE;
  +      o_line_erase_grips(w_current, o_current);
  +    } else {
  +      /* object is selected, draw the grips */
  +      o_line_draw_grips(w_current, o_current);
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_bus_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  w_current->override_color = w_current->background_color;
  +  o_bus_draw(w_current, o_current);
  +  w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_bus_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  +{
  +  int size;
  +  int color;
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  gdk_gc_set_foreground(w_current->outline_xor_gc,
  +			x_get_darkcolor(color));
  +
  +  if (w_current->bus_style == THICK ) {
  +    size = SCREENabs(w_current, BUS_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->outline_xor_gc, size+1,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_draw_line(w_current->window, w_current->outline_xor_gc,
  +                o_current->line->screen_x[0]+dx,
  +                o_current->line->screen_y[0]+dy,
  +                o_current->line->screen_x[1]+dx,
  +                o_current->line->screen_y[1]+dy);
  +
  +  /* backing store ? not approriate here */
  +
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->outline_xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_bus_draw_xor_single(TOPLEVEL *w_current,
  +			   int dx, int dy, int whichone, OBJECT *o_current)
  +{
  +  int color;
  +  int dx1= - 1, dy1 = - 1, dx2 = -1, dy2 = -1;
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  gdk_gc_set_foreground(w_current->outline_xor_gc,
  +			x_get_darkcolor(color));
  +
  +#if 0
  +  if (w_current->bus_style == THICK ) {
  +    size = SCREENabs(w_current, BUS_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->outline_xor_gc, size+1,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +#endif
  +
  +  if (whichone == 0) {
  +    dx1 = dx;
  +    dy1 = dy;
  +    dx2 = 0;
  +    dy2 = 0;
  +  } else if (whichone == 1) {
  +    dx2 = dx;
  +    dy2 = dy;
  +    dx1 = 0;
  +    dy1 = 0;
  +  } else {
  +    fprintf(stderr, _("Got an invalid which one in o_bus_draw_xor_single\n"));
  +  }
  +
  +  gdk_draw_line(w_current->window, w_current->outline_xor_gc,
  +                o_current->line->screen_x[0]+dx1,
  +                o_current->line->screen_y[0]+dy1,
  +                o_current->line->screen_x[1]+dx2,
  +                o_current->line->screen_y[1]+dy2);
  +
  +  /* backing store ? not approriate here */
  +
  +#if 0
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->outline_xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_bus_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  int size;
  +
  +  w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +
  +#if 0 /* not ready for prime time use, this is the snap any point #if 0 */
  +  int distance1;
  +  int distance2;
  +  OBJECT *real;
  +  OBJECT *o_current;
  +  int temp_x, temp_y;
  +  o_current = o_CONN_search_closest_range(w_current,
  +                                          w_current->page_current->object_head,
  +                                          w_current->start_x, w_current->start_y,
  +                                          &temp_x, &temp_y, 200, NULL, NULL);
  +
  +  if (o_current) {
  +    w_current->last_x = w_current->start_x = temp_x;
  +    w_current->last_y = w_current->start_y = temp_y;
  +  } else {
  +    w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +    w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +  }
  +#endif
  +
  +#if 0 /* not ready for prime time use */
  +  /* new bus extenstion stuff */
  +  o_current = w_current->page_current->selection_head->next;
  +  if (o_current != NULL && w_current->event_state == STARTDRAWNET) {
  +    if (o_current->type == OBJ_BUS) {
  +      if (o_current->line) {
  +
  +        real = o_list_sear( /* ch */
  +                           w_current->page_current->object_head,
  +                           o_current);
  +
  +        if (!real) {
  +          fprintf(stderr, _("selected a nonexistant object!\n"));
  +          exit(-1);
  +        }
  +        distance1 = dist(
  +                         real->line->screen_x[0],
  +                         real->line->screen_y[0],
  +                         w_current->start_x, w_current->start_y);
  +
  +        distance2 = dist(
  +                         real->line->screen_x[1],
  +                         real->line->screen_y[1],
  +                         w_current->start_x, w_current->start_y);
  +
  +        printf("%d %d\n", distance1, distance2);
  +
  +        if (distance1 < distance2) {
  +          w_current->last_x = w_current->start_x =
  +            real->line->screen_x[0];
  +          w_current->last_y = w_current->start_y =
  +            real->line->screen_y[0];
  +        } else {
  +          w_current->last_x = w_current->start_x =
  +            real->line->screen_x[1];
  +          w_current->last_y = w_current->start_y =
  +            real->line->screen_y[1];
  +        }
  +      }
  +    } else if (o_current->type == OBJ_COMPLEX ||
  +               o_current->type == OBJ_PLACEHOLDER) {
  +      real = o_list_sear( /* ch */
  +                         w_current->page_current->object_head,
  +                         o_current);
  +
  +      if (!real) {
  +        fprintf(stderr, _("selected a nonexistant object!\n"));
  +        exit(-1);
  +      }
  +
  +      o_CONN_search_closest(w_current, o_current->complex,
  +                            w_current->start_x, w_current->start_y,
  +                            &temp_x, &temp_y, NULL);
  +      w_current->last_x = w_current->start_x = temp_x;
  +      w_current->last_y = w_current->start_y = temp_y;
  +    }
  +
  +  }
  +#endif
  +
  +  if (w_current->bus_style == THICK ) {
  +    size = SCREENabs(w_current, BUS_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->xor_gc, w_current->start_x, w_current->start_y, w_current->last_x, w_current->last_y);
  +
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_bus_end(TOPLEVEL *w_current, int x, int y)
  +{
  +  int x1, y1;
  +  int x2, y2;
  +  int color;
  +  int size;
  +  GList *other_objects = NULL;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return(FALSE);
  +  }
  +
  +  if (w_current->override_bus_color == -1) {
  +    color = w_current->bus_color;
  +  } else {
  +    color = w_current->override_bus_color;
  +  }
  +
  +  size = SCREENabs(w_current, BUS_WIDTH);
  +
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->xor_gc, 
  +		w_current->start_x, w_current->start_y, 
  +		w_current->last_x, w_current->last_y);
  +
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +    gdk_gc_set_line_attributes(w_current->gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  /* don't allow zero length bus */
  +  /* this ends the bus drawing behavior we want this? hack */
  +  if ( (w_current->start_x == w_current->last_x) &&
  +       (w_current->start_y == w_current->last_y) ) {
  +         w_current->start_x = (-1);
  +         w_current->start_y = (-1);
  +         w_current->last_x = (-1);
  +         w_current->last_y = (-1);
  +         w_current->inside_action=0;
  +	 i_set_state(w_current, STARTDRAWBUS);
  +         o_bus_eraserubber(w_current);
  +         return(FALSE);
  +       }
  +
  +#if 0 /* not ready for prime time use */
  +  /* second attempt at all snapping */
  +  o_current = o_CONN_search_closest_range(w_current,
  +                                          w_current->page_current->object_head,
  +                                          w_current->last_x, w_current->last_y,
  +                                          &temp_x, &temp_y, 200, NULL, NULL);
  +
  +  if (o_current) {
  +    w_current->last_x = temp_x;
  +    w_current->last_y = temp_y;
  +  } else {
  +    w_current->last_x = fix_x(w_current, x);
  +    w_current->last_y = fix_y(w_current, y);
  +  }
  +#endif
  +
  +  gdk_gc_set_foreground(w_current->gc,
  +			x_get_color(color));
  +  gdk_draw_line(w_current->window, w_current->gc, w_current->start_x, w_current->start_y, w_current->last_x, w_current->last_y);
  +  gdk_draw_line(w_current->backingstore, w_current->gc, w_current->start_x, w_current->start_y, w_current->last_x, w_current->last_y);
  +
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  SCREENtoWORLD(w_current, w_current->start_x, w_current->start_y, &x1, &y1);
  +  SCREENtoWORLD(w_current, w_current->last_x, w_current->last_y, &x2, &y2);
  +  x1 = snap_grid(w_current, x1);
  +  y1 = snap_grid(w_current, y1);
  +  x2 = snap_grid(w_current, x2);
  +  y2 = snap_grid(w_current, y2);
  +
  +  w_current->save_x = w_current->last_x;
  +  w_current->save_y = w_current->last_y;
  +
  +  w_current->page_current->object_tail =
  +  o_bus_add(w_current,
  +            w_current->page_current->object_tail,
  +            OBJ_BUS,
  +            color,
  +            x1, y1, x2, y2, 0);
  +
  +  /* conn stuff */
  +  other_objects = s_conn_return_others(other_objects,
  +                                       w_current->page_current->
  +                                       object_tail);
  +  o_cue_undraw_list(w_current, other_objects);
  +  o_cue_draw_list(w_current, other_objects);
  +  g_list_free(other_objects);
  +  o_cue_draw_single(w_current, w_current->page_current->object_tail);
  +
  +  /* this needs to be bus specific... might not be needed */
  +#if 0
  +  o_bus_conn_erase(w_current, w_current->page_current->object_tail);
  +  o_bus_conn_draw(w_current, w_current->page_current->object_tail);
  +  o_conn_draw_objects(w_current, w_current->page_current->object_tail);
  +
  +  if (w_current->net_consolidate == TRUE) {
  +    o_bus_consolidate_segments(w_current, 
  +                               w_current->page_current->object_tail);
  +  }
  +#endif
  +
  +  w_current->page_current->CHANGED=1;
  +  w_current->start_x = w_current->save_x;
  +  w_current->start_y = w_current->save_y;
  +  o_undo_savestate(w_current, UNDO_ALL);
  +  return(TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_bus_rubberbus(TOPLEVEL *w_current, int x, int y)
  +{
  +  int diff_x, diff_y;
  +  int size;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  if (w_current->bus_style == THICK ) {
  +    size = SCREENabs(w_current, BUS_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc, 
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->xor_gc, w_current->start_x, w_current->start_y, w_current->last_x, w_current->last_y);
  +
  +  /* going into ortho mode (control key not pressed) */
  +  /* erase non-ortho line */
  +
  +  /* going into non-ortho mode (control key pressed) */
  +  /* erase ortho line */
  +
  +  w_current->last_x = fix_x(w_current, x);
  +  w_current->last_y = fix_y(w_current, y);
  +
  +  /* If you press the control key then you can draw non-ortho bus */
  +  if (!w_current->CONTROLKEY) {
  +    diff_x = abs(w_current->last_x - w_current->start_x);
  +    diff_y = abs(w_current->last_y - w_current->start_y);
  +
  +    if (diff_x >= diff_y) {
  +      w_current->last_y = w_current->start_y;
  +    } else {
  +      w_current->last_x = w_current->start_x;
  +    }
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->xor_gc, w_current->start_x, w_current->start_y, w_current->last_x, w_current->last_y);
  +
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  used in button cancel code in x_events.c
  + */
  +void o_bus_eraserubber(TOPLEVEL *w_current)
  +{
  +  int size;
  +
  +  if (w_current->bus_style == THICK ) {
  +    size = SCREENabs(w_current, BUS_WIDTH);
  +
  +    if (size < 0)
  +      size=0;
  +
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +#if 0
  +  gdk_gc_set_foreground(w_current->gc,
  +			x_get_color(w_current->background_color) );
  +#endif
  +
  +  gdk_draw_line(w_current->window, w_current->xor_gc, w_current->start_x, w_current->start_y, w_current->last_x, w_current->last_y);
  +
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  used in button cancel code in x_events.c
  + */
  +void o_bus_xorrubber(TOPLEVEL *w_current)
  +{
  +  int size;
  +
  +  if (w_current->bus_style == THICK ) {
  +
  +    size = SCREENabs(w_current, BUS_WIDTH);
  +
  +    if (size < 0)
  +      size=0;
  +
  +    gdk_gc_set_line_attributes(w_current->gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->gc,
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->gc, w_current->start_x, w_current->start_y, w_current->last_x, w_current->last_y);
  +
  +  if (w_current->bus_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  
  
  
  1.19      +697 -507  eda/geda/gaf/gschem/src/o_circle.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_circle.c
  ===================================================================
  RCS file: o_circle.c
  diff -N o_circle.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_circle.c	14 Jul 2006 02:23:54 -0000	1.19
  @@ -0,0 +1,835 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* Kazu on July 16, 1999 - Added these macros to simplify the code */
  +#define GET_BOX_WIDTH(w)			\
  +	abs((w)->last_x - (w)->start_x)
  +#define GET_BOX_HEIGHT(w)			\
  +	abs((w)->last_y - (w)->start_y)
  +
  +/*! \brief Draw a circle on the screen.
  + *  \par Function Description
  + *  This function is used to draw a circle on screen. The circle is described
  + *  by the OBJECT which is referred by <B>o_current</B>. The display is done 
  + *  according to the current state, given by the TOPLEVEL object pointed by 
  + *  <B>w_current</B>.
  + *
  + *  It first checks if the OBJECT pointed is valid or not. If not it
  + *  returns and do not output anything. That should never happen though.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Circle OBJECT to draw.
  + */
  +void o_circle_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int wleft, wright, wtop, wbottom; /* world bounds */
  +  int radius;
  +  int circle_width, length, space;
  +  int fill_width, angle1, pitch1, angle2, pitch2;
  +  GdkCapStyle circle_end;
  +  GdkColor *color;
  +  void (*draw_func)() = NULL;
  +  void (*fill_func)();
  +
  +  if (o_current->circle == NULL) {
  +    return;
  +  }
  +	
  +  /*
  +   * The function now recalculates the OBJECT as a circle. It involves
  +   * calculating every single dimensions according to the zoom factor,
  +   * the position, @dots{}.
  +   * It also recalculates the bounding box of the object and check whether
  +   * this object is visible or not. If not there is no reason to draw it !
  +   */
  +  o_circle_recalc(w_current, o_current);
  +	
  +  /*
  +   * Get read to check for visibility of this line by using it's
  +   * bounding box
  +   */
  +  world_get_circle_bounds(w_current, o_current->circle,
  +                          &wleft, &wtop, &wright, &wbottom);
  +	
  +  if (!visible(w_current, wleft, wtop, wright, wbottom)) {
  +    return;
  +  }
  +	
  +#if DEBUG
  +  printf("drawing circle\n\n");
  +#endif
  +	
  +  /*
  +   * The draw of the circle is divided in two steps : first step is to draw
  +   * the outline, the second is to draw the filling pattern inside (if any).
  +   *
  +   * Finally the function takes care of the grips.
  +   */
  +  if (w_current->override_color != -1 ) {
  +    color = x_get_color(w_current->override_color);
  +  } else {
  +    color = x_get_color(o_current->color);
  +  }
  +
  +  radius = o_current->circle->screen_radius;
  +
  +  /*
  +   * The values describing the line type are extracted from the
  +   * <B>o_current</B> pointed structure. These are the width of the line, the
  +   * field called length and the field called space and the desired end type
  +   * for the line.
  +   *
  +   * Depending on the type of the line that has to be used to draw the circle
  +   * the appropriate function is called. Values of space and length are
  +   * adapted to the type of line. The possible functions are the following :
  +   * #o_arc_draw_solid(), #o_arc_draw_dotted(), #o_arc_draw_dashed() and
  +   * #o_arc_draw_phantom(). Therefore it reuses the code from arc primitive.
  +   *
  +   * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it lead
  +   * to an endless loop in function called after. If such a case is encountered
  +   * the circle is drawn as a solid circle independently of its initial type.
  +   */
  +  if(o_current->screen_line_width > 0) {
  +    circle_width = o_current->screen_line_width;
  +  } else {
  +    circle_width = 1;
  +  }
  +
  +  length = o_current->screen_line_length;
  +  space = o_current->screen_line_space;
  +
  +  switch(o_current->line_end) {
  +    case END_NONE:   circle_end = GDK_CAP_BUTT;       break;
  +    case END_SQUARE: circle_end = GDK_CAP_PROJECTING; break;
  +    case END_ROUND:  circle_end = GDK_CAP_ROUND;      break;
  +    default: fprintf(stderr, _("Unknown end for circle\n"));
  +      circle_end = GDK_CAP_BUTT;
  +      break;
  +  }
  +
  +  switch(o_current->line_type) {
  +    case TYPE_SOLID:
  +    length = -1;
  +    space = -1;
  +    draw_func = (void *) o_arc_draw_solid;
  +    break;
  +			
  +    case TYPE_DOTTED:
  +    length = -1; /* ..._draw_dotted only space used */
  +    draw_func = (void *) o_arc_draw_dotted;
  +    break;
  +			
  +    case TYPE_DASHED:
  +    draw_func = (void *) o_arc_draw_dashed;
  +    break;
  +			
  +    case TYPE_CENTER:
  +    draw_func = (void *) o_arc_draw_center;
  +    break;
  +			
  +    case TYPE_PHANTOM:
  +    draw_func = (void *) o_arc_draw_phantom;
  +    break;
  +			
  +    case TYPE_ERASE:
  +    break;
  +			
  +    default:
  +    length = -1;
  +    space = -1;
  +    circle_width = 0; /* just to be careful */
  +    fprintf(stderr, _("Unknown type for circle!\n"));
  +    draw_func = (void *) o_arc_draw_solid;			
  +    break;
  +  }
  +
  +  if((length == 0) || (space == 0))
  +  draw_func = (void *) o_arc_draw_solid;
  +	
  +  (*draw_func)(w_current->window, w_current->gc, color,
  +               circle_end,
  +               o_current->circle->screen_x,
  +               o_current->circle->screen_y,
  +               radius,
  +               0, FULL_CIRCLE / 64,
  +               circle_width, length, space);
  +  (*draw_func)(w_current->backingstore, w_current->gc, color,
  +               circle_end,
  +               o_current->circle->screen_x,
  +               o_current->circle->screen_y,
  +               radius,
  +               0, FULL_CIRCLE / 64,
  +               circle_width, length, space);
  +
  +  /*
  +   * The values needed for the fill operation are taken from the
  +   * <B>o_current</B> pointed OBJECT. It include the type of fill required, the
  +   * width of the lines (if the fill use line) and angles and pitchs for hatch
  +   * based filling.
  +   *
  +   * Once again the width of the line is important as if it is equal to 0 it
  +   * may not be displayed. That is definetely not what we are looking for.
  +   *
  +   * Depending on the type of fill that has to be used inside the circle the
  +   * right function is called. Values of <B>angle1</B>, <B>angle2</B>,
  +   * <B>pitch1</B> and <B>pitch2</B> are adapted to the type of filling. The
  +   * possible functions are the following : #o_circle_fill_hollow(),
  +   * #o_circle_fill_fill(), #o_circle_fill_mesh() and #o_circle_fill_hatch().
  +   *
  +   * The combination <B>pitch1</B> <= 0 and <B>pitch2</B> <= 0 is avoided as it
  +   * lead to an endless loop in function called after. It happens when the
  +   * zoom factor is too small for two lines separated by the pitch to be
  +   * distinct. If such a case is encountered the circle is filled hollow
  +   * (e.q. not filled).
  +   */
  +  if(o_current->screen_fill_width > 0) {
  +    fill_width = o_current->screen_fill_width;
  +  } else {
  +    fill_width = 1;
  +  }
  +	
  +  angle1 = o_current->fill_angle1;
  +  pitch1 = o_current->screen_fill_pitch1;
  +  angle2 = o_current->fill_angle2;
  +  pitch2 = o_current->screen_fill_pitch2;
  +	
  +  switch(o_current->fill_type) {
  +    case FILLING_HOLLOW:
  +      angle1 = -1; angle2 = -1;
  +      pitch1 = 1; pitch2 = 1;
  +      /*
  +       * this function is empty ! however if it do not use it we have to add
  +       * a test before the call. Simply putting a return here instead is not
  +       * possible as it would prevent any hollow circle from having its grips
  +       */
  +      fill_func = (void *) o_circle_fill_hollow;
  +      break;
  +		
  +    case FILLING_FILL:
  +      angle1 = -1; angle2 = -1;
  +      pitch1 = 1; pitch2 = 1;
  +      fill_func = (void *) o_circle_fill_fill;
  +      break;
  +			
  +    case FILLING_MESH:
  +      fill_func = (void *) o_circle_fill_mesh;
  +      break;
  +
  +    case FILLING_HATCH:
  +      angle2 = -1;
  +      pitch2 = 1;
  +      fill_func = (void *) o_circle_fill_hatch;
  +      break;
  +			
  +    case FILLING_VOID:
  +    default:
  +      angle1 = -1; angle2 = -1;
  +      pitch1 = 1; pitch2 = 1;
  +      fill_func = (void *) o_circle_fill_hollow;			
  +      fprintf(stderr, _("Unknown type for circle (fill)!\n"));
  +  }
  +
  +  if((pitch1 <= 0) || (pitch2 <= 0)) {
  +    fill_func = (void *) o_circle_fill_fill;
  +  }
  +
  +  (*fill_func)(w_current->window, w_current->gc, color,
  +               o_current->circle->screen_x,
  +               o_current->circle->screen_y,
  +               radius,
  +               fill_width, angle1, pitch1, angle2, pitch2);
  +  (*fill_func)(w_current->backingstore, w_current->gc, color,
  +               o_current->circle->screen_x,
  +               o_current->circle->screen_y,
  +               radius,
  +               fill_width, angle1, pitch1, angle2, pitch2);
  +
  +#if DEBUG
  +  printf("drawing circle\n");
  +#endif
  +
  +  if (o_current->draw_grips && w_current->draw_grips == TRUE) {	
  +    
  +    /* pb20011010 - modified to use the new o_circle_[draw|erase]_grips() */
  +    if (!o_current->selected) {
  +      /* object is no more selected, erase the grips */
  +      o_current->draw_grips = FALSE;
  +      o_circle_erase_grips(w_current, o_current);
  +    } else {
  +      /* object is selected, draw the grips */
  +      o_circle_draw_grips(w_current, o_current);
  +    }
  +  }
  +}
  +
  +/*! \brief Placeholder filling function.
  + *  \par Function Description
  + *  This function does nothing. It has the same prototype as all the filling
  + *  functions. It prevent from making a difference between filling in function
  + *  #o_circle_draw().
  + *
  + *  The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
  + *  for <B>angle1</B> and <B>angle2</B> is degree.
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] x           Center x coordinate of Circle.
  + *  \param [in] y           Center y coordinate of Circle.
  + *  \param [in] radius      Radius of Circle.
  + *  \param [in] width       Circle pattern fill width.
  + *  \param [in] angle1      1st angle for pattern.
  + *  \param [in] pitch1      1st pitch for pattern.
  + *  \param [in] angle2      2nd angle for pattern.
  + *  \param [in] pitch2      2nd pitch for pattern.
  + */
  +void o_circle_fill_hollow(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +			  gint x, gint y, gint radius,
  +			  gint width,
  +			  gint angle1, gint pitch1, gint angle2, gint pitch2)
  +{
  +  
  +}
  +
  +/*! \brief Fill inside of circle with a solid pattern.
  + *  \par Function Description
  + *  This function fills the inside of the circle with a solid pattern.
  + *  Parameters <B>angle1</B>, <B>pitch1</B> and <B>angle2</B>, <B>pitch2</B>
  + *  and <B>width</B> are unused here but kept for compatibility with other
  + *  circle filling functions.
  + *
  + *  The circle is described by the coordinates of its center and its radius.
  + *  Please not that it is not the way GDK take it. Translation is made
  + *  afterward.
  + *
  + *  The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
  + *  for <B>angle1</B> and <B>angle2</B> is degree.
  + *
  + *  The solid fill is done with the #gdk_draw_arc() function and its
  + *  parameters <B>filled</B> set. The circle is filled with the color
  + *  <B>color</B> given as a parameter to the function.
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] x           Center x coordinate of Circle.
  + *  \param [in] y           Center y coordinate of Circle.
  + *  \param [in] radius      Radius of Circle.
  + *  \param [in] width       (unused)
  + *  \param [in] angle1      (unused)
  + *  \param [in] pitch1      (unused)
  + *  \param [in] angle2      (unused)
  + *  \param [in] pitch2      (unused)
  + */
  +void o_circle_fill_fill(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +			gint x, gint y, gint radius,
  +			gint width,
  +			gint angle1, gint pitch1, gint angle2, gint pitch2)
  +{
  +  gdk_gc_set_foreground(gc, color);
  +  gdk_gc_set_line_attributes(gc, 1, GDK_LINE_SOLID,
  +                             GDK_CAP_BUTT, GDK_JOIN_MITER);
  +
  +  gdk_draw_arc(w, gc,
  +               TRUE, x-radius, y-radius, 2*radius, 2*radius, 0, FULL_CIRCLE);
  +
  +}
  +
  +/*! \brief Fill inside of circle with single line pattern.
  + *  \par Function Description
  + *  This function fills the inside of the circle with a pattern made of lines.
  + *  The lines are drawn inside the circle with an angle <B>angle1</B> from the
  + *  horizontal. The distance between two of these lines is given by
  + *  <B>pitch1</B> and their width by <B>width</B>.
  + *  Parameters <B>angle2</B>, <B>pitch2</B> are unused here but kept for
  + *  compatibility with other circle filling functions.
  + *
  + *  The circle is described by the coordinates of its center and its radius.
  + *  Please not that it is not the way GDK take it. Translation is made
  + *  afterward. 
  + *
  + *  The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
  + *  for <B>angle1</B> and <B>angle2</B> is degree.
  + *
  + *  The only attribute of line here is its width from the parameter <B>width</B>.
  + *
  + *  Negative or null values for <B>pitch1</B> are not allowed as it leads to
  + *  an endless loop.
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] x           Center x coordinate of Circle.
  + *  \param [in] y           Center y coordinate of Circle.
  + *  \param [in] radius      Radius of Circle.
  + *  \param [in] width       Circle pattern fill width.
  + *  \param [in] angle1      1st angle for pattern.
  + *  \param [in] pitch1      1st pitch for pattern.
  + *  \param [in] angle2      (unused)
  + *  \param [in] pitch2      (unused)
  + */
  +void o_circle_fill_hatch(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +			 gint x, gint y, gint radius,
  +			 gint width,
  +			 gint angle1, gint pitch1, gint angle2, gint pitch2)
  +{
  +  double x0, y0, x1, y1, x2, y2;
  +  double cos_a_, sin_a_;
  +
  +  gdk_gc_set_line_attributes(gc, width, GDK_LINE_SOLID,
  +                             GDK_CAP_BUTT, GDK_JOIN_MITER);
  +
  +  /*
  +   * The function use a matrix. Its elements are obtained from the sinus and
  +   * cosinus of the angle <B>angle1</B>. It represent the rotation matrix that
  +   * when applied to a point, rotate it of <B>angle1</B>.
  +   */
  +  cos_a_ = cos(((double) angle1) * M_PI/180);
  +  sin_a_ = sin(((double) angle1) * M_PI/180);
  +
  +  /*
  +   * When drawing a line in a circle there is two intersections. It looks for
  +   * the coordinates of one of these points when the line is horizontal.
  +   * The second one can be easily obtained by symmetry in relation to the
  +   * vertical axis going through the centre of the circle.
  +   *
  +   * These two points are then rotated of angle <B>angle1</B> using the
  +   * elements of the rotation matrix previously computed.
  +   *
  +   * The corresponding line can be drawn providing that the coordinates
  +   * are rounded.
  +   *
  +   * These operations are repeated for every horizontal line that can fit
  +   * in the upper half of the circle (using and incrementing the variable
  +   * <B>y0</B>).
  +   */
  +  y0 = 0;
  +  while(y0 < (double) radius) {
  +    x0 = pow((double) radius, 2) - pow(y0, 2);
  +    x0 = sqrt(x0);
  +
  +    x1 = (x0*cos_a_ - y0*sin_a_) + x;
  +    y1 = y - (x0*sin_a_ + y0*cos_a_);
  +    x2 = ((-x0)*cos_a_ - y0*sin_a_) + x;
  +    y2 = y - ((-x0)*sin_a_ + y0*cos_a_);
  +		
  +    gdk_draw_line(w, gc,
  +                  (int) x1, (int) y1, (int) x2, (int) y2);
  +        
  +    /*
  +     * The function use the symetry in relation to the centre of the circle.
  +     * It avoid repetitive computation for the second half of the surface
  +     * of the circle.
  +     */
  +    x1 = (x0*cos_a_ - (-y0)*sin_a_) + x;
  +    y1 = y- (x0*sin_a_ + (-y0)*cos_a_);
  +    x2 = ((-x0)*cos_a_ - (-y0)*sin_a_) + x;
  +    y2 = y- ((-x0)*sin_a_ + (-y0)*cos_a_);
  +    
  +    gdk_draw_line(w, gc, (int) x1, (int) y1, (int) x2, (int) y2);
  +    
  +    y0 = y0 + pitch1;
  +  }
  +}
  +
  +/*! \brief Fill inside of circle with mesh pattern.
  + *  \par Function Description
  + *  This function fills the inside of the circle with a pattern made of set
  + *  of parallel lines in two directions. The first set is drawn inside the
  + *  circle with an angle <B>angle1</B> from the horizontal. The distance between
  + *  two of these lines is given by <B>pitch1</B>.
  + *  The second set is drawn inside the circle with an angle <B>angle2</B> from
  + *  the horizontal. The distance between two of these lines is given by
  + *  <B>pitch2</B>.
  + *  Every lines have the same width given by <B>width</B>.
  + *
  + *  The unit for <B>width</B>, <B>pitch1</B> and <B>pitch2</B> is pixel and unit
  + *  for <B>angle1</B> and <B>angle2</B> is degree.
  + *
  + *  This function simply makes two successive calls to the function
  + *  #o_circle_fill_hatch() respectively with <B>angle1</B>, <B>pitch1</B> and
  + *  <B>angle2</B>, <B>pitch2</B> for parameters.
  + *
  + *  \param [in] w           GdkDrawable to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] x           Center x coordinate of Circle.
  + *  \param [in] y           Center y coordinate of Circle.
  + *  \param [in] radius      Radius of Circle.
  + *  \param [in] width       Circle pattern fill width.
  + *  \param [in] angle1      1st angle for pattern.
  + *  \param [in] pitch1      1st pitch for pattern.
  + *  \param [in] angle2      2nd angle for pattern.
  + *  \param [in] pitch2      2nd pitch for pattern.
  + */
  +void o_circle_fill_mesh(GdkDrawable *w, GdkGC *gc, GdkColor *color,
  +			gint x, gint y, gint radius,
  +			gint width,
  +			gint angle1, gint pitch1, gint angle2, gint pitch2)
  +{
  +  o_circle_fill_hatch(w, gc, color,
  +                      x, y, radius,
  +                      width, angle1, pitch1, -1, -1);
  +  o_circle_fill_hatch(w, gc, color,
  +                      x, y, radius,
  +                      width, angle2, pitch2, -1, -1);
  +	
  +}
  +
  +/*! \brief Erase a circle described by OBJECT
  + *  \par Function Description
  + *  This function erases a circle described in a #OBJECT structure
  + *  pointed by <B>o_current</B>.
  + *
  + *  It makes a call to the function #o_circle_draw() after setting the
  + *  special color. Therefore a circle is drawn with background color over
  + *  the previous one.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Circle OBJECT to erase.
  + */
  +void o_circle_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +	w_current->override_color = w_current->background_color;
  +	o_circle_draw(w_current, o_current);
  +	w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_circle_eraserubber(TOPLEVEL *w_current)
  +{
  +   o_circle_rubbercircle_xor(w_current);
  +}
  +
  +/*! \brief Draw a circle described by OBJECT with translation
  + *  \par Function Description
  + *  This function draws the circle object described by <B>*o_current</B>
  + *  translated by the vector (<B>dx</B>,<B>dy</B>) with an xor-function over
  + *  the current sheet.
  + *  The translation vector is in screen unit.
  + *
  + *  The circle is displayed with the color of the object.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] dx         Delta x coordinate for circle.
  + *  \param [in] dy         Delta y coordinate for circle.
  + *  \param [in] o_current  Circle OBJECT to draw.
  + *
  + *  \todo
  + *  add in offsets, get rid of global diffs_x,y
  + */
  +void o_circle_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  +{
  +  int x, y, radius;
  +  int color;
  +
  +  if (o_current->circle == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  /* radius of the circle */
  +  radius = o_current->circle->screen_radius;
  +  /* upper left corner of the square the circle is inscribed in */
  +  /* gdk coords system */
  +  x = o_current->circle->screen_x - o_current->circle->screen_radius;
  +  y = o_current->circle->screen_y - o_current->circle->screen_radius;
  +  
  +  /* translate the upper left corner */
  +  x = x + dx;
  +  y = y + dy;
  +  
  +  /* To draw be sure to setup width height */
  +  gdk_gc_set_foreground(w_current->outline_xor_gc,
  +			x_get_darkcolor(color));
  +  gdk_draw_arc(w_current->window, w_current->outline_xor_gc,
  +	       FALSE,
  +	       x, y,
  +	       2 * radius, 2 * radius,
  +	       0, FULL_CIRCLE);
  +  
  +  /* backing store ?  not appropriate here */
  +}
  +
  +/*! \brief Start process to input a new circle.
  + *  \par Function Description
  + *  This function starts the process to input a new circle. Parameters for
  + *  this circle are pu into/extracted from the <B>w_current</B> toplevel
  + *  structure.
  + *  <B>x</B> and <B>y</B> are current coordinates of the mouse pointer in
  + *  screen units.
  + *
  + *  The first step of the circle input is to set the center of the arc.
  + *  This center is kept in (<B>w_current->start_x</B>,<B>w_current->start_y</B>). 
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_circle_start(TOPLEVEL *w_current, int x, int y)
  +{
  +	/* center of circle */
  +	w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +	w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +	/* radius */
  +	w_current->distance = 0;
  +
  +	/* first temporary circle */
  +	o_circle_rubbercircle_xor(w_current);
  +
  +}
  +
  +/*! \brief End the input of a circle.
  + *  \par Function Description
  + *  This function ends the input of the radius of the circle.
  + *  The (<B>x</B>,<B>y</B>) point is taken as the other end of the radius
  + *  segment, i.e. on the circle. The distance between this point and the
  + *  center is the radius of the circle.
  + *  <B>x</B> and <B>y</B> are in screen coords.
  + *
  + *  The center has previously been input and saved as
  + *  (<B>w_current->start_x</B>,<B>w_current->start_y</B>).
  + *
  + *  The temporary circle drawn during the input of the radius is erased.
  + *  A new object is allocated, initialized and linked in the object list.
  + *  This new object is finally drawn.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_circle_end(TOPLEVEL *w_current, int x, int y)
  +{
  +  int center_x, center_y;
  +  int fx, fy;
  +  int radius;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  /* erase the temporary circle */
  +  o_circle_rubbercircle_xor(w_current);
  +  
  +  /* get the last coords of the pointer */
  +  fx = fix_x(w_current, x);
  +  fy = fix_y(w_current, y);
  +  /* compute the radius in screen unit */
  +  w_current->distance = dist(w_current->start_x, w_current->start_y,
  +                             fx, fy);
  +
  +  /* circle with null radius are not allowed */
  +  if (w_current->distance == 0) {
  +    /* cancel the object creation */
  +    w_current->start_x  = -1;
  +    w_current->start_y  = -1;
  +    w_current->last_x   = -1;
  +    w_current->last_y   = -1;
  +    w_current->distance = -1;
  +    return;
  +  }
  +
  +  /* get center coords in world unit */
  +  SCREENtoWORLD(w_current,
  +                w_current->start_x, w_current->start_y,
  +                &center_x, &center_y);
  +  /* get radius in world unit */
  +  radius = snap_grid(w_current,
  +                     WORLDabs(w_current, w_current->distance));
  +
  +  /* create the object */
  +  w_current->page_current->object_tail =
  +  o_circle_add(w_current,
  +               w_current->page_current->object_tail,
  +               OBJ_CIRCLE, w_current->graphic_color,
  +               center_x, center_y, radius);
  +
  +  /* draw it */
  +  o_redraw_single(w_current, w_current->page_current->object_tail);
  +  
  +  w_current->start_x = (-1);
  +  w_current->start_y = (-1);
  +  w_current->last_x  = (-1);
  +  w_current->last_y  = (-1);
  +  w_current->loc_x   = (-1);
  +  w_current->loc_y   = (-1);
  +  w_current->distance = (-1);
  +  
  +  w_current->page_current->CHANGED = 1;
  +
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \brief Draw temporary circle while dragging edge.
  + *  \par Function Description
  + *  This function draws a circle according to its internal representation and
  + *  allows the modification of its radius. The radius is updated according to
  + *  the current mouse position in <B>x</B> and <B>y</B>.
  + *  It draws a full circle and the horizontal segment of the radius in the
  + *  right half of the circle.
  + *
  + *  The previous temporary circle is erased, the radius is then computed and
  + *  updated and finally a new temporary circle is drawn.
  + *
  + *  The arc is internally described by :
  + *  <DL>
  + *    <DT>*</DT><DD>(<B>w_current->start_x</B>,<B>w_current->start_y</B>) as its
  + *                   center ;
  + *    <DT>*</DT><DD><B>w_current->distance</B> as its radius.
  + *  </DL>
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_circle_rubbercircle(TOPLEVEL *w_current, int x, int y)
  +{
  +  int diff_x, diff_y;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  /* erase the previous temporary circle */
  +  o_circle_rubbercircle_xor(w_current);
  +
  +  /*
  +   * The radius is taken as the biggest distance on the x and y axis between
  +   * the center of the circle and the mouse position.
  +   */
  +  /* update the radius */
  +  w_current->last_x = fix_x(w_current, x);
  +  w_current->last_y = fix_y(w_current, y);
  +  
  +  diff_x = GET_BOX_WIDTH (w_current);
  +  diff_y = GET_BOX_HEIGHT(w_current);
  +  if (diff_x >= diff_y) {
  +    w_current->last_y   = w_current->start_y;
  +    w_current->distance = diff_x;
  +  } else {
  +    w_current->last_x   = w_current->start_x;
  +    w_current->distance = diff_y;
  +  }
  +
  +  /* draw the new temporary circle */
  +  o_circle_rubbercircle_xor(w_current);
  +
  +}
  +
  +/*! \brief Draw circle from TOPLEVEL object.
  + *  \par Function Description
  + *  This function draws the circle from the variables in the toplevel
  + *  structure <B>*w_current</B>.
  + *  The center of the circle is at (<B>w_current->start_x</B>,
  + *  <B>w_current->start_y</B>) and its radius is in <B>w_current->distance</B>.
  + *
  + *  It draws a horizontal radius segment on the right half of the circle and
  + *  the circle with the selection color and an xor-function over the current
  + *  sheet..
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + */
  +void o_circle_rubbercircle_xor(TOPLEVEL *w_current)
  +{
  +  /* draw the circle from the w_current variables */
  +  gdk_gc_set_foreground(w_current->xor_gc, 
  +			x_get_darkcolor(w_current->select_color));
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		w_current->start_x, w_current->start_y,
  +		w_current->start_x + w_current->distance,
  +		w_current->start_y);
  +  gdk_draw_arc(w_current->window, w_current->xor_gc, FALSE,
  +	       w_current->start_x - w_current->distance,
  +	       w_current->start_y - w_current->distance,
  +	       w_current->distance * 2,
  +	       w_current->distance * 2,
  +	       0, FULL_CIRCLE);
  +}
  +
  +/*! \brief Draw grip marks on circle.
  + *  \par Function Description
  + *  This function draws the grip that match the circle object <B>*o_current</B>.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Circle OBJECT to draw grip points on.
  + */
  +void o_circle_draw_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  int x, y;
  +
  +  if (w_current->draw_grips == FALSE)
  +	  return;
  +
  +  /* coords of the lower right corner of the square */
  +  x = o_current->circle->screen_x + o_current->circle->screen_radius;
  +  y = o_current->circle->screen_y + o_current->circle->screen_radius;
  +  
  +  /* grip on lower right corner of the square */
  +  o_grips_draw(w_current, x, y);
  +
  +}
  +
  +/*! \brief Erase grip marks from circle.
  + *  \par Function Description
  + *  The function erases the grips displayed on a circle object.
  + *
  + *  A circle has a single grip on the lower right corner of the square it
  + *  is inscribed in.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Circle OBJECT to erase grip marks from.
  + */
  +void o_circle_erase_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  int x, y;
  +
  +  if (w_current->draw_grips == FALSE)
  +	  return;
  +
  +  /* coords of the lower right corner of square */
  +  x = o_current->circle->screen_x + o_current->circle->screen_radius;
  +  y = o_current->circle->screen_y + o_current->circle->screen_radius;
  +  
  +  /* grip on lower right corner of the square */
  +  o_grips_erase(w_current, x, y);
  +
  +}
  
  
  
  1.26      +827 -728  eda/geda/gaf/gschem/src/o_complex.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_complex.c
  ===================================================================
  RCS file: o_complex.c
  diff -N o_complex.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_complex.c	14 Jul 2006 02:23:54 -0000	1.26
  @@ -0,0 +1,938 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int left, right, top, bottom;
  +
  +  if (!w_current->DONT_REDRAW) {
  +    o_redraw(w_current, o_current->complex->prim_objs);
  +  }
  +
  +  get_complex_bounds(w_current, o_current->complex->prim_objs,
  +                     &left, &top, &right, &bottom);
  +  o_current->left   = left;
  +  o_current->top    = top;
  +  o_current->right  = right;
  +  o_current->bottom = bottom;
  +
  +  WORLDtoSCREEN(w_current,
  +                o_current->complex->x,
  +                o_current->complex->y,
  +                &o_current->complex->screen_x,
  +                &o_current->complex->screen_y);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  w_current->override_color = w_current->background_color;
  +  o_complex_draw(w_current, o_current);
  +  w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *complex)
  +{
  +  OBJECT *o_current = complex;
  +
  +  while(o_current != NULL) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        o_line_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +
  +      case(OBJ_NET):
  +        o_net_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +
  +      case(OBJ_BUS):
  +        o_bus_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +
  +      case(OBJ_BOX):
  +        o_box_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +        o_picture_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_circle_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_complex_draw_xor(w_current, dx, dy,
  +                           o_current->complex->prim_objs);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_text_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +
  +      case(OBJ_PIN):
  +        o_pin_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_arc_draw_xor(w_current, dx, dy, o_current);
  +        break;
  +    }
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_start(TOPLEVEL *w_current, int screen_x, int screen_y)
  +{
  +  int x, y;
  +  int i, temp;
  +
  +  w_current->last_x = w_current->start_x = fix_x(w_current, screen_x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, screen_y);
  +
  +  w_current->last_drawb_mode = -1;
  +
  +  /* make sure list is null first, so that you don't have a mem
  +   * leak */
  +  SCREENtoWORLD(w_current,
  +                w_current->start_x,
  +                w_current->start_y,
  +                &x,
  +                &y);
  +
  +  w_current->DONT_DRAW_CONN = 1;
  +  w_current->ADDING_SEL = 1; /* reuse this flag, rename later hack */
  +  w_current->page_current->complex_place_tail =
  +  (OBJECT *) o_complex_add(
  +                           w_current,
  +                           w_current->page_current->complex_place_head,
  +                           OBJ_COMPLEX, WHITE, x, y, 0, 0,
  +                           w_current->internal_clib,
  +                           w_current->internal_basename, 1, TRUE);
  +  w_current->ADDING_SEL = 0;
  +  w_current->DONT_DRAW_CONN = 0;
  +
  +  if (w_current->complex_rotate) {
  +    temp = w_current->complex_rotate / 90;
  +    for (i = 0; i < temp; i++) {
  +      o_complex_place_rotate(w_current);
  +    }
  +  }
  +
  +  o_drawbounding(w_current, 
  +                 w_current->page_current->complex_place_head->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_place_rotate(TOPLEVEL *w_current)
  +{
  +  OBJECT *o_current;
  +  int screen_x_local = -1;
  +  int screen_y_local = -1;
  +  int new_angle;
  +
  +  o_current = w_current->page_current->complex_place_head->next;
  +  while(o_current) {
  +    switch(o_current->type) {	
  +      case(OBJ_COMPLEX):
  +        screen_x_local = o_current->complex->screen_x; 
  +        screen_y_local = o_current->complex->screen_y;
  +        break;
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +  if (screen_x_local == -1) {
  +    printf(_("Could not find complex in new componet placement!\n"));
  +    return;
  +  }
  +
  +  o_current = w_current->page_current->complex_place_head->next;
  +  while(o_current) {
  +    switch(o_current->type) {	
  +
  +      case(OBJ_TEXT):
  +        new_angle = (o_current->text->angle + 90) % 360;
  +        o_text_rotate(w_current, screen_x_local, screen_y_local,
  +                      new_angle, 90, o_current);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +        new_angle = (o_current->complex->angle + 90) % 360;
  +        o_complex_rotate(w_current, screen_x_local, screen_y_local,
  +                         new_angle, 90, o_current);
  +        break;
  +
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_end(TOPLEVEL *w_current, int screen_x, int screen_y)
  +{
  +  int diff_x, diff_y;
  +  int x, y;
  +  int rleft, rtop, rbottom, rright;
  +  OBJECT *o_current;
  +  OBJECT *o_start;
  +  OBJECT *o_temp;
  +  char *include_filename;
  +  int temp, new_angle, i;
  +  GList *connected_objects=NULL;
  +
  +  diff_x = w_current->last_x - w_current->start_x;
  +  diff_y = w_current->last_y - w_current->start_y;
  +
  +  SCREENtoWORLD(w_current, screen_x, screen_y, &x, &y);
  +
  +#if 0
  +  x = snap_grid(w_current, x);
  +  y = snap_grid(w_current, y);
  +#endif
  +
  +#if DEBUG
  +  printf("place_basename: %s\n",internal_basename);
  +  printf("place_clib: %s\n",internal_clib);
  +#endif
  +
  +  if (w_current->include_complex) {
  +    include_filename = g_strconcat (w_current->internal_clib,
  +                                    G_DIR_SEPARATOR_S,
  +                                    w_current->internal_basename,
  +                                    NULL);
  +
  +    w_current->ADDING_SEL=1;
  +    o_start = w_current->page_current->object_tail;
  +    w_current->page_current->object_tail =
  +      o_read(w_current,
  +             w_current->page_current->object_tail,
  +             include_filename);
  +    o_start = o_start->next;
  +    w_current->ADDING_SEL=0;
  +
  +    o_complex_world_translate(w_current, x, y, o_start);
  +
  +    o_temp = o_start;
  +    while (o_temp != NULL) {
  +      if (o_temp->type == OBJ_NET || o_temp->type == OBJ_PIN ||
  +          o_temp->type == OBJ_BUS) {
  +        s_conn_update_object(w_current, o_temp);
  +                  
  +        connected_objects = s_conn_return_others(connected_objects,
  +                                                 o_temp);
  +      }
  +      o_temp = o_temp->next;
  +    }
  +    o_cue_undraw_list(w_current, connected_objects);
  +    o_cue_draw_list(w_current, connected_objects);
  +    g_list_free(connected_objects);
  +
  +    free(include_filename);
  +
  +    if (w_current->actionfeedback_mode == OUTLINE) {
  +#if 0
  +      printf("inside draw outline here\n");
  +#endif
  +      /* erase outline */
  +      o_complex_translate_display(
  +                                  w_current,
  +                                  diff_x, diff_y,
  +                                  w_current->page_current->
  +                                  complex_place_head->next);
  +    } else {
  +#if 0
  +      printf("inside draw bounding here\n");
  +#endif
  +      get_complex_bounds(
  +                         w_current,
  +                         w_current->page_current->
  +                         complex_place_head->next,
  +                         &rleft, &rtop, &rright, &rbottom);
  +      gdk_gc_set_foreground(
  +                            w_current->gc,
  +                            x_get_color(w_current->background_color));
  +      gdk_draw_rectangle(w_current->window, w_current->gc,
  +                         FALSE,
  +                         rleft   + diff_x,
  +                         rtop    + diff_y,
  +                         rright  - rleft,
  +                         rbottom - rtop);
  +    }
  +
  +    o_redraw(w_current, o_start);
  +    w_current->page_current->CHANGED = 1;
  +    o_undo_savestate(w_current, UNDO_ALL);
  +    i_update_menus(w_current);
  +    o_list_delete_rest(w_current, w_current->page_current->
  +                       complex_place_head);
  +    return;
  +  }
  +
  +  o_temp = w_current->page_current->object_tail;
  +  w_current->page_current->object_tail =
  +    o_complex_add(
  +                  w_current,
  +                  w_current->page_current->object_tail,
  +                  OBJ_COMPLEX, WHITE, x, y, w_current->complex_rotate, 0,
  +                  w_current->internal_clib,
  +                  w_current->internal_basename, 1, TRUE);
  +
  +  /* complex rotate post processing */
  +  o_temp = o_temp->next; /* skip over last object */
  +  while (o_temp != NULL) {
  +    switch(o_temp->type) {
  +      case(OBJ_TEXT):
  +        temp = w_current->complex_rotate / 90;
  +        for (i = 0; i < temp; i++) {
  +          new_angle = (o_temp->
  +                       text->angle + 90) % 360;
  +          o_text_rotate(w_current, 
  +                        screen_x, screen_y,
  +                        new_angle, 90, o_temp);
  +        }
  +        break;
  +    }
  +		
  +    o_temp = o_temp->next;
  +  }
  +
  +  /* 1 should be define fix everywhere hack */
  +	
  +  o_current = w_current->page_current->object_tail;
  +
  +  if (scm_hook_empty_p(add_component_hook) == SCM_BOOL_F &&
  +      o_current != NULL) {
  +    scm_run_hook(add_component_hook,
  +                 scm_cons(g_make_attrib_smob_list(w_current, o_current),
  +                          SCM_EOL));
  +  }
  +
  +  if (scm_hook_empty_p(add_component_object_hook) == SCM_BOOL_F &&
  +      o_current != NULL) {
  +    scm_run_hook(add_component_object_hook,
  +		 scm_cons(g_make_object_smob(w_current, o_current),
  +			  SCM_EOL));
  +  }
  +
  +  /* put code here to deal with emebedded stuff */
  +  if (w_current->embed_complex) {
  +    char* new_basename;
  +
  +    free(o_current->complex_clib);
  +
  +    o_current->complex_clib = g_strdup ("EMBEDDED");
  +
  +    new_basename = g_strconcat ("EMBEDDED",
  +                                o_current->complex_basename,
  +                                NULL);
  +
  +    free(o_current->complex_basename);
  +
  +    o_current->complex_basename = g_strdup (new_basename);
  +
  +    free(new_basename);
  +  }
  +
  +  /* check for nulls in all this hack */
  +  if (w_current->actionfeedback_mode == OUTLINE) {
  +#if 0
  +    printf("inside draw outline here\n");
  +#endif
  +    /* erase outline */
  +    o_complex_translate_display(
  +                                w_current,
  +                                diff_x, diff_y,
  +                                w_current->page_current->complex_place_head->next);
  +  } else {
  +#if 0
  +    printf("inside draw bounding here\n");
  +#endif
  +    get_complex_bounds(
  +                       w_current,
  +                       w_current->page_current->complex_place_head->next,
  +                       &rleft, &rtop,
  +                       &rright, &rbottom);
  +    gdk_gc_set_foreground(
  +                          w_current->gc,
  +                          x_get_color(w_current->background_color));
  +    gdk_draw_rectangle(w_current->window, w_current->gc, FALSE,
  +                       rleft   + diff_x,
  +                       rtop    + diff_y,
  +                       rright  - rleft,
  +                       rbottom - rtop);
  +  }
  +
  +  /*! \todo redraw has to happen at the end of all this hack or
  +   * maybe not? */
  +  o_list_delete_rest(w_current,
  +                     w_current->page_current->complex_place_head);
  +
  +  /* This doesn't allow anything else to be in the selection
  +   * list when you add a component */
  +
  +  o_selection_remove_most(w_current,
  +                          w_current->page_current->selection2_head);
  +  o_selection_add(w_current->page_current->selection2_head, 
  +                  w_current->page_current->object_tail);
  +  /* the o_redraw_selected is in x_events.c after this call
  +   * returns */
  +  o_attrib_add_selected(w_current, w_current->page_current->selection2_head,
  +                        w_current->page_current->object_tail);
  +
  +  s_conn_update_complex(w_current, o_current->complex->prim_objs);
  +  connected_objects = s_conn_return_complex_others(connected_objects,
  +                                                   o_current);
  +  o_cue_undraw_list(w_current, connected_objects);
  +  o_cue_draw_list(w_current, connected_objects);
  +  g_list_free(connected_objects);
  +  o_cue_draw_single(w_current, w_current->page_current->object_tail);
  +        
  +  w_current->page_current->CHANGED = 1;
  +  o_undo_savestate(w_current, UNDO_ALL);
  +  i_update_menus(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_rubbercomplex(TOPLEVEL *w_current)
  +{
  +  o_drawbounding(w_current,
  +                 w_current->page_current->complex_place_head->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), FALSE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_translate_display(TOPLEVEL *w_current,
  +				 int x1, int y1, OBJECT *complex)
  +{
  +  OBJECT *o_current = complex;
  +
  +  while (o_current != NULL) {
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        o_line_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_NET):
  +        o_net_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_BUS):
  +        o_bus_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_BOX):
  +        o_box_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +        o_picture_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_circle_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_complex_draw_xor(w_current, x1, y1, 
  +                           o_current->complex->prim_objs);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_text_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_PIN):
  +        o_pin_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_arc_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +    }
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_translate_display_selection(TOPLEVEL *w_current,
  +					   int x1, int y1, SELECTION *head)
  +{
  +  SELECTION *s_current = head;
  +  OBJECT *o_current;
  +
  +  while (s_current != NULL) {
  +
  +    o_current = s_current->selected_object;
  +
  +    if (!o_current) {
  +      fprintf(stderr, _("Got NULL in o_complex_translate_display_selection\n"));
  +      exit(-1);
  +    }
  +
  +    switch(o_current->type) {
  +      case(OBJ_LINE):
  +        o_line_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_NET):
  +        o_net_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_BUS):
  +        o_bus_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_BOX):
  +        o_box_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +        o_picture_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_circle_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_complex_draw_xor(w_current, x1, y1, 
  +                           o_current->complex->prim_objs);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_text_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_PIN):
  +        o_pin_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_arc_draw_xor(w_current, x1, y1, o_current);
  +        break;
  +    }
  +    s_current = s_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  experimental
  + */
  +void o_complex_translate2(TOPLEVEL *w_current, int dx, int dy, OBJECT *object)
  +{
  +  if (object == NULL)  {
  +    printf("cmt2 NO!\n");
  +    return;
  +  }
  +
  +  o_complex_translate_display(w_current, dx, dy, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't know if this belongs yet
  + */
  +void o_complex_translate_all(TOPLEVEL *w_current, int offset)
  +{
  +  int rleft, rtop, rright, rbottom;
  +  OBJECT *o_current;
  +  int x, y;
  +
  +  /* first zoom extents */
  +  a_zoom_extents(w_current, w_current->page_current->object_head, 
  +                 A_PAN_DONT_REDRAW);
  +  o_redraw_all(w_current);
  +
  +  get_complex_bounds(w_current, w_current->page_current->object_head,
  +                     &rleft,
  +                     &rtop,
  +                     &rright,
  +                     &rbottom);
  +
  +  /*! \todo do we want snap grid here? */
  +  SCREENtoWORLD(w_current,
  +                fix_x(w_current, rleft  ),
  +                fix_y(w_current, rbottom),
  +                &x,
  +                &y);
  +
  +  o_current = w_current->page_current->object_head;
  +  while(o_current != NULL) {
  +    if (o_current->type != OBJ_COMPLEX && o_current->type != OBJ_PLACEHOLDER) {
  +      s_conn_remove(w_current, o_current);
  +    } else {
  +      s_conn_remove_complex(w_current, o_current);
  +    }
  +    o_current = o_current->next;
  +  }
  +        
  +  if (offset == 0) {
  +    s_log_message(_("Translating schematic [%d %d]\n"), -x, -y);
  +    o_complex_world_translate(
  +                              w_current,
  +                              -x, -y,
  +                              w_current->page_current->object_head);
  +  } else {
  +    s_log_message(_("Translating schematic [%d %d]\n"),
  +                  offset, offset);
  +    o_complex_world_translate(
  +                              w_current,
  +                              offset, offset,
  +                              w_current->page_current->object_head);
  +  }
  +
  +  o_current = w_current->page_current->object_head;
  +  while(o_current != NULL) {
  +    if (o_current->type != OBJ_COMPLEX && o_current->type != OBJ_PLACEHOLDER) {
  +      s_conn_update_object(w_current, o_current);
  +    } else {
  +      s_conn_update_complex(w_current, o_current->complex->prim_objs);
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +  /* this is an experimental mod, to be able to translate to all
  +   * places */
  +#if 0
  +  o_complex_world_translate(1000, 1000, object_head);
  +  printf("symbol -%d -%d\n", x, y);
  +  o_complex_world_translate(-x, -y, object_head); /* to zero, zero */
  +#endif
  +
  +  a_zoom_extents(w_current, w_current->page_current->object_head, 
  +                 A_PAN_DONT_REDRAW);
  +  o_unselect_all(w_current);
  +  o_redraw_all(w_current);
  +  w_current->page_current->CHANGED=1;
  +  o_undo_savestate(w_current, UNDO_ALL);
  +  i_update_menus(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_translate_selection(TOPLEVEL *w_current, int dx, int dy, 
  +				   SELECTION *head)
  +{
  +  if (head == NULL)  {
  +    printf(_("Got NULL in o_complex_translate_selection!\n"));
  +    return;
  +  }
  +
  +  o_complex_translate_display_selection(w_current, dx, dy, head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_complex_rotate(TOPLEVEL *w_current, int centerx, int centery,
  +		      int angle, int angle_change, OBJECT *object)
  +{
  +  int x, y;
  +  int newx, newy;
  +  int world_centerx, world_centery;
  +
  +  SCREENtoWORLD(w_current,
  +                centerx,
  +                centery,
  +                &world_centerx,
  +                &world_centery);
  +
  +  x = object->complex->x + (-world_centerx);
  +  y = object->complex->y + (-world_centery);
  +
  +  rotate_point_90(x, y, 90, &newx, &newy);
  +
  +  x = newx + (world_centerx);
  +  y = newy + (world_centery);
  +
  +  o_complex_world_translate_toplevel(w_current,
  +                                     -object->complex->x, 
  +                                     -object->complex->y, object);
  +  o_complex_rotate_lowlevel(w_current,
  +                            0, 0, angle, angle_change, object);
  +
  +  object->complex->x = 0;
  +  object->complex->y = 0;
  +
  +  o_complex_world_translate_toplevel(w_current, x, y, object);
  +
  +  object->complex->angle = angle;
  +
  +#if DEBUG
  +  printf("setting final rotated angle to: %d\n\n", object->angle);
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_complex_mirror(TOPLEVEL *w_current, int centerx, int centery,
  +		     OBJECT *object)
  +{
  +  int x, y;
  +  int newx, newy;
  +  int origx, origy;
  +  int world_centerx, world_centery;
  +  int change = 0;
  +
  +  SCREENtoWORLD(w_current,
  +                centerx,
  +                centery,
  +                &world_centerx,
  +                &world_centery);
  +
  +  origx = object->complex->x;
  +  origy = object->complex->y;
  +
  +  x = object->complex->x + (-world_centerx);
  +  y = object->complex->y + (-world_centery);
  +
  +  newx = -x;
  +  newy = y;
  +
  +  x = newx + (world_centerx);
  +  y = newy + (world_centery);
  +
  +  o_complex_world_translate_toplevel(w_current,
  +                                     -object->complex->x, 
  +                                     -object->complex->y, object);
  +
  +  o_complex_mirror_lowlevel(w_current, 0, 0, object);
  +
  +  switch(object->complex->angle) {
  +    case(90):
  +      object->complex->angle = 270;
  +#if 0
  +      o_text_change_angle(w_current, object->complex->prim_objs,
  +                          object->complex->angle);
  +#endif
  +
  +      change = 1;
  +      break;
  +
  +    case(270):
  +      object->complex->angle = 90;
  +#if 0
  +      o_text_change_angle(w_current, object->complex->prim_objs
  +                          object->complex->angle);
  +#endif
  +      change = 1;
  +      break;
  +
  +  }
  +#if 0
  +  object->complex->angle = (object->complex->angle + 180) % 360;
  +#endif
  +
  +  object->complex->mirror = !object->complex->mirror;
  +#if 0
  +  object->complex->x = 0;
  +  object->complex->y = 0;
  +#endif
  +
  +  o_complex_world_translate_toplevel(w_current, x, y, object);
  +
  +#if DEBUG
  +  printf("final res %d %d\n", object->complex->x,  object->complex->y);
  +#endif
  +#if 0
  +  object->complex->x = x;
  +  object->complex->y = y;
  +#endif
  +  return(change);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is a special mirror which doesn't mirror the object in memory,
  + *  but read the new "correctly mirrored/rotated" object from disk
  + *  \todo yes this is aweful, and I will eventually fix it, but for now
  + *        it has to do hack
  + */
  +OBJECT *o_complex_mirror2(TOPLEVEL *w_current, OBJECT *list,
  +			  int centerx, int centery,
  +			  OBJECT *object)
  +{
  +  OBJECT *new_obj = NULL;
  +  int x, y;
  +  int newx, newy;
  +  int origx, origy;
  +  int world_centerx, world_centery;
  +  int change=0;
  +  int color;
  +
  +  SCREENtoWORLD(w_current,
  +                centerx,
  +                centery,
  +                &world_centerx,
  +                &world_centery);
  +
  +  origx = object->complex->x;
  +  origy = object->complex->y;
  +
  +  x = object->complex->x + (-world_centerx);
  +  y = object->complex->y + (-world_centery);
  +
  +  newx = -x;
  +  newy = y;
  +
  +  x = newx + (world_centerx);
  +  y = newy + (world_centery);
  +
  +  switch(object->complex->angle) {
  +    case(90):
  +      object->complex->angle = 270;
  +#if 0
  +      o_text_change_angle(w_current, object->complex->prim_objs,
  +                          object->complex->angle);
  +#endif
  +      change = 1;
  +      break;
  +
  +    case(270):
  +      object->complex->angle = 90;
  +#if 0
  +      o_text_change_angle(w_current, object->complex->prim_objs,
  +                          object->complex->angle);
  +#endif
  +      change=1;
  +      break;
  +
  +  }
  +
  +  object->complex->mirror = !object->complex->mirror;
  +
  +  if (object->saved_color == -1) {
  +    color = object->color;
  +  } else {
  +    color = object->saved_color;
  +  }
  +
  +
  +  new_obj = o_complex_add(w_current,
  +                          list, object->type,
  +                          color,
  +                          x, y,
  +                          object->complex->angle, 
  +                          object->complex->mirror,
  +                          object->complex_clib, object->complex_basename,
  +                          1, FALSE);
  +
  +  /*! \todo fix up name sometime ... */
  +  new_obj->sid = object->sid;
  +
  +  new_obj->attribs = o_attrib_copy_all(
  +                                       w_current, new_obj, object->attribs);
  +
  +  o_attrib_slot_update(w_current, new_obj);
  +
  +  o_complex_delete(w_current, object);
  +
  +  /* need to do the following, because delete severs links */
  +  o_attrib_reattach(new_obj->attribs);
  +  o_attrib_set_color(w_current, new_obj->attribs);
  +
  +
  +#if 0
  +  w_current->page_current->object_tail = (OBJECT *)
  +  return_tail(w_current->page_current->object_head);
  +#endif
  +
  +  return(new_obj);
  +}
  
  
  
  1.24      +159 -70   eda/geda/gaf/gschem/src/o_copy.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_copy.c
  ===================================================================
  RCS file: o_copy.c
  diff -N o_copy.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_copy.c	14 Jul 2006 02:23:55 -0000	1.24
  @@ -0,0 +1,537 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <string.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_copy_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  if (w_current->page_current->selection2_head->next != NULL) {
  +    /* Save the current state. When rotating the selection when copying,
  +       we have to come back to here */
  +    o_undo_savestate(w_current, UNDO_ALL);
  +
  +    w_current->last_drawb_mode = -1;
  +    /* Shouldn't this set by the caller ? */
  +    /*    w_current->event_state = COPY; */
  +
  +    w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +    w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +    o_drawbounding(w_current, NULL,
  +                   w_current->page_current->selection2_head->next,
  +                   x_get_darkcolor(w_current->bb_color), TRUE);
  +    w_current->inside_action = 1;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_copy_end(TOPLEVEL *w_current)
  +{
  +  SELECTION *temp_list = NULL;
  +  SELECTION *s_current = NULL;
  +  GList *new_objects = NULL;
  +  GList *connected_objects=NULL;
  +  OBJECT *new_object = NULL;
  +  OBJECT *complex_object = NULL;
  +  OBJECT *new_objects_head = NULL;
  +  OBJECT *object;
  +  int diff_x, diff_y;
  +  int screen_diff_x, screen_diff_y;
  +  int lx, ly;
  +  int sx, sy;
  +  int color;
  +  int redraw_state;
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  if (object == NULL) {
  +    /*! \todo error condition */
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    return;
  +  }
  +
  +  screen_diff_x = w_current->last_x - w_current->start_x;
  +  screen_diff_y = w_current->last_y - w_current->start_y;
  +
  +  SCREENtoWORLD(w_current,
  +                w_current->last_x,
  +                w_current->last_y,
  +                &lx,
  +                &ly);
  +  SCREENtoWORLD(w_current,
  +                w_current->start_x,
  +                w_current->start_y,
  +                &sx,
  +                &sy);
  +
  +  diff_x = lx - sx;
  +  diff_y = ly - sy;
  +
  +  /* skip over head node */
  +  s_current = w_current->page_current->selection2_head->next;
  +  temp_list = o_selection_new_head();
  +  new_objects_head = s_basic_init_object("object_head");
  +
  +  while(s_current != NULL) {
  +
  +    if (s_current->selected_object == NULL) {
  +      fprintf(stderr, _("ERROR: NULL object in o_copy_end!\n"));
  +      exit(-1);
  +    }
  +
  +    object = s_current->selected_object;
  +    switch(object->type) {
  +
  +      case(OBJ_NET):
  +
  +	/* ADDING_SEL is a bad name, rename hack */
  +	/* basically I don't want to add the */
  +	/* connections till much later */
  +        w_current->ADDING_SEL=1;
  +        new_object = (OBJECT *) o_net_copy(w_current,
  +					   return_tail(new_objects_head),
  +                                           object);
  +        w_current->ADDING_SEL=0; 
  +
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_net_draw_xor(w_current,
  +                         screen_diff_x, screen_diff_y,
  +                         object);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_net_translate_world(w_current,
  +                              diff_x, diff_y,
  +                              new_object);
  +        w_current->ADDING_SEL=0; 
  +
  +
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_net_draw(w_current, new_object);
  +
  +        s_conn_update_object(w_current, new_object);
  +        new_objects = g_list_append(new_objects, new_object);
  +        connected_objects = s_conn_return_others(connected_objects,
  +                                                 new_object);
  +        break;
  +        
  +      case(OBJ_PIN):
  +	/* ADDING_SEL is a bad name, rename hack */
  +	/* basically I don't want to add the */
  +	/* connections till much later */
  +        w_current->ADDING_SEL=1; 
  +        new_object = (OBJECT *) o_pin_copy(w_current,
  +                                           return_tail(new_objects_head), 
  +                                           object);
  +        w_current->ADDING_SEL=0; 
  +
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_pin_draw_xor(w_current,
  +                         screen_diff_x,
  +                         screen_diff_y,
  +                         object);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_pin_translate_world(w_current,
  +                              diff_x, diff_y,
  +                              new_object);
  +        w_current->ADDING_SEL=0; 
  +        
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_pin_draw(w_current, new_object);
  +        
  +        s_conn_update_object(w_current, new_object);
  +        new_objects = g_list_append(new_objects, new_object);
  +        connected_objects = s_conn_return_others(connected_objects,
  +                                                 new_object);
  +        break;
  +
  +      case(OBJ_BUS):
  +	/* ADDING_SEL is a bad name, rename hack */
  +	/* basically I don't want to add the */
  +	/* connections till much later */
  +        w_current->ADDING_SEL=1; 
  +        new_object = (OBJECT *) o_bus_copy(w_current,
  +                                           return_tail(new_objects_head),
  +                                           object);
  +        w_current->ADDING_SEL=0; 
  +
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_bus_draw_xor(w_current,
  +                         screen_diff_x, screen_diff_y,
  +                         object);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_bus_translate_world(w_current,
  +                              diff_x, diff_y,
  +                              new_object);
  +        w_current->ADDING_SEL=0; 
  +        
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_bus_draw(w_current, new_object);
  +        
  +        s_conn_update_object(w_current, new_object);
  +        new_objects = g_list_append(new_objects, new_object);
  +        connected_objects = s_conn_return_others(connected_objects,
  +                                                 new_object);
  +        break;
  +        
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        w_current->ADDING_SEL=1; 
  +        if (object->complex_clib && 
  +            strncmp(object->complex_clib, "EMBEDDED", 8) == 0) {
  +
  +          new_object = (OBJECT *) 
  +            o_complex_copy_embedded(w_current, 
  +				    return_tail(new_objects_head), 
  +                                    object);
  +
  +        } else {
  +          new_object = (OBJECT *) o_complex_copy(w_current,
  +                                                 return_tail(new_objects_head), 
  +                                                 object);
  +        }
  +        w_current->ADDING_SEL=0; 
  +				
  +        complex_object = new_object;
  +
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_complex_draw_xor(w_current, screen_diff_x, screen_diff_y,
  +                             object->complex->prim_objs);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_complex_world_translate_toplevel(w_current,
  +                                           diff_x,
  +                                           diff_y,
  +                                           new_object);
  +        w_current->ADDING_SEL=0; 
  +
  +        o_selection_add(temp_list, new_object);
  +
  +	/* NEWSEL: this needs to be fixed too */
  +	/* this may not be needed anymore? */
  +        o_attrib_slot_copy(w_current, object, 
  +                           new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_redraw_single(w_current, new_object);
  +
  +        s_conn_update_complex(w_current, new_object->complex->prim_objs);
  +        new_objects = g_list_append(new_objects, new_object);
  +        connected_objects = s_conn_return_complex_others(connected_objects,
  +                                                         new_object);
  +        break;
  +
  +      case(OBJ_LINE):
  +        new_object = (OBJECT *) o_line_copy(w_current,
  +                                            return_tail(new_objects_head),
  +                                            object);
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_line_draw_xor(w_current,
  +                          screen_diff_x, screen_diff_y,
  +                          object);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_line_translate_world(w_current,
  +                               diff_x, diff_y,
  +                               new_object);
  +        w_current->ADDING_SEL=0; 
  +
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_line_draw(w_current, new_object);
  +        break;
  +
  +      case(OBJ_BOX):
  +        new_object = (OBJECT *) o_box_copy(w_current,
  +                                           return_tail(new_objects_head),
  +                                           object);
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_box_draw_xor(w_current,
  +                         screen_diff_x,
  +                         screen_diff_y,
  +                         object);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_box_translate_world(w_current,
  +                              diff_x, diff_y,
  +                              new_object);
  +        w_current->ADDING_SEL=0; 
  +        
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_box_draw(w_current, new_object);
  +        
  +        break;
  +
  +#ifndef HAS_GTK12
  +      case(OBJ_PICTURE):
  +        new_object = (OBJECT *) o_picture_copy(w_current,
  +					       return_tail(new_objects_head),
  +					       object);
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_picture_draw_xor(w_current,
  +			     screen_diff_x,
  +			     screen_diff_y,
  +			     object);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_picture_translate_world(w_current,
  +				  diff_x, diff_y,
  +				  new_object);
  +        w_current->ADDING_SEL=0; 
  +        
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_picture_draw(w_current, new_object);
  +        
  +        break;
  +#endif
  +      case(OBJ_CIRCLE):
  +        new_object = (OBJECT *) o_circle_copy(w_current,
  +                                              return_tail(new_objects_head),
  +                                              object);
  +
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_circle_draw_xor(w_current,
  +                            screen_diff_x,
  +                            screen_diff_y,
  +                            object);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_circle_translate_world(w_current,
  +                                 diff_x, diff_y,
  +                                 new_object);
  +        w_current->ADDING_SEL=0; 
  +
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_circle_draw(w_current, new_object);
  +        break;
  +
  +      case(OBJ_ARC):
  +        new_object = (OBJECT *) o_arc_copy(w_current,
  +					   return_tail(new_objects_head), 
  +                                           object);
  +
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_arc_draw_xor(w_current,
  +                         screen_diff_x,
  +                         screen_diff_y,
  +                         object);
  +        }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_arc_translate_world(w_current,
  +                              diff_x, diff_y,
  +                              new_object);
  +        w_current->ADDING_SEL=0; 
  +        
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = object->saved_color;
  +        o_arc_draw(w_current, new_object);
  +        break;
  +
  +    }
  +
  +    w_current->page_current->object_tail =
  +      (OBJECT *) return_tail(w_current->page_current->
  +                             object_head);
  +    s_current = s_current->next;
  +  }
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +  while(s_current != NULL) {
  +
  +    if (s_current->selected_object == NULL) {
  +      fprintf(stderr, _("ERROR: NULL object in o_copy_end!\n"));
  +      exit(-1);
  +    }
  +
  +    object = s_current->selected_object;
  +    switch(object->type) {
  +
  +      case(OBJ_TEXT):
  +        w_current->ADDING_SEL=1; 
  +        new_object = (OBJECT *) o_text_copy(w_current,
  +                                            return_tail(new_objects_head),
  +                                            object);
  +        w_current->ADDING_SEL=0; 
  +
  +	/* this is also okay NEWSEL new_obj is single */
  +        if (object->attached_to) {
  +          if (object->attached_to->copied_to) {
  +            o_attrib_attach(w_current, new_objects_head,
  +                            new_object, object->attached_to-> copied_to);
  +	    	    
  +            /*! \todo I have no idea if this is
  +               really needed.... ? */
  +#if 0
  +            o_attrib_slot_update(
  +                                 w_current,
  +                                 object->attached_to->copied_to);
  +#endif
  +
  +            /* satisfied copy request */
  +            object->attached_to->copied_to = NULL;
  +          }
  +        }
  +	
  +        if (w_current->actionfeedback_mode == OUTLINE) {
  +          o_text_draw_xor(w_current,
  +                          screen_diff_x,
  +                          screen_diff_y,
  +                          object);
  +			  }
  +
  +        w_current->ADDING_SEL=1; 
  +        o_text_translate_world(w_current, diff_x, diff_y, new_object);
  +        w_current->ADDING_SEL=0; 
  +
  +				/* old object was attr */
  +        if (!new_object->attribute && 
  +            object->attribute) {
  +          new_object->color = w_current-> detachedattr_color;
  +          o_complex_set_color(new_object, new_object->color);
  +          new_object->visibility = VISIBLE;
  +          color = new_object->color;
  +        } else {
  +          color = object->saved_color;
  +        }
  +
  +        o_selection_add(temp_list, new_object);
  +        new_object->saved_color = color;
  +        
  +	/* signify that object is no longer an attribute */
  +	o_text_draw(w_current, new_object);
  +
  +        o_complex_set_saved_color_only(
  +                                       new_object->text->prim_objs, 
  +                                       color);
  +        break;
  +    }
  +
  +    w_current->page_current->object_tail =
  +      (OBJECT *) return_tail(w_current->page_current->
  +                             object_head);
  +    s_current = s_current->next;
  +  }
  +
  +  /* Go back to the state before copying, to restore possible rotations
  +     of the selection */
  +  redraw_state = w_current->DONT_REDRAW;
  +  w_current->DONT_REDRAW = 0;
  +  o_undo_callback(w_current, UNDO_ACTION);
  +  w_current->DONT_REDRAW = redraw_state;
  +
  +  /* Add the new objects */
  +  w_current->page_current->object_tail = (OBJECT *)
  +  return_tail(w_current->page_current->object_head);
  +
  +  s_basic_link_object(new_objects_head, w_current->page_current->object_tail);
  +
  +  /* Run the copy component hook */
  +  object = new_objects_head->next;
  +  while (object != NULL) {
  +    if ((object->type == OBJ_COMPLEX) &&
  +	(scm_hook_empty_p(copy_component_hook) == SCM_BOOL_F)) {
  +      scm_run_hook(copy_component_hook,
  +		   scm_cons (g_make_attrib_smob_list(w_current, object),
  +		   SCM_EOL));
  +    }
  +    object = object->next;
  +  }
  +  
  +  /* And redraw them */
  +  object = new_objects_head;
  +  while (object) {
  +    o_redraw_single(w_current, object);
  +    object=object->next;
  +  }
  +  
  +  /* Delete the new object head */
  +  /*  new_objects_head->next = NULL;
  +      s_delete_list_fromstart(w_current, new_objects_head); */
  +
  +  w_current->page_current->object_tail = (OBJECT *)
  +  return_tail(w_current->page_current->object_head);
  +
  +  /* erase the bounding box */
  +  if (w_current->actionfeedback_mode == BOUNDINGBOX) {
  +    o_drawbounding(w_current, NULL,
  +                   w_current->page_current->selection2_head->next,
  +                   x_get_darkcolor(w_current->bb_color), TRUE);
  +  }
  +
  +  o_select_run_hooks(w_current, NULL, 2); 
  +  o_selection_remove_most(w_current,
  +                          w_current->page_current->selection2_head);
  +  o_selection_destroy_head(w_current->page_current->selection2_head);
  +  w_current->page_current->selection2_head = temp_list;
  +  w_current->page_current->selection2_tail = o_selection_return_tail(
  +                                                                     temp_list);
  +#if DEBUG
  +  o_selection_print_all(w_current->page_current->selection2_head);
  +#endif
  +
  +  w_current->page_current->CHANGED = 1;
  +
  +  /* not needed o_redraw(w_current, w_current->page_current->object_head); */
  +  o_cue_draw_list(w_current, new_objects);
  +  o_cue_undraw_list(w_current, connected_objects);
  +  o_cue_draw_list(w_current, connected_objects);
  +  
  +  g_list_free(new_objects);
  +  g_list_free(connected_objects);
  +  new_objects = NULL;
  +  connected_objects = NULL;
  +  
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  
  
  
  1.4       +196 -53   eda/geda/gaf/gschem/src/o_cue.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_cue.c
  ===================================================================
  RCS file: o_cue.c
  diff -N o_cue.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_cue.c	14 Jul 2006 02:23:55 -0000	1.4
  @@ -0,0 +1,544 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <string.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_redraw_all(TOPLEVEL *w_current, OBJECT *head)
  +{
  +  OBJECT *o_current;
  +
  +  o_current = head;
  +  while(o_current != NULL) {
  +    switch(o_current->type) {
  +      case(OBJ_NET):
  +      case(OBJ_BUS):
  +      case(OBJ_PIN):
  +        o_cue_draw_single(w_current, o_current);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_cue_redraw_all(w_current, o_current->complex->prim_objs);
  +	break;
  +
  +    }
  +    
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_draw_lowlevel(TOPLEVEL *w_current, OBJECT *object, int whichone)
  +{
  +  int x, y, screen_x, screen_y;
  +  GList *cl_current;
  +  CONN *conn;
  +  int type, count = 0;
  +  int done = FALSE;
  +  int size, x2size, pinsize;
  +  int otherone;
  +  int bus_involved=FALSE;
  +
  +  if (whichone < 0 || whichone > 1) return;
  +  
  +  x = object->line->x[whichone];
  +  y = object->line->y[whichone];
  +
  +  type = CONN_ENDPOINT;
  +  
  +  cl_current = object->conn_list;
  +  while(cl_current != NULL && !done) {
  +    conn = (CONN *) cl_current->data;
  +   
  +    if (conn->x == x && conn->y == y) {
  +#if 0
  +      printf("type: %d x: %d y: %d cx: %d cy: %d\n", conn->type, x, y, conn->x, conn->y);
  +#endif
  +      switch(conn->type) {
  +        
  +        case(CONN_ENDPOINT):
  +          count++;
  +          if (conn->other_object &&
  +              ((object->type == OBJ_NET &&
  +               conn->other_object->type == OBJ_BUS) ||
  +              (object->type == OBJ_BUS &&
  +               conn->other_object->type == OBJ_NET))) {
  +            bus_involved=TRUE;
  +          }
  +          break;
  +
  +        case(CONN_MIDPOINT):
  +          type = CONN_MIDPOINT;
  +          done = TRUE;
  +          count = 0;
  +          if (conn->other_object &&
  +              ((object->type == OBJ_NET &&
  +                conn->other_object->type == OBJ_BUS) ||
  +               (object->type == OBJ_BUS &&
  +               conn->other_object->type == OBJ_NET))) {
  +            bus_involved=TRUE;
  +          }
  +          break;
  +      }
  +    }
  +
  +    cl_current = cl_current->next;
  +  }
  +
  +#if DEBUG
  +  printf("type: %d count: %d\n", type, count);
  +#endif
  +  
  +  size = SCREENabs(w_current, CUE_BOX_SIZE);
  +  x2size = 2 * size;
  +
  +  if (w_current->override_color != -1 ) {
  +    gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(w_current->override_color));
  +  } else {
  +    gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(w_current->net_endpoint_color));
  +  }
  +
  +  WORLDtoSCREEN(w_current, x, y, &screen_x, &screen_y);
  +
  +  switch(type) {
  +    
  +    case(CONN_ENDPOINT):
  +      if (object->type == OBJ_NET) { /* only nets have these cues */
  +        if (count < 1) { /* Didn't find anything connected there */
  +          gdk_draw_rectangle(w_current->window,
  +                             w_current->gc, TRUE,
  +                             screen_x - size,
  +                             screen_y - size,
  +                             x2size,
  +                             x2size);
  +          gdk_draw_rectangle(w_current->backingstore,
  +                             w_current->gc, TRUE,
  +                             screen_x - size,
  +                             screen_y - size,
  +                             x2size,
  +                             x2size);
  +        
  +        } else if (count >= 2) {
  +          /* draw circle */
  +
  +          if (bus_involved) {
  +            size = SCREENabs(w_current, CUE_CIRCLE_SMALL_SIZE);
  +          } else {
  +            size = SCREENabs(w_current, CUE_CIRCLE_LARGE_SIZE);
  +          }
  +          
  +          gdk_draw_arc(w_current->window, w_current->gc,
  +                       TRUE,
  +                       screen_x - size / 2,
  +                       screen_y - size / 2,
  +                       size, size, 0, FULL_CIRCLE);
  +          gdk_draw_arc(w_current->backingstore,
  +                       w_current->gc, TRUE,
  +                       screen_x - size / 2,
  +                       screen_y - size / 2,
  +                       size, size, 0, FULL_CIRCLE);
  +
  +        }
  +      } else if (object->type == OBJ_PIN) {
  +        /* Didn't find anything connected there */
  +        if (count < 1 && object->whichend == whichone) {
  +                  
  +          otherone = !whichone;
  +
  +          pinsize = SCREENabs(w_current, 10);
  +          if (w_current->pin_style == THICK ) {
  +            gdk_gc_set_line_attributes(w_current->gc, pinsize,
  +                                       GDK_LINE_SOLID,
  +                                       GDK_CAP_NOT_LAST,
  +                                       GDK_JOIN_MITER);
  +          }
  +
  +          if (object->line->y[whichone] == object->line->y[otherone]) {
  +            /* horizontal line */
  +            if (object->line->x[whichone] <= object->line->x[otherone]) {
  +              gdk_draw_line(w_current->window, w_current->gc,
  +                            screen_x, screen_y, screen_x + size, screen_y);
  +              gdk_draw_line(w_current->backingstore, w_current->gc,
  +                            screen_x, screen_y, screen_x + size, screen_y);
  +            } else {
  +              gdk_draw_line(w_current->window, w_current->gc,
  +                            screen_x, screen_y, screen_x - size, screen_y);
  +              gdk_draw_line(w_current->backingstore, w_current->gc,
  +                            screen_x, screen_y, screen_x - size, screen_y);
  +            }
  +          } else if (object->line->x[0] == object->line->x[1]) {
  +            /* vertical line */
  +            if (object->line->y[whichone] <= object->line->y[otherone]) {
  +              gdk_draw_line(w_current->window, w_current->gc,
  +                            screen_x, screen_y, screen_x, screen_y - size);
  +              gdk_draw_line(w_current->backingstore, w_current->gc,
  +                            screen_x, screen_y, screen_x, screen_y - size);
  +            } else {
  +              gdk_draw_line(w_current->window, w_current->gc,
  +                            screen_x, screen_y, screen_x, screen_y + size);
  +              gdk_draw_line(w_current->backingstore, w_current->gc,
  +                            screen_x, screen_y, screen_x, screen_y + size);
  +            }
  +          } else {
  +            /* angled line */
  +            /* not supporting rendering of que for angled pin for now. hack */
  +          }
  +
  +          if (w_current->pin_style == THICK ) {
  +            gdk_gc_set_line_attributes(w_current->gc, 0,
  +                                       GDK_LINE_SOLID,
  +                                       GDK_CAP_NOT_LAST,
  +                                       GDK_JOIN_MITER);
  +          }
  +        }
  +      }
  +      break;
  +
  +    case(CONN_MIDPOINT):
  +  
  +      /* draw circle */
  +      if (bus_involved) {
  +        size = SCREENabs(w_current, CUE_CIRCLE_SMALL_SIZE);
  +      } else {
  +        size = SCREENabs(w_current, CUE_CIRCLE_LARGE_SIZE);
  +      }
  +
  +      gdk_draw_arc(w_current->window, w_current->gc,
  +                   TRUE,
  +                   screen_x - size / 2,
  +                   screen_y - size / 2,
  +                   size, size, 0, FULL_CIRCLE);
  +      gdk_draw_arc(w_current->backingstore,
  +                   w_current->gc, TRUE,
  +                   screen_x - size / 2,
  +                   screen_y - size / 2,
  +                   size, size, 0, FULL_CIRCLE);
  +
  +      break;
  +
  +      /* here is where you draw bus rippers */
  +      
  +  }
  +  
  +}
  +
  +/*! \brief Lowlevel endpoint erase.
  + *  \par Function Description
  + *  This function erases OBJECT endpoints forceably.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] object     OBJECT to forceably erase endpoint from.
  + *  \param [in] whichone   Which endpoint to erase from OBJECT.
  + */
  +void o_cue_erase_lowlevel(TOPLEVEL *w_current, OBJECT *object, int whichone)
  +{
  +  int x, y, screen_x, screen_y;
  +  int size, x2size;
  +  
  +  x = object->line->x[whichone];
  +  y = object->line->y[whichone];
  +
  +  size = SCREENabs(w_current, CUE_BOX_SIZE);
  +  x2size = 2 * size;
  +
  +  gdk_gc_set_foreground(w_current->gc,
  +                        x_get_color(w_current->background_color));
  + 
  +  WORLDtoSCREEN(w_current, x, y, &screen_x, &screen_y);
  +  
  +  gdk_draw_rectangle(w_current->window,
  +                     w_current->gc, TRUE,
  +                     screen_x - size,
  +                     screen_y - size,
  +                     x2size,
  +                     x2size);
  +  gdk_draw_rectangle(w_current->backingstore,
  +                     w_current->gc, TRUE,
  +                     screen_x - size,
  +                     screen_y - size,
  +                     x2size,
  +                     x2size);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_draw_lowlevel_midpoints(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  int x, y, screen_x, screen_y;
  +  GList *cl_current;
  +  CONN *conn;
  +  int size;
  +
  +  if (w_current->override_color != -1 ) {
  +    gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(w_current->override_color));
  +  } else {
  +    gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(w_current->net_endpoint_color));
  +  }
  +  
  +  cl_current = object->conn_list;
  +  while(cl_current != NULL) {
  +    conn = (CONN *) cl_current->data;
  +
  +    switch(conn->type) {        
  +      case(CONN_MIDPOINT):
  +
  +        x = conn->x;
  +        y = conn->y;
  +          
  +        WORLDtoSCREEN(w_current, x, y, &screen_x, &screen_y);
  + 
  +        /* draw circle */
  +        if (conn->other_object &&
  +            ( (object->type == OBJ_BUS &&
  +               conn->other_object->type == OBJ_NET) ||
  +              (object->type == OBJ_NET &&
  +               conn->other_object->type == OBJ_BUS))) {
  +          size = SCREENabs(w_current, CUE_CIRCLE_SMALL_SIZE);
  +        } else {
  +          size = SCREENabs(w_current, CUE_CIRCLE_LARGE_SIZE);
  +        }
  +
  +        gdk_draw_arc(w_current->window, w_current->gc,
  +                     TRUE,
  +                     screen_x - size / 2,
  +                     screen_y - size / 2,
  +                     size, size, 0, FULL_CIRCLE);
  +        gdk_draw_arc(w_current->backingstore,
  +                     w_current->gc, TRUE,
  +                     screen_x - size / 2,
  +                     screen_y - size / 2,
  +                     size, size, 0, FULL_CIRCLE);
  +        break;
  +    }
  +   
  +
  +    cl_current = cl_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_draw_single(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  if (!object) {
  +    return;
  +  }
  +
  +  if (object->type != OBJ_NET && object->type != OBJ_PIN &&
  +      object->type != OBJ_BUS) {
  +        return;
  +      }
  +
  +  if (object->type != OBJ_PIN) {
  +    o_cue_draw_lowlevel(w_current, object, 0);
  +    o_cue_draw_lowlevel(w_current, object, 1);
  +    o_cue_draw_lowlevel_midpoints(w_current, object);
  +  } else {
  +    o_cue_draw_lowlevel(w_current, object, object->whichend);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_erase_single(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  if (!object) {
  +    return;
  +  }
  +
  +  if (object->type != OBJ_NET && object->type != OBJ_PIN &&
  +      object->type != OBJ_BUS)
  +  {
  +    return;
  +  }
  +
  +  if (object->type != OBJ_PIN) {
  +    o_cue_erase_lowlevel(w_current, object, 0);
  +    o_cue_erase_lowlevel(w_current, object, 1);
  +    w_current->override_color = w_current->background_color;
  +    o_cue_draw_lowlevel_midpoints(w_current, object);
  +    w_current->override_color = -1;
  +  } else {
  +    o_cue_erase_lowlevel(w_current, object, object->whichend);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_undraw(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  GList *cl_current;
  +  CONN *conn;
  +
  +  o_cue_erase_single(w_current, object);
  +
  +  cl_current = object->conn_list;
  +  while(cl_current != NULL) {
  +    conn = (CONN *) cl_current->data;
  +
  +    if (conn->other_object) {
  +      o_redraw_single(w_current, conn->other_object);
  +    }
  +
  +    cl_current = cl_current->next;
  +  }
  +
  +  o_redraw_single(w_current, object);
  +}
  +
  +/*! \brief Undraw complex OBJECT.
  + *  \par Function Description
  + *  This function undraws complex objects (pass in the toplevel object)
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] object     OBJECT to undraw.
  + */
  +void o_cue_undraw_complex(TOPLEVEL *w_current, OBJECT *object)
  +{
  +  GList *cl_current;
  +  CONN *conn;
  +  OBJECT *o_current;
  +
  +  if (object->type != OBJ_COMPLEX && object->type != OBJ_PLACEHOLDER) {
  +    return;
  +  }
  +
  +  o_current = object->complex->prim_objs;
  +  while(o_current != NULL) {
  +
  +    if (o_current->type == OBJ_PIN || o_current->type == OBJ_NET ||
  +        o_current->type == OBJ_BUS) {
  +      
  +      o_cue_erase_single(w_current, o_current);
  +      
  +      cl_current = o_current->conn_list;
  +      while(cl_current != NULL) {
  +        conn = (CONN *) cl_current->data;
  +
  +        if (conn->other_object) {
  +          o_redraw_single(w_current, conn->other_object);
  +        }
  +
  +        cl_current = cl_current->next;
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +  o_redraw_single(w_current, object);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_draw_list(TOPLEVEL *w_current, GList *object_list)
  +{
  +  OBJECT *object;
  +  GList *ol_current;
  +
  +  ol_current = object_list;
  +  while(ol_current != NULL) {
  +    object = (OBJECT *) ol_current->data;
  +
  +    o_cue_draw_single(w_current, object);
  +    
  +    ol_current = ol_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_undraw_list(TOPLEVEL *w_current, GList *object_list)
  +{
  +  OBJECT *object;
  +  GList *ol_current;
  +
  +  ol_current = object_list;
  +  while(ol_current != NULL) {
  +    object = (OBJECT *) ol_current->data;
  +
  +    o_cue_undraw(w_current, object);
  +    
  +    ol_current = ol_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_cue_undraw_objects(TOPLEVEL *w_current, OBJECT *list)
  +{
  +  OBJECT *o_current;
  +
  +  o_current = list;
  +  while(o_current != NULL) {
  +
  +    if (o_current->type == OBJ_PIN || o_current->type == OBJ_NET ||
  +        o_current->type == OBJ_BUS) {
  +      o_cue_undraw(w_current, o_current);
  +    }
  +    
  +    o_current = o_current->next;
  +  }
  +
  +}
  
  
  
  1.21      +238 -171  eda/geda/gaf/gschem/src/o_delete.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_delete.c
  ===================================================================
  RCS file: o_delete.c
  diff -N o_delete.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_delete.c	14 Jul 2006 02:23:55 -0000	1.21
  @@ -0,0 +1,319 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_delete_net(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  int removing_sel_save;
  +  GList *other_objects = NULL;
  +
  +  o_cue_undraw(w_current, obj);
  +  o_net_erase(w_current, obj);
  +  o_line_erase_grips(w_current, obj);
  +
  +  other_objects = s_conn_return_others(other_objects, obj);
  +       
  +  removing_sel_save = w_current->REMOVING_SEL;
  +  w_current->REMOVING_SEL = 1;
  +  s_delete(w_current, obj);
  +  w_current->REMOVING_SEL = removing_sel_save;
  +
  +  w_current->page_current->object_tail =
  +  (OBJECT *) return_tail(w_current->page_current->object_head);
  +
  +  o_cue_undraw_list(w_current, other_objects);
  +  o_cue_draw_list(w_current, other_objects);
  +  g_list_free(other_objects);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_delete_bus(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  int removing_sel_save;
  +  GList *other_objects = NULL;
  +        
  +  o_cue_undraw(w_current, obj);
  +  o_bus_erase(w_current, obj);
  +  o_line_erase_grips(w_current, obj);
  +
  +  other_objects = s_conn_return_others(other_objects, obj);
  +
  +  removing_sel_save = w_current->REMOVING_SEL;
  +  w_current->REMOVING_SEL = 1;
  +  s_delete(w_current, obj);
  +  w_current->REMOVING_SEL = removing_sel_save;
  +
  +  w_current->page_current->object_tail =
  +  (OBJECT *) return_tail(w_current->page_current->object_head);
  +
  +  o_cue_undraw_list(w_current, other_objects);
  +  o_cue_draw_list(w_current, other_objects);
  +  g_list_free(other_objects);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void o_delete_pin(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  GList *other_objects = NULL;
  +        
  +  o_cue_undraw(w_current, obj);
  +  o_pin_erase(w_current, obj);
  +  o_line_erase_grips(w_current, obj);
  +        
  +  other_objects = s_conn_return_others(other_objects, obj);
  +        
  +  s_delete(w_current, obj);
  +  w_current->page_current->object_tail =
  +  (OBJECT *) return_tail(w_current->page_current->object_head);
  +
  +  o_cue_undraw_list(w_current, other_objects);
  +  o_cue_draw_list(w_current, other_objects);
  +  g_list_free(other_objects);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_delete_complex(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  GList *other_objects = NULL;
  +
  +  o_cue_undraw_complex(w_current, obj);
  +  o_complex_erase(w_current, obj);
  +
  +  other_objects = s_conn_return_complex_others(other_objects, obj);
  +
  +  o_complex_delete(w_current, obj);
  +
  +  /*! \todo special case hack no return_tail. why? */
  +  o_cue_undraw_list(w_current, other_objects);
  +  o_cue_draw_list(w_current, other_objects);
  +  g_list_free(other_objects);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void o_delete_line(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  o_line_erase(w_current, obj);
  +  o_line_erase_grips(w_current, obj);
  +  
  +  s_delete(w_current, obj);
  +  w_current->page_current->object_tail =
  +    (OBJECT *) return_tail(w_current->page_current->object_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void o_delete_box(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  o_box_erase(w_current, obj);
  +  o_box_erase_grips(w_current, obj);
  +
  +  s_delete(w_current, obj);
  +  w_current->page_current->object_tail =
  +  (OBJECT *) return_tail(w_current->page_current->object_head);
  +}
  +
  +#ifndef HAS_GTK12
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void o_delete_picture(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  o_picture_erase(w_current, obj);
  +  o_picture_erase_grips(w_current, obj);
  +
  +  s_delete(w_current, obj);
  +  w_current->page_current->object_tail =
  +  (OBJECT *) return_tail(w_current->page_current->object_head);
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void o_delete_circle(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +	o_circle_erase(w_current, obj);
  +	o_circle_erase_grips(w_current, obj);
  +
  +	s_delete(w_current, obj);
  +
  +	w_current->page_current->object_tail =
  +		(OBJECT *) return_tail(w_current->page_current->object_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_delete_text(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  o_text_erase(w_current, obj);
  +
  +  s_delete(w_current, obj);
  +  w_current->page_current->object_tail =
  +  (OBJECT *) return_tail(w_current->page_current->object_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void o_delete_arc(TOPLEVEL *w_current, OBJECT *obj)
  +{
  +  o_arc_erase(w_current, obj);
  +
  +  s_delete(w_current, obj);
  +  w_current->page_current->object_tail =
  +  (OBJECT *) return_tail(w_current->page_current->object_head);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_delete(TOPLEVEL *w_current)
  +{
  +  SELECTION *s_current = NULL;
  +  OBJECT *object = NULL;
  +
  +  object = o_select_return_first_object(w_current);
  +  if (object == NULL) {
  +    /*! \todo error condition */
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    return;
  +  }
  +
  +
  +  /* skip over head node */
  +  s_current = w_current->page_current->selection2_head->next;
  +
  +  while(s_current != NULL) {
  +
  +    object = s_current->selected_object;
  +    if (object == NULL) {
  +      fprintf(stderr, 
  +              _("ERROR: NULL object in o_delete_end!\n"));
  +      exit(-1);
  +    }
  +
  +    switch(object->type) {
  +      case(OBJ_LINE):
  +        o_delete_line(w_current, object);
  +        break;
  +
  +      case(OBJ_NET):
  +        o_delete_net(w_current, object);
  +        break;
  +
  +      case(OBJ_BUS):
  +        o_delete_bus(w_current, object);
  +        break;
  +
  +      case(OBJ_BOX):
  +        o_delete_box(w_current, object);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +        o_delete_picture(w_current, object);
  +#endif
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_delete_circle(w_current, object);
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +      case(OBJ_PLACEHOLDER):
  +        o_delete_complex(w_current, object);
  +        break;
  +
  +      case(OBJ_PIN):
  +        o_delete_pin(w_current, object);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_delete_text(w_current, object);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_delete_arc(w_current, object);
  +        break;
  +    }
  +    s_current = s_current->next;
  +  }
  +
  +  w_current->inside_action = 0;
  +
  +  o_selection_destroy_all(w_current->page_current->selection2_head);
  +  w_current->page_current->selection2_head = o_selection_new_head();
  +  w_current->page_current->CHANGED=1;
  +
  +  /* no longer needed */
  +  /* o_redraw(w_current, w_current->page_current->object_head);*/
  +
  +  o_undo_savestate(w_current, UNDO_ALL);
  +  i_update_menus(w_current);
  +}
  
  
  
  1.4       +129 -61   eda/geda/gaf/gschem/src/o_find.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_find.c
  ===================================================================
  RCS file: o_find.c
  diff -N o_find.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_find.c	14 Jul 2006 02:23:55 -0000	1.4
  @@ -0,0 +1,169 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <math.h>
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/x_states.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gboolean o_find_object(TOPLEVEL *w_current, int screen_x, int screen_y,
  +		       gboolean change_selection)
  +{
  +  OBJECT *o_current=NULL;
  +  gboolean object_found = FALSE;
  +
  +  if (w_current->page_current->object_lastplace == NULL) {
  +    o_current = w_current->page_current->object_head;
  +  } else {
  +    o_current = w_current->page_current->object_lastplace;
  +  }
  +
  +  /* do first search */
  +  while (o_current != NULL) {
  +    if (inside_region(o_current->left, o_current->top,
  +                      o_current->right, o_current->bottom, 
  +                      screen_x, screen_y)) {
  +      if (o_current->sel_func != NULL &&
  +	  o_current->type != OBJ_HEAD &&
  +	  (o_current->visibility == VISIBLE ||
  +	   (o_current->visibility == INVISIBLE &&
  +	    w_current->show_hidden_text))) {
  +	if (change_selection) {
  +	  (*o_current->sel_func)(
  +				 w_current, o_current, 
  +				 SINGLE, 0); /* 0 is count */
  +	}
  +	object_found = TRUE;
  +	w_current->page_current-> object_lastplace =
  +	  o_current->next;
  +	i_update_menus(w_current);
  +	return object_found;
  +      }
  +    }
  +    
  +    o_current = o_current->next;
  +  } 
  +
  +#if DEBUG
  +  printf("SEARCHING AGAIN\n");
  +#endif
  +
  +  /* now search again since we didn't find anything starting at start
  +     just in case we started last time at object_lastplace */
  +  o_current = w_current->page_current->object_head;
  +  while (o_current != NULL && 
  +         o_current != w_current->page_current->object_lastplace) {
  +    if (inside_region(o_current->left, o_current->top,
  +                      o_current->right, o_current->bottom, 
  +                      screen_x, screen_y)) {
  +      
  +      if (o_current->sel_func != NULL &&
  +          o_current->type != OBJ_HEAD &&
  +          (o_current->visibility == VISIBLE ||
  +           (o_current->visibility == INVISIBLE &&
  +            w_current->show_hidden_text))) {
  +	if (change_selection) {
  +	  /* 0 is count */
  +	  (*o_current->sel_func)(w_current, o_current, SINGLE, 0);
  +	}
  +	w_current->page_current->object_lastplace = o_current;
  + 	object_found = TRUE;
  +        
  +        i_update_menus(w_current);
  +        return object_found;
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +  /* didn't find anything.... reset lastplace */
  +  w_current->page_current->object_lastplace = NULL;
  +
  +  /* deselect everything only if shift key isn't pressed and 
  +     the caller allows it */	
  +  if (change_selection && (!w_current->SHIFTKEY)) {
  +
  +#if DEBUG
  +    o_selection_print_all( w_current->page_current->selection2_head);
  +#endif
  +    o_select_run_hooks(w_current, NULL, 2); 
  +    o_selection_remove_most(w_current, 
  +                            w_current->page_current->selection2_head);
  +  }
  +
  +  i_update_menus(w_current);
  +  
  +  return (object_found);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gboolean o_find_selected_object(TOPLEVEL *w_current,
  +				int screen_x, int screen_y)
  +{
  +  OBJECT *o_current=NULL;
  +  SELECTION *s_current;
  +
  +  g_assert (w_current->page_current->selection2_head != NULL);
  +
  +  /* Skip the head node */
  +  s_current = w_current->page_current->selection2_head->next;
  +  /* do first search */
  +  while (s_current != NULL) {
  +    o_current = s_current->selected_object;
  +    if (inside_region(o_current->left, o_current->top,
  +                      o_current->right, o_current->bottom, 
  +                      screen_x, screen_y)) {
  +
  +#if DEBUG
  +      printf("o_find_selected_object:\n");
  +      printf("Object bounds:\n\tL: %i\tR: %i\n\tT: %i\tB: %i.\n",
  +	     o_current->left, o_current->right, o_current->top, o_current->bottom);
  +      printf("Screen pointer at: (%i,%i)\n", screen_x, screen_y);
  +#endif
  +      if (o_current->sel_func != NULL &&
  +	  o_current->type != OBJ_HEAD &&
  +	  (o_current->visibility == VISIBLE ||
  +	   (o_current->visibility == INVISIBLE &&
  +	    w_current->show_hidden_text))) {
  +	return TRUE;
  +      }
  +    }
  +    
  +    s_current = s_current->next;
  +  } 
  +
  +  return (FALSE);
  +}
  
  
  
  1.9       +1722 -1033eda/geda/gaf/gschem/src/o_grips.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_grips.c
  ===================================================================
  RCS file: o_grips.c
  diff -N o_grips.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_grips.c	14 Jul 2006 02:23:55 -0000	1.9
  @@ -0,0 +1,1821 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* Kazu on July 16, 1999 - Added these macros to simplify the code */
  +#define GET_BOX_WIDTH(w)                        \
  +        abs((w)->last_x - (w)->start_x)
  +#define GET_BOX_HEIGHT(w)                       \
  +	        abs((w)->last_y - (w)->start_y)
  +#define GET_BOX_LEFT(w)                         \
  +	        min((w)->start_x, (w)->last_x);
  +#define GET_BOX_TOP(w)                          \
  +	        min((w)->start_y, (w)->last_y);
  +
  +#define GET_PICTURE_WIDTH(w)			\
  +	abs((w)->last_x - (w)->start_x) 
  +#define GET_PICTURE_HEIGHT(w)			\
  +	(w)->pixbuf_wh_ratio == 0 ? 0 : abs((w)->last_x - (w)->start_x)/(w)->pixbuf_wh_ratio
  +#define GET_PICTURE_LEFT(w)				\
  +	min((w)->start_x, (w)->last_x);
  +#define GET_PICTURE_TOP(w)				\
  +	(w)->start_y < (w)->last_y ? (w)->start_y  : \
  +                                     (w)->start_y-abs((w)->last_x - (w)->start_x)/(w)->pixbuf_wh_ratio;
  +
  +/*! \brief
  + *  This variable holds the identifier of the grip currently under
  + *  modification. Its range of values depends on the type of object.
  + */
  +static int whichone_changing = -1;
  +/*! \brief
  + *  This variable holds a pointer on the object under modification.
  + */
  +static OBJECT *object_changing;
  +
  +/*! \brief Check if point is inside grip.
  + *  \par Function Description
  + *  This function is used to determine if the (<B>x</B>,<B>y</B>) point is
  + *  inside a grip of one of the selected object on the current sheet.
  + *  The selected object are in a list starting at
  + *  <B>w_current->page_current->selection2_head</B>.
  + *  The <B>x</B> and <B>y</B> parameters are in screen units.
  + *  If the point is inside one grip, a pointer on the object it belongs to is
  + *  returned and <B>*whichone</B> is set according to the position of the grip
  + *  on the object.
  + *  Else, <B>*whichone</B> is unchanged and the function returns <B>NULL</B>.
  + *
  + *  A specific search function is provided for every kind of graphical object.
  + *  The list of selected object is covered : each object is tested with the
  + *  appropriate function.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  x          Current x coordinate of pointer in screen units.
  + *  \param [in]  y          Current y coordinate of pointer in screen units.
  + *  \param [out] whichone   Which grip point is selected.
  + *  \return Pointer to OBJECT the grip is on, NULL otherwise.
  + */
  +OBJECT *o_grips_search(TOPLEVEL *w_current, int x, int y, int *whichone)
  +{
  +  OBJECT *object=NULL;
  +  OBJECT *found=NULL;
  +  SELECTION *s_current;
  +  int size, x2size;
  +	
  +  if (!whichone) {
  +    return(NULL);
  +  }
  +
  +  /* get the size of the grip according to zoom level */
  +  size = o_grips_size(w_current);
  +  /* size is half the width of a grip, x2size is full width */
  +  x2size = size * 2;
  +	
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +  while (s_current) {
  +    if (s_current->selected_object) {
  +      object = s_current->selected_object;
  +      switch(object->type) {
  +				
  +        case(OBJ_ARC):
  +          /* check the grips of the arc object */
  +          found = o_grips_search_arc(w_current, object,
  +                                     x, y, size, whichone);
  +          if(found != NULL) return found;
  +          break;
  +				
  +        case(OBJ_BOX):
  +          /* check the grips of the box object */
  +          found = o_grips_search_box(w_current, object,
  +                                     x, y, size, whichone);
  +          if(found != NULL) return found;
  +          break;
  +		  
  +        case(OBJ_PICTURE):
  +          /* check the grips of the picture object */
  +#ifndef HAS_GTK12
  +          found = o_grips_search_picture(w_current, object,
  +                                         x, y, size, whichone);
  +          if(found != NULL) return found;
  +#endif
  +          break;
  +		  
  +        case(OBJ_CIRCLE):
  +          /* check the grips of the circle object */
  +          found = o_grips_search_circle(w_current, object,
  +                                        x, y, size, whichone);
  +          if(found != NULL) return found;
  +          break;
  +			
  +        case(OBJ_LINE):
  +        case(OBJ_PIN):
  +        case(OBJ_NET):
  +        case(OBJ_BUS):
  +          /* check the grips of the line object */
  +          /* the function is the same for line, pin, net, bus */
  +          found = o_grips_search_line(w_current, object,
  +                                      x, y, size, whichone);
  +          if(found != NULL) return found;
  +          break;
  +
  +#if 0 
  +      /* This code is wrong.  Continue searching even if the object */
  +      /* does not have grips */
  +        default:
  +          /* object type is unknown : error condition */
  +          return NULL;
  +#endif
  +      }
  +    }
  +    s_current = s_current->next;	
  +  }
  +	
  +  return(NULL);
  +}
  +
  +/*! \brief Check if pointer is inside arc grip.
  + *  \par Function Description
  + *  This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>) is
  + *  inside one of the grips of an <B>o_current</B> pointed arc object. If so
  + *  the <B>whichone</B> pointed integer is set to the number of this grip and
  + *  the return pointer is a pointer on this object. If the point is not
  + *  inside a grip the function returns a NULL pointer and the <B>whichone</B>
  + *  pointed integer is unset.
  + *
  + *  An arc object has three grips :
  + *  <DL>
  + *    <DT>*</DT><DD>one at the center of the arc. This grip is used to modify
  + *                  the radius of the arc. If this one is selected, the
  + *                  <B>whichone</B> pointed integer is set to <B>ARC_RADIUS</B>.
  + *    <DT>*</DT><DD>one at one end of the arc. It corresponds to the starting
  + *                  angle of the arc. If this one is selected, the
  + *                  <B>whichone</B> pointed integer is set to <B>ARC_START_ANGLE</B>.
  + *    <DT>*</DT><DD>one at the other end of the arc. It corresponds to the
  + *                  ending angle of the arc. If this one is selected, the
  + *                  <B>whichone</B> pointed integer is set to <B>ARC_END_ANGLE</B>.
  + *  </DL>
  + *
  + *  The <B>x</B> and <B>y</B> parameters are in screen units.
  + *
  + *  The <B>size</B> parameter is the width (and height) of the square
  + *  representing a grip in screen unit.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Arc OBJECT to check.
  + *  \param [in]  x          Current x coordinate of pointer in screen units.
  + *  \param [in]  y          Current y coordinate of pointer in screen units.
  + *  \param [in]  size       Half the width of the grip square in screen units.
  + *  \param [out] whichone   Which grip point is selected.
  + *  \return Pointer to OBJECT the grip is on, NULL otherwise.
  + */
  +OBJECT *o_grips_search_arc(TOPLEVEL *w_current, OBJECT *o_current,
  +			   int x, int y, int size, int *whichone)
  +{
  +  int centerx, centery, radius, start_angle, end_angle;
  +  int left, top, right, bottom;
  +  int x2size;
  +  double tmp;
  +
  +  centerx     = o_current->arc->screen_x;
  +  centery     = o_current->arc->screen_y;
  +  radius      = o_current->arc->screen_width / 2;
  +  start_angle = o_current->arc->start_angle;
  +  end_angle   = o_current->arc->end_angle;
  +
  +  /* width/height of the grip */
  +  x2size = 2 * size;
  +
  +  /* check the grip on the center of the arc */
  +  left   = centerx - size;
  +  top    = centery - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = ARC_RADIUS;
  +    return(o_current);
  +  }
  +
  +  /* check the grip at the start angle of the arc */
  +  tmp = ((double) start_angle) * M_PI / 180;
  +  left   = centerx + radius * cos(tmp) - size;
  +  top    = centery - radius * sin(tmp) - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = ARC_START_ANGLE;
  +    return(o_current);
  +  }
  +
  +  /* check the grip at the end angle of the arc */
  +  tmp = ((double) start_angle + end_angle) * M_PI / 180;
  +  left   = centerx + radius * cos(tmp) - size;
  +  top    = centery - radius * sin(tmp) - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = ARC_END_ANGLE;
  +    return(o_current);
  +  }
  +
  +  return NULL;
  +}
  +
  +/*! \brief Check if pointer is inside box grip.
  + *  \par Function Description
  + *  This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>) is
  + *  inside one of the grips of the <B>o_current</B> pointed box object.
  + *  If so, the <B>whichone</B> pointed integer is set to the identifier of
  + *  this grip and the returned pointer is a pointer on this object. 
  + *  If the point is not inside a grip the function returns a NULL pointer
  + *  and the <B>whichone</B> pointed integer is unset.
  + *
  + *  A box object has four grips : one at each corner of the box. The
  + *  identifiers of each corner are <B>BOX_UPPER_LEFT</B>,
  + *  <B>BOX_UPPER_RIGHT</B>, <B>BOX_LOWER_LEFT</B> and <B>BOX_LOWER_RIGHT</B>.
  + *
  + *  The <B>x</B> and <B>y</B> parameters are in screen units.
  + *
  + *  The <B>size</B> parameter is half the width (and half the height) of
  + *  the square representing a grip in screen unit.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Box OBJECT to check.
  + *  \param [in]  x          Current x coordinate of pointer in screen units.
  + *  \param [in]  y          Current y coordinate of pointer in screen units.
  + *  \param [in]  size       Half the width of the grip square in screen units.
  + *  \param [out] whichone   Which grip point is selected.
  + *  \return Pointer to OBJECT the grip is on, NULL otherwise.
  + */
  +OBJECT *o_grips_search_box(TOPLEVEL *w_current, OBJECT *o_current,
  +			   int x, int y, int size, int *whichone)
  +{
  +  int left, right, top, bottom;
  +  int x2size;
  +
  +  /* width/height of the grip */
  +  x2size = 2 * size;
  +
  +  /* inside upper left grip ? */
  +  left   = o_current->box->screen_upper_x - size;
  +  top    = o_current->box->screen_upper_y - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = BOX_UPPER_LEFT;
  +    return(o_current);
  +  }
  +
  +  /* inside lower right grip ? */
  +  left   = o_current->box->screen_lower_x - size;
  +  top    = o_current->box->screen_lower_y - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = BOX_LOWER_RIGHT;
  +    return(o_current);
  +  }
  +
  +  /* inside upper right grip ? */
  +  left   = o_current->box->screen_lower_x - size;
  +  top    = o_current->box->screen_upper_y - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = BOX_UPPER_RIGHT;
  +    return(o_current);
  +  }
  +
  +  /* inside lower left grip ? */
  +  left   = o_current->box->screen_upper_x - size;
  +  top    = o_current->box->screen_lower_y - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = BOX_LOWER_LEFT;
  +    return(o_current);
  +  }
  +
  +  return NULL;
  +}
  +
  +#ifndef HAS_GTK12
  +/*! \brief Check if pointer is inside picture grip.
  + *  \par Function Description
  + *  This function checks if the pointer event occuring at (<B>x</B>,<B>y</B>)
  + *  is inside one of the grips of the <B>o_current</B> pointed picture object. 
  + *  If so, the <B>whichone</B> pointed integer is set to the identifier of
  + *  this grip and the returned pointer is a pointer on this object. 
  + *  If the point is not inside a grip the function returns a NULL pointer
  + *  and the <B>whichone</B> pointed integer is unset.
  + *
  + *  A picture object has four grips : one at each corner of the picture.
  + *  The identifiers of each corner are #PICTURE_UPPER_LEFT,
  + *  #PICTURE_UPPER_RIGHT, #PICTURE_LOWER_LEFT and
  + *  #PICTURE_LOWER_RIGHT.
  + *
  + *  The <B>x</B> and <B>y</B> parameters are in screen units.
  + *
  + *  The <B>size</B> parameter is half the width (and half the height) of the
  + *  square representing a grip in screen unit.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Picture OBJECT to check.
  + *  \param [in]  x          Current x coordinate of pointer in screen units.
  + *  \param [in]  y          Current y coordinate of pointer in screen units.
  + *  \param [in]  size       Half the width of the grip square in screen units.
  + *  \param [out] whichone   Which grip point is selected.
  + *  \return Pointer to OBJECT the grip is on, NULL otherwise.
  + */
  +OBJECT *o_grips_search_picture(TOPLEVEL *w_current, OBJECT *o_current,
  +			       int x, int y, int size, int *whichone)
  +{
  +  int left, right, top, bottom;
  +  int x2size;
  +
  +  /* width/height of the grip */
  +  x2size = 2 * size;
  +
  +  /* inside upper left grip ? */
  +  left   = o_current->picture->screen_upper_x - size;
  +  top    = o_current->picture->screen_upper_y - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = PICTURE_UPPER_LEFT;
  +    return(o_current);
  +  }
  +
  +  /* inside lower right grip ? */
  +  left   = o_current->picture->screen_lower_x - size;
  +  top    = o_current->picture->screen_lower_y - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = PICTURE_LOWER_RIGHT;
  +    return(o_current);
  +  }
  +
  +  /* inside upper right grip ? */
  +  left   = o_current->picture->screen_lower_x - size;
  +  top    = o_current->picture->screen_upper_y - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = PICTURE_UPPER_RIGHT;
  +    return(o_current);
  +  }
  +
  +  /* inside lower left grip ? */
  +  left   = o_current->picture->screen_upper_x - size;
  +  top    = o_current->picture->screen_lower_y - size;
  +  right  = left + x2size;
  +  bottom = top  + x2size;
  +  if (inside_region(left, top, right, bottom, x, y)) {
  +    *whichone = PICTURE_LOWER_LEFT;
  +    return(o_current);
  +  }
  +
  +  return NULL;
  +}
  +#endif
  +
  +/*! \brief Check if pointer is inside circle grip.
  + *  \par Function Description
  + *  This function determines if the (<B>x</B>,<B>y</B>) point is inside one of
  + *  the grip of the circle object <B>o_current</B>.
  + *  It computes the area covered by each grip and check if (<B>x</B>,<B>y</B>)
  + *  is in one of these areas.
  + *  If the event occured in one of the grip, a pointer on the object is
  + *  returned and <B>*whichone</B> is set to the identifier of the grip.
  + *  If not, the function returns a <B>NULL</B> pointer and <B>*whichone</B>
  + *  is unchanged.
  + *
  + *  The parameter <B>size</B> is half the size of the grip in screen units.
  + *
  + *  A circle has only one grip on the lower right corner of the box it
  + *  is inscribed in. Moving this grip change the radius of the circle.
  + *  The identifier of this grip is <B>CIRCLE_RADIUS</B>.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Circle OBJECT to check.
  + *  \param [in]  x          Current x coordinate of pointer in screen units.
  + *  \param [in]  y          Current y coordinate of pointer in screen units.
  + *  \param [in]  size       Half the width of the grip square in screen units.
  + *  \param [out] whichone   Which grip point is selected.
  + *  \return Pointer to OBJECT the grip is on, NULL otherwise.
  + */
  +OBJECT *o_grips_search_circle(TOPLEVEL *w_current, OBJECT *o_current,
  +			      int x, int y, int size, int *whichone)
  +{
  +	int left, top, right, bottom;
  +	int x1, y1;
  +	int x2size;
  +	
  +	/* width/height of the grip */
  +	x2size = 2 * size;
  +
  +        /* check the grip for radius */	
  +	x1 = o_current->circle->screen_x + o_current->circle->screen_radius;
  +	y1 = o_current->circle->screen_y + o_current->circle->screen_radius;
  +	left   = x1 - size;
  +	top    = y1 - size;
  +	right  = left + x2size;
  +	bottom = top  + x2size;
  +	if (inside_region(left, top, right, bottom, x, y)) {
  +		/* printf("found something 0!\n"); */
  +		*whichone = CIRCLE_RADIUS;
  +		return(o_current);
  +	}
  +
  +	return NULL;
  +}
  +
  +/*! \brief Check if pointer is inside line grip.
  + *  \par Function Description
  + *  This function determines if the (<B>x</B>,<B>y</B>) point is inside one of
  + *  the grip of the line object <B>o_current</B>.
  + *  It computes the area covered by each grip and check if (<B>x</B>,<B>y</B>)
  + *  is in one of these areas. 
  + *  If the event occured in one of its grip, a pointer on the object is
  + *  returned and <B>*whichone</B> is set to the identifier of the grip. If not,
  + *  the function returns <B>NULL</B> pointer and <B>*whichone</B> is unchanged.
  + *
  + *  The parameter <B>size</B> is half the size of the grip in screen units.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Line OBJECT to check.
  + *  \param [in]  x          Current x coordinate of pointer in screen units.
  + *  \param [in]  y          Current y coordinate of pointer in screen units.
  + *  \param [in]  size       Half the width of the grip square in screen units.
  + *  \param [out] whichone   Which grip point is selected.
  + *  \return Pointer to OBJECT the grip is on, NULL otherwise.
  + */
  +OBJECT *o_grips_search_line(TOPLEVEL *w_current, OBJECT *o_current,
  +			    int x, int y, int size, int *whichone)
  +{
  +	int left, top, right, bottom;
  +	int x2size;
  +
  +	/* width/height of the grip */
  +	x2size = 2 * size;
  +
  +	/* check the grip on the end of line 1 */
  +	left = o_current->line->screen_x[LINE_END1] - size;
  +	top  = o_current->line->screen_y[LINE_END1] - size;
  +	right  = left + x2size;
  +	bottom = top  + x2size;
  +	if (inside_region(left, top, right, bottom, x, y)) {
  +		*whichone = LINE_END1;
  +		return(o_current);
  +	}
  +
  +	/* check the grip on the end of line 2 */
  +	left = o_current->line->screen_x[LINE_END2] - size;
  +	top  = o_current->line->screen_y[LINE_END2] - size;
  +	right  = left + x2size;
  +	bottom = top  + x2size;
  +	if (inside_region(left, top, right, bottom, x, y)) {
  +		*whichone = LINE_END2;
  +		return(o_current);
  +	}
  +
  +	return NULL;
  +}
  +
  +/*! \brief Start process of modifiying one grip.
  + *  \par Function Description
  + *  This function starts the process of modifying one grip of an object
  + *  on the current sheet. The event occured in (<B>x</B>,<B>y</B>) in screen unit.
  + *  If this position is related to a grip of an object, the function
  + *  prepares the modification of this grip thanks to the user input.
  + *
  + *  The function returns <B>FALSE</B> if an error occured of if no grip
  + *  have been found under (<B>x</B>,<B>y</B>). It returns <B>TRUE</B> if a grip
  + *  has been found and modification of the object has been started.
  + *
  + *  If a grip has been found, this function modifies the global variables
  + *  <B>whichone_changing</B> and <B>object_changing</B> with respectively the
  + *  identifier of the grip and the object it belongs to.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  x          Current x coordinate of pointer in screen units.
  + *  \param [in]  y          Current y coordinate of pointer in screen units.
  + *  \return FALSE if an error occurred or no grip was found, TRUE otherwise.
  + */
  +int o_grips_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  OBJECT *object;
  +  int whichone;
  +	
  +  if (w_current->draw_grips == FALSE) {
  +    return(FALSE);
  +  }
  +
  +  /* search if there is a grip on a selected object at (x,y) */
  +  object = o_grips_search(w_current, x, y, &whichone);
  +  if (object) {
  +    /* there is one */
  +    /* depending on its type, start the modification process */
  +    switch(object->type) {
  +      case(OBJ_ARC):
  +	/* start the modification of a grip on an arc */
  +        o_grips_start_arc(w_current, object, x, y, whichone);
  +				
  +        whichone_changing = whichone;
  +        object_changing = object;
  +        return(TRUE);
  +        break;
  +
  +      case(OBJ_BOX):
  +	/* start the modification of a grip on a box */
  +        o_grips_start_box(w_current, object, x, y, whichone);
  +				
  +        whichone_changing = whichone;
  +        object_changing = object;
  +        return(TRUE);
  +        break;
  +				
  +      case(OBJ_PICTURE):
  +	/* start the modification of a grip on a picture */
  +#ifndef HAS_GTK12
  +        o_grips_start_picture(w_current, object, x, y, whichone);
  +				
  +        whichone_changing = whichone;
  +        object_changing = object;
  +        return(TRUE);
  +#endif
  +        break;
  +				
  +      case(OBJ_CIRCLE):
  +	/* start the modification of a grip on a circle */
  +        o_grips_start_circle(w_current, object, x, y, whichone);
  +				
  +        whichone_changing = whichone;
  +        object_changing = object;
  +        return(TRUE);
  +        break;
  +			
  +      case(OBJ_LINE):
  +	/* start the modification of a grip on a line */
  +        o_grips_start_line(w_current, object, x, y, whichone);
  +				
  +        whichone_changing = whichone;
  +        object_changing = object;
  +        return(TRUE);
  +        break;
  +
  +      case(OBJ_NET): 
  +        w_current->last_drawb_mode = -1;
  +        w_current->last_x = object->line->screen_x[whichone];
  +        w_current->last_y = object->line->screen_y[whichone];
  +        w_current->start_x = object->line->screen_x[!whichone];
  +        w_current->start_y = object->line->screen_y[!whichone];
  +				
  +        o_net_erase(w_current, object);
  +        gdk_gc_set_foreground(w_current->xor_gc, 
  +                              x_get_darkcolor(w_current->select_color) );
  +        gdk_draw_line(w_current->window, w_current->xor_gc, 
  +                      w_current->start_x, w_current->start_y, 
  +                      w_current->last_x, w_current->last_y);
  +        o_line_erase_grips(w_current, object);
  +				
  +        whichone_changing = whichone;
  +        object_changing = object;
  +        gdk_gc_set_foreground(w_current->gc, 
  +                              x_get_color(w_current->background_color)); 
  +        return(TRUE);
  +				
  +        break; 
  +				
  +      case(OBJ_PIN): 
  +				
  +        w_current->last_drawb_mode = -1;
  +        w_current->last_x = object->line->screen_x[whichone];
  +        w_current->last_y = object->line->screen_y[whichone];
  +        w_current->start_x = object->line->screen_x[!whichone];
  +        w_current->start_y = object->line->screen_y[!whichone];
  +				
  +        o_pin_erase(w_current, object);
  +        gdk_gc_set_foreground(w_current->xor_gc, 
  +                              x_get_darkcolor(w_current->select_color) );
  +        gdk_draw_line(w_current->window, w_current->xor_gc, 
  +                      w_current->start_x, w_current->start_y, 
  +                      w_current->last_x, w_current->last_y);
  +        o_line_erase_grips(w_current, object);
  +				
  +        whichone_changing = whichone;
  +        object_changing = object;
  +        return(TRUE);
  +				
  +        break; 
  +				
  +      case(OBJ_BUS): 
  +        w_current->last_drawb_mode = -1;
  +        w_current->last_x = object->line->screen_x[whichone];
  +        w_current->last_y = object->line->screen_y[whichone];
  +        w_current->start_x = object->line->screen_x[!whichone];
  +        w_current->start_y = object->line->screen_y[!whichone];
  +				
  +        o_bus_erase(w_current, object);
  +        gdk_gc_set_foreground(w_current->xor_gc, 
  +                              x_get_darkcolor(w_current->select_color) );
  +        gdk_draw_line(w_current->window, w_current->xor_gc, 
  +                      w_current->start_x, w_current->start_y, 
  +                      w_current->last_x, w_current->last_y);
  +        o_line_erase_grips(w_current, object);
  +				
  +        whichone_changing = whichone;
  +        object_changing = object;
  +        gdk_gc_set_foreground(w_current->gc, 
  +                              x_get_color(w_current->background_color)); 
  +        return(TRUE);
  +				
  +        break;
  +
  +      default:
  +				/* object type unknown : error condition */
  +        return(FALSE);
  +				
  +    }
  +  }
  +	
  +  return(FALSE);
  +}
  +
  +/*! \brief Initialize grip motion process for an arc.
  + *  \par Function Description
  + *  This function initializes the grip motion process for an arc.
  + *  From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
  + *  structure the coordinates of the center, the radius and the two angle
  + *  that describes an arc. These variables are used in the grip process.
  + *
  + *  The coordinates of the center of the arc on x- and y-axis are stored
  + *  into the <B>loc_x</B> and <B>loc_y</B> fields of the TOPLEVEL structure
  + *  in screen unit.
  + *
  + *  The radius of the center is stored into the <B>distance</B> field of
  + *  the TOPLEVEL structure in screen unit.
  + *
  + *  The two angles describing the arc on a circle are stored into the
  + *  <B>start_x</B> for the starting angle and <B>start_y</B> for the ending angle.
  + *  These angles are expressed in degrees.
  + *
  + *  Depending on which grips has been selected on the arc, the
  + *  corresponding variables in its original state is duplicated in
  + *  <B>last_x</B> and/or <B>last_y</B> of the TOPLEVEL structure.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Arc OBJECT to check.
  + *  \param [in]  x          (unused)
  + *  \param [in]  y          (unused)
  + *  \param [out] whichone   (unused)
  + */
  +void o_grips_start_arc(TOPLEVEL *w_current, OBJECT *o_current,
  +		       int x, int y, int whichone)
  +{
  +  w_current->last_drawb_mode = -1;
  +
  +  /* erase the arc before */
  +  o_arc_erase(w_current, o_current);
  +
  +  /* describe the arc with TOPLEVEL variables */
  +  /* center */
  +  w_current->start_x = o_current->arc->screen_x;
  +  w_current->start_y = o_current->arc->screen_y;
  +  /* radius */
  +  w_current->distance = o_current->arc->screen_width / 2;
  +  /* angles */
  +  w_current->loc_x = o_current->arc->start_angle;
  +  w_current->loc_y = o_current->arc->end_angle;
  +
  +  /* draw the first temporary arc */
  +  o_arc_rubberarc_xor(w_current);
  +	
  +}
  +
  +/*! \brief Initialize grip motion process for a box.
  + *  \par Function Description
  + *  This function initializes the grip motion process for a box. From the
  + *  <B>o_current</B> pointed object, it stores into the TOPLEVEL structure
  + *  the .... These variables are used in the grip process.
  + *
  + *  The function first erases the grips.
  + *
  + *  The coordinates of the selected corner are put in
  + *  (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
  + *
  + *  The coordinates of the opposite corner go in
  + *  (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not suppose
  + *  to change during the action.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Box OBJECT to check.
  + *  \param [in]  x          (unused)
  + *  \param [in]  y          (unused)
  + *  \param [out] whichone   Which coordinate to check.
  + */
  +void o_grips_start_box(TOPLEVEL *w_current, OBJECT *o_current,
  +		       int x, int y, int whichone)
  +{
  +  w_current->last_drawb_mode = -1;
  +	
  +  /* erase the box before */
  +  o_box_erase(w_current, o_current);
  +
  +  /* (last_x,last_y)    is the selected corner */
  +  /* (start_x, start_y) is the opposite corner */
  +  switch(whichone) {
  +    case BOX_UPPER_LEFT: 
  +      w_current->last_x  = o_current->box->screen_upper_x;
  +      w_current->last_y  = o_current->box->screen_upper_y;
  +      w_current->start_x = o_current->box->screen_lower_x;
  +      w_current->start_y = o_current->box->screen_lower_y;
  +      break;
  +    case BOX_LOWER_RIGHT: 
  +      w_current->last_x  = o_current->box->screen_lower_x;
  +      w_current->last_y  = o_current->box->screen_lower_y;
  +      w_current->start_x = o_current->box->screen_upper_x;
  +      w_current->start_y = o_current->box->screen_upper_y;
  +      break;
  +    case BOX_UPPER_RIGHT: 
  +      w_current->last_x  = o_current->box->screen_lower_x;
  +      w_current->last_y  = o_current->box->screen_upper_y;
  +      w_current->start_x = o_current->box->screen_upper_x;
  +      w_current->start_y = o_current->box->screen_lower_y;
  +      break;
  +    case BOX_LOWER_LEFT: 
  +      w_current->last_x  = o_current->box->screen_upper_x;
  +      w_current->last_y  = o_current->box->screen_lower_y;
  +      w_current->start_x = o_current->box->screen_lower_x;
  +      w_current->start_y = o_current->box->screen_upper_y;
  +      break;
  +    default:
  +      return; /* error */
  +  }
  +
  +  /* draw the first temporary box */
  +  o_box_rubberbox_xor(w_current);
  +
  +}
  +
  +#ifndef HAS_GTK12
  +/*! \brief Initialize grip motion process for a picture.
  + *  \par Function Description
  + *  This function initializes the grip motion process for a picture.
  + *  From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
  + *  structure the .... These variables are used in the grip process.
  + *
  + *  The function first erases the grips.
  + *
  + *  The coordinates of the selected corner are put in
  + *  (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
  + *
  + *  The coordinates of the opposite corner go in
  + *  (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not
  + *  suppose to change during the action.
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Picture OBJECT to check.
  + *  \param [in]  x          (unused)
  + *  \param [in]  y          (unused)
  + *  \param [out] whichone   Which coordinate to check.
  + */
  +void o_grips_start_picture(TOPLEVEL *w_current, OBJECT *o_current,
  +			   int x, int y, int whichone)
  +{
  +  w_current->last_drawb_mode = -1;
  +	
  +  /* erase the picture before */
  +  o_picture_erase(w_current, o_current);
  +  w_current->current_pixbuf = o_current->picture->original_picture;
  +  w_current->pixbuf_filename = o_current->picture->filename;
  +  w_current->pixbuf_wh_ratio = o_current->picture->ratio;
  +
  +  /* (last_x,last_y)    is the selected corner */
  +  /* (start_x, start_y) is the opposite corner */
  +  switch(whichone) {
  +    case PICTURE_UPPER_LEFT: 
  +      w_current->last_x  = o_current->picture->screen_upper_x;
  +      w_current->last_y  = o_current->picture->screen_upper_y;
  +      w_current->start_x = o_current->picture->screen_lower_x;
  +      w_current->start_y = o_current->picture->screen_lower_y;
  +      break;
  +    case PICTURE_LOWER_RIGHT: 
  +      w_current->last_x  = o_current->picture->screen_lower_x;
  +      w_current->last_y  = o_current->picture->screen_lower_y;
  +      w_current->start_x = o_current->picture->screen_upper_x;
  +      w_current->start_y = o_current->picture->screen_upper_y;
  +      break;
  +    case PICTURE_UPPER_RIGHT: 
  +      w_current->last_x  = o_current->picture->screen_lower_x;
  +      w_current->last_y  = o_current->picture->screen_upper_y;
  +      w_current->start_x = o_current->picture->screen_upper_x;
  +      w_current->start_y = o_current->picture->screen_lower_y;
  +      break;
  +    case PICTURE_LOWER_LEFT: 
  +      w_current->last_x  = o_current->picture->screen_upper_x;
  +      w_current->last_y  = o_current->picture->screen_lower_y;
  +      w_current->start_x = o_current->picture->screen_lower_x;
  +      w_current->start_y = o_current->picture->screen_upper_y;
  +      break;
  +    default:
  +      return; /* error */
  +  }
  +
  +  /* draw the first temporary picture */
  +  o_picture_rubberbox_xor(w_current);
  +
  +}
  +#endif
  +/*! \brief Initialize grip motion process for a circle.
  + *  \par Function Description
  + *  This function initializes the grip motion process for a circle.
  + *  From the <B>o_current</B> pointed object, it stores into the TOPLEVEL
  + *  structure the coordinate of the center and the radius. These variables
  + *  are used in the grip process.
  + *
  + *  The function first erases the grips.
  + *
  + *  The coordinates of the center are put in
  + *  (<B>w_current->start_x</B>,<B>w_current->start_y</B>). They are not suppose
  + *  to change during the action.
  + *
  + *  The coordinates of the point on the circle to the right of the center
  + *  go in (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Circle OBJECT to check.
  + *  \param [in]  x          (unused)
  + *  \param [in]  y          (unused)
  + *  \param [out] whichone   Which coordinate to check.
  + */
  +void o_grips_start_circle(TOPLEVEL *w_current, OBJECT *o_current,
  +			  int x, int y, int whichone)
  +{
  +  w_current->last_drawb_mode = -1;
  +  
  +  /* erase the circle before */
  +  o_circle_erase(w_current, o_current);
  +  
  +  /* describe the circle with TOPLEVEL variables */
  +  /* (start_x, start_y) is the center of the circle */
  +  w_current->start_x  = o_current->circle->screen_x;
  +  w_current->start_y  = o_current->circle->screen_y;
  +  /* (last_x,last_y)    is the point on circle on the right of center */
  +  w_current->last_x   = o_current->circle->screen_x +
  +                        o_current->circle->screen_radius;
  +  w_current->last_y   = o_current->circle->screen_y;
  +  /* distance           is the radius of the circle */
  +  w_current->distance = o_current->circle->screen_radius;
  +  
  +  /* draw the first temporary circle */
  +  o_circle_rubbercircle_xor(w_current);
  +
  +}
  +	
  +/*! \brief Initialize grip motion process for a line.
  + *  This function starts the move of one of the two grips of the line
  + *  object <B>o_current</B>.
  + *  The line and its grips are first erased. The move of the grips is
  + *  materializd with a temporary line in selection color drawn over the
  + *  sheet with an xor-function.
  + *
  + *  During the move of the grip, the line is described by
  + *  (<B>w_current->start_x</B>,<B>w_current->start_y</B>) and
  + *  (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
  + *
  + *  The line end that corresponds to the moving grip is in
  + *  (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
  + *
  + *  \param [in]  w_current  The TOPLEVEL object.
  + *  \param [in]  o_current  Line OBJECT to check.
  + *  \param [in]  x          (unused)
  + *  \param [in]  y          (unused)
  + *  \param [out] whichone   Which coordinate to check.
  + */
  +void o_grips_start_line(TOPLEVEL *w_current, OBJECT *o_current,
  +			int x, int y, int whichone)
  +{
  +  w_current->last_drawb_mode = -1;
  +  
  +  /* erase the line before */
  +  o_line_erase(w_current, o_current);
  +  
  +  /* describe the line with TOPLEVEL variables */
  +  w_current->last_x  = o_current->line->screen_x[whichone];
  +  w_current->last_y  = o_current->line->screen_y[whichone];
  +  w_current->start_x = o_current->line->screen_x[!whichone];
  +  w_current->start_y = o_current->line->screen_y[!whichone];
  +  
  +  /* draw the first temporary line */
  +  o_line_rubberline_xor(w_current);
  +}
  +
  +/*! \brief Modify previously selected object according to mouse position.
  + *  \par Function Description
  + *  This function modify the previously selected
  + *  object according to the mouse position in <B>x</B> and <B>y</B>.
  + *  The grip under modification is updated and the temporary object displayed.
  + *
  + *  The object under modification is <B>object_changing</B> and the grip
  + *  concerned is <B>whichone_changing</B>.
  + *
  + *  Depending on the object type, a specific function is used.
  + *  It erases the temporary object, updates its internal representation,
  + *  and draws it again.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_grips_motion(TOPLEVEL *w_current, int x, int y)
  +{
  +	
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  /* no object changing */
  +  if (object_changing == NULL) {
  +    /* stop grip process */
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +	
  +  switch(object_changing->type) {
  +    case(OBJ_ARC):
  +    /* erase, update and draw an arc */
  +    o_grips_motion_arc(w_current, x, y, whichone_changing);
  +    break;
  +
  +    case(OBJ_BOX):
  +    /* erase, update and draw a box */
  +    o_grips_motion_box(w_current, x, y, whichone_changing);
  +    break;
  +		
  +    case(OBJ_PICTURE):
  +    /* erase, update and draw a box */
  +#ifndef HAS_GTK12
  +    o_grips_motion_picture(w_current, x, y, whichone_changing);
  +#endif
  +    break;
  +		
  +    case(OBJ_CIRCLE):
  +    /* erase, update and draw a circle */
  +    o_grips_motion_circle(w_current, x, y, whichone_changing);
  +    break;
  +		
  +    case(OBJ_LINE):
  +    case(OBJ_NET):
  +    case(OBJ_PIN):
  +    case(OBJ_BUS):
  +    /* erase, update and draw a line */
  +    /* same for net, pin and bus as they share the same internal rep. */
  +    o_grips_motion_line(w_current, x, y, whichone_changing);
  +    break;
  +
  +    default:
  +    return; /* error condition */
  +  }
  +	
  +}
  +
  +/*! \brief Modify previously selected arc according to mouse position.
  + *  \par Function Description
  + *  This function is the refreshing part of the grip motion process.
  + *  It is called whenever the position of the pointer is changed,
  + *  therefore requiring the TOPLEVEL variables to be updated.
  + *  Depending on the grip selected and moved, the temporary TOPLEVEL
  + *  variables are changed according to the current position of the pointer.
  + *
  + *  If the grip at the center of the arc has been moved - modifying the
  + *  radius of the arc -, the <B>w_current->distance</B> field is updated.
  + *  To increase the radius of the arc, the user must drag the grip to the
  + *  right of the center. To decrease the radius of the arc, the user must
  + *  drag the grip to the left of the center. Negative radius can not be
  + *  obtained.
  + *
  + *  If one of the end of arc grip has been moved - modifying the arc
  + *  describing the arc -, the <B>w_current->start_x</B> or
  + *  <B>w_current->start_y</B> are updated according to which of the grip
  + *  has been selected.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + *  \param [in] whichone   Which grip to start motion with.
  + */
  +void o_grips_motion_arc(TOPLEVEL *w_current, int x, int y, int whichone)
  +{
  +  o_arc_rubberarc(w_current, x, y, whichone);
  +}
  +
  +/*! \brief Modify previously selected box according to mouse position.
  + *  \par Function Description
  + *  This function is the refreshing part of the grip motion process. It is
  + *  called whenever the position of the pointer is changed, therefore
  + *  requiring the TOPLEVEL variables to be updated.
  + *  Depending on the grip selected and moved, the temporary TOPLEVEL
  + *  variables are changed according to the current position of the pointer
  + *  and the modifications temporary drawn.
  + *
  + *  This function only makes a call to #o_box_rubberbox() that updates
  + *  the TOPLEVEL variables, erase the previous temporary box and draw the
  + *  new temporary box.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + *  \param [in] whichone   Which grip to start motion with.
  + */
  +void o_grips_motion_box(TOPLEVEL *w_current, int x, int y, int whichone)
  +{
  +  /* erase, update and draw the temporary box */
  +  o_box_rubberbox(w_current, x, y);
  +}
  +
  +#ifndef HAS_GTK12
  +/*! \brief Modify previously selected picture according to mouse position.
  + *  \par Function Description
  + *  This function is the refreshing part of the grip motion process. It is
  + *  called whenever the position of the pointer is changed, therefore
  + *  requiring the TOPLEVEL variables to be updated.
  + *  Depending on the grip selected and moved, the temporary TOPLEVEL
  + *  variables are changed according to the current position of the pointer
  + *  and the modifications temporary drawn.
  + *
  + *  This function only makes a call to #o_picture_rubberbox() that
  + *  updates the TOPLEVEL variables, erase the previous temporary picture
  + *  and draw the new temporary picture.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + *  \param [in] whichone   Which grip to start motion with.
  + */
  +void o_grips_motion_picture(TOPLEVEL *w_current, int x, int y, int whichone)
  +{
  +  /* erase, update and draw the temporary picture */
  +  o_picture_rubberbox(w_current, x, y);
  +}
  +#endif
  +
  +/*! \brief Modify previously selected circle according to mouse position.
  + *  \par Function Description
  + *  This function is the refreshing part of the grip motion process. It is
  + *  called whenever the position of the pointer is changed, therefore
  + *  requiring the TOPLEVEL variables to be updated.
  + *  Depending on the grip selected and moved, the temporary TOPLEVEL
  + *  variables are changed according to the current position of the pointer
  + *  and the modifications temporary drawn.
  + *
  + *  This function only makes a call to #o_circle_rubbercircle() that updates
  + *  the TOPLEVEL variables, erase the previous temporary circle and draw
  + *  the new temporary circle.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + *  \param [in] whichone   Which grip to start motion with.
  + */
  +void o_grips_motion_circle(TOPLEVEL *w_current, int x, int y, int whichone)
  +{
  +	/* erase, update and draw the temporary circle */
  +	o_circle_rubbercircle(w_current, x, y);
  +
  +}
  +
  +/*! \brief Modify previously selected line according to mouse position.
  + *  \par Function Description
  + *  This function is called during the move of the grip to update the
  + *  temporary line drawn under the mouse pointer.
  + *  The current position of the mouse is in <B>x</B> and <B>y</B> in screen coords.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + *  \param [in] whichone   Which grip to start motion with.
  + */
  +void o_grips_motion_line(TOPLEVEL *w_current, int x, int y, int whichone)
  +{
  +  /* erase, update and draw the temporary line */
  +  o_line_rubberline(w_current, x, y);
  +	
  +}
  +
  +/*! \brief End process of modifying object with grip.
  + *  \par Function Description
  + *  This function ends the process of modifying a parameter of an object
  + *  with a grip.
  + *  The temporary representation of the object is erased, the object is
  + *  modified and finally drawn.
  + *
  + *  The object under modification is <B>object_changing</B> and the grip
  + *  concerned is <B>whichone_changing</B>.
  + *
  + *  Depending on the object type, a specific function is used. It erases
  + *  the temporary object, updates the object and draws the modified object
  + *  normally.
  + *
  + *  \param [in,out] w_current  The TOPLEVEL object.
  + */
  +void o_grips_end(TOPLEVEL *w_current)
  +{
  +  OBJECT *object=NULL;
  +  int x, y;
  +  GList *other_objects = NULL;
  +  GList *connected_objects = NULL;
  +  int size;
  +	
  +  object = object_changing;
  +
  +  if (!object) {
  +    /* actually this is an error condition hack */
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    return;
  +  }
  +
  +  switch(object->type) {
  +    
  +    case(OBJ_ARC):
  +    /* modify an arc object */
  +    o_grips_end_arc(w_current, object, whichone_changing);
  +    break;
  +	  
  +    case(OBJ_BOX):
  +    /* modify a box object */
  +    o_grips_end_box(w_current, object, whichone_changing);
  +    break;
  +	  
  +    case(OBJ_PICTURE):
  +    /* modify a picture object */
  +#ifndef HAS_GTK12
  +    o_grips_end_picture(w_current, object, whichone_changing);
  +#endif
  +    break;
  +	  
  +    case(OBJ_CIRCLE):
  +    /* modify a circle object */
  +    o_grips_end_circle(w_current, object, whichone_changing);
  +    break;
  +	  
  +    case(OBJ_LINE):
  +    /* modify a line object */
  +    o_grips_end_line(w_current, object, whichone_changing);
  +    break;
  +
  +    case(OBJ_NET):
  +    /* don't allow zero length nets / lines / pins
  +     * this ends the net drawing behavior 
  +     * we want this? hack */
  +    if ((w_current->start_x == w_current->last_x) &&
  +        (w_current->start_y == w_current->last_y)) {
  +      w_current->start_x = (-1);
  +      w_current->start_y = (-1);
  +      w_current->last_x = (-1);
  +      w_current->last_y = (-1);
  +      w_current->inside_action=0;
  +      i_set_state(w_current, SELECT);
  +      o_net_eraserubber(w_current);
  +      o_redraw_single(w_current, object);
  +      i_update_toolbar(w_current);
  +      return;
  +    }
  +	  
  +	  
  +    SCREENtoWORLD(w_current, 
  +                  w_current->last_x, 
  +                  w_current->last_y, &x, &y);
  +	  
  +    x = snap_grid(w_current, x);
  +    y = snap_grid(w_current, y);
  +	  
  +    o_cue_undraw(w_current, object);
  +    o_net_erase(w_current, object);
  +    /* erase xor line */
  +    gdk_gc_set_foreground(w_current->xor_gc,
  +                          x_get_darkcolor(w_current->select_color));
  +    gdk_draw_line(w_current->window, w_current->xor_gc,
  +                  w_current->start_x, w_current->start_y,
  +                  w_current->last_x, w_current->last_y);
  +    o_line_erase_grips(w_current, object);
  +	  
  +    other_objects = s_conn_return_others(other_objects, object);
  +    s_conn_remove(w_current, object);
  +	  
  +    o_net_modify(w_current, object, x, y, whichone_changing);
  +
  +    s_conn_update_object(w_current, object);
  +    o_net_recalc(w_current, object);
  +	  
  +    /* get the other connected objects and redraw them */
  +    connected_objects = s_conn_return_others(connected_objects,
  +                                             object);
  +    
  +    /* add bus rippers if necessary */
  +    if (o_net_add_busrippers(w_current, object, connected_objects)) {
  +      
  +      o_net_erase(w_current, object);
  +      /*o_line_erase_grips(w_current, object); */
  +      
  +      if (w_current->net_style == THICK ) {
  +        size = SCREENabs(w_current, 10);
  +        
  +        if (size < 0)
  +          size=0;
  +          
  +          gdk_gc_set_line_attributes(w_current->gc, size, 
  +                                     GDK_LINE_SOLID,
  +                                     GDK_CAP_BUTT,
  +                                     GDK_CAP_NOT_LAST);
  +        }
  +      
  +      gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(w_current->background_color));
  +      gdk_draw_line(w_current->window, w_current->gc,
  +                    w_current->start_x, w_current->start_y,
  +                    w_current->last_x, w_current->last_y);
  +
  +      o_cue_undraw(w_current, object);
  +      o_net_draw(w_current, object);
  +      o_cue_draw_single(w_current, object);
  +      
  +      if (w_current->net_style == THICK ) {
  +        gdk_gc_set_line_attributes(w_current->gc, 0, 
  +                                   GDK_LINE_SOLID,
  +                                   GDK_CAP_NOT_LAST,
  +                                   GDK_JOIN_MITER);
  +      }
  +    }
  +
  +    /* draw the object objects */
  +    o_cue_undraw_list(w_current, other_objects);
  +    o_cue_draw_list(w_current, other_objects);
  +    
  +    o_redraw_single(w_current, object);
  +
  +    if (connected_objects) {
  +      g_list_free(connected_objects);
  +      connected_objects = NULL;
  +    }
  +
  +    /* get the other connected objects and redraw them */
  +    connected_objects = s_conn_return_others(connected_objects,
  +                                             object);
  +    
  +    o_cue_undraw_list(w_current, connected_objects);
  +    o_cue_draw_list(w_current, connected_objects);
  +    /* finally draw this objects cues */
  +    o_cue_draw_single(w_current, object);
  +    break;
  +
  +    case(OBJ_PIN):
  +    /* don't allow zero length nets / lines / pins
  +     * this ends the net drawing behavior 
  +     * we want this? hack */
  +    if ((w_current->start_x == w_current->last_x) &&
  +        (w_current->start_y == w_current->last_y)) {
  +      w_current->start_x = (-1);
  +      w_current->start_y = (-1);
  +      w_current->last_x = (-1);
  +      w_current->last_y = (-1);
  +      o_redraw_single(w_current, object);
  +      w_current->inside_action=0;
  +      i_set_state(w_current, SELECT);
  +      i_update_toolbar(w_current);
  +      return;
  +    }
  +	  
  +	  
  +    SCREENtoWORLD(w_current, 
  +                  w_current->last_x, 
  +                  w_current->last_y, &x, &y);
  +	  
  +    x = snap_grid(w_current, x);
  +    y = snap_grid(w_current, y);
  +	  
  +    o_cue_undraw(w_current, object);
  +    o_pin_erase(w_current, object);
  +    /* erase xor line */
  +    gdk_gc_set_foreground(w_current->xor_gc,
  +                          x_get_darkcolor(w_current->select_color));
  +    gdk_draw_line(w_current->window, w_current->xor_gc,
  +                  w_current->start_x, w_current->start_y,
  +                  w_current->last_x, w_current->last_y);
  +    o_line_erase_grips(w_current, object);
  +	  
  +    other_objects = s_conn_return_others(other_objects, object);
  +    s_conn_remove(w_current, object);
  +	  
  +    o_pin_modify(w_current, object, x, y, 
  +                 whichone_changing);
  +    s_conn_update_object(w_current, object);
  +    o_redraw_single(w_current, object);
  +	  
  +    /* draw the object objects */
  +    o_cue_undraw_list(w_current, other_objects);
  +    o_cue_draw_list(w_current, other_objects);
  +	  
  +    /* get the other connected objects and redraw them */
  +    connected_objects = s_conn_return_others(connected_objects,
  +                                             object);
  +    o_cue_undraw_list(w_current, connected_objects);
  +    o_cue_draw_list(w_current, connected_objects);
  +	  
  +    /* finally draw this objects cues */
  +    o_cue_draw_single(w_current, object);
  +    break;
  +	  
  +    case(OBJ_BUS):
  +    /* don't allow zero length nets / lines / pins
  +     * this ends the net drawing behavior 
  +     * we want this? hack */
  +    if ((w_current->start_x == w_current->last_x) &&
  +        (w_current->start_y == w_current->last_y)) {
  +      w_current->start_x = (-1);
  +      w_current->start_y = (-1);
  +      w_current->last_x = (-1);
  +      w_current->last_y = (-1);
  +      o_net_eraserubber(w_current);
  +      o_redraw_single(w_current, object);
  +      w_current->inside_action=0;
  +      i_set_state(w_current, SELECT);
  +      i_update_toolbar(w_current);
  +      return;
  +    }
  +	  
  +    SCREENtoWORLD(w_current, 
  +                  w_current->last_x, 
  +                  w_current->last_y, &x, &y);
  +	  
  +    x = snap_grid(w_current, x);
  +    y = snap_grid(w_current, y);
  +	  
  +    o_cue_undraw(w_current, object);
  +    o_bus_erase(w_current, object);
  +    /* erase xor line */
  +    gdk_gc_set_foreground(w_current->xor_gc,
  +                          x_get_darkcolor(w_current->select_color));
  +    gdk_draw_line(w_current->window, w_current->xor_gc,
  +                  w_current->start_x, w_current->start_y,
  +                  w_current->last_x, w_current->last_y);
  +    o_line_erase_grips(w_current, object);
  +	  
  +    other_objects = s_conn_return_others(other_objects, object);
  +    s_conn_remove(w_current, object);
  +	  
  +    o_bus_modify(w_current, object, x, y, 
  +                 whichone_changing);
  +    s_conn_update_object(w_current, object);
  +    o_redraw_single(w_current, object);
  +	  
  +    /* draw the object objects */
  +    o_cue_undraw_list(w_current, other_objects);
  +    o_cue_draw_list(w_current, other_objects);
  +	  
  +    /* get the other connected objects and redraw them */
  +    connected_objects = s_conn_return_others(connected_objects,
  +                                             object);
  +    o_cue_undraw_list(w_current, connected_objects);
  +    o_cue_draw_list(w_current, connected_objects);
  +	  
  +    /* finally draw this objects cues */
  +    o_cue_draw_single(w_current, object);
  +    break;
  +	  
  +    default:
  +    return;
  +  }
  +
  +			
  +  w_current->page_current->CHANGED=1;
  +  
  +  g_list_free(other_objects);
  +  other_objects = NULL;
  +  g_list_free(connected_objects);
  +  connected_objects = NULL;
  +
  +  /* reset global variables */
  +  whichone_changing = -1;
  +  object_changing = NULL;
  +  
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \brief End process of modifying arc object with grip.
  + *  \par Function Description
  + *  This function ends the grips process specific to an arc object. It erases
  + *  the old arc and write back to the object the new parameters of the arc.
  + *  Depending on the grip selected and moved, the right fields are updated.
  + *  The function handles the conversion from screen unit to world unit before
  + *  updating and redrawing.
  + *
  + *  If the grip at the center of the arc has been moved - modifying the radius
  + *  of the arc -, the new radius is calculated expressed in world unit
  + *  (the center is unchanged). It is updated with the function #o_arc_modify().
  + *
  + *  If one of the end of arc grip has been moved - modifying one of the
  + *  angles describing the arc -, this angle is updated with the
  + *  #o_arc_modify() function.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Arc OBJECT to end modification on.
  + *  \param [in] whichone   Which grip is pointed to.
  + */
  +void o_grips_end_arc(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
  +{
  +  int arg1, arg2;
  +
  +  /* erase the temporary arc */
  +  o_arc_rubberarc_xor(w_current);
  +
  +  /* determination of the parameters to give to o_arc_modify() */
  +  switch(whichone) {
  +    case ARC_RADIUS:
  +      /* convert the radius in world coords */
  +      arg1 = WORLDabs(w_current, w_current->distance);
  +      /* second parameter is not used */
  +      arg2 = -1;
  +      break;
  +		  
  +    case ARC_START_ANGLE:
  +      /* get the start angle from w_current */
  +      arg1 = w_current->loc_x;
  +      /* second parameter is not used */
  +      arg2 = -1;
  +      break;
  +
  +    case ARC_END_ANGLE:
  +      /* get the end angle from w_current */
  +      arg1 = w_current->loc_y;
  +      /* second parameter is not used */
  +      arg2 = -1;
  +      break;
  +
  +    default:
  +      return;
  +  }
  +
  +  /* modify the arc with the parameters determined above */
  +  o_arc_modify(w_current, o_current, arg1, arg2, whichone);
  +
  +  /* display the new arc */
  +  o_redraw_single(w_current, o_current);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief End process of modifying box object with grip.
  + *  \par Function Description
  + * 
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Box OBJECT to end modification on.
  + *  \param [in] whichone   Which grip is pointed to.
  + */
  +void o_grips_end_box(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
  +{
  +  int box_width, box_height;
  +  int x, y;
  +  
  +  box_width  = GET_BOX_WIDTH (w_current);
  +  box_height = GET_BOX_HEIGHT(w_current);
  +  
  +  /* don't allow zero width/height boxes
  +   * this ends the box drawing behavior 
  +   * we want this? hack */
  +  if ((box_width == 0) && (box_height == 0)) {
  +    w_current->start_x = (-1);
  +    w_current->start_y = (-1);
  +    w_current->last_x  = (-1);
  +    w_current->last_y  = (-1);
  +    
  +    w_current->inside_action=0;
  +    i_set_state(w_current, SELECT);
  +    
  +    o_redraw_single(w_current, o_current);
  +    i_update_toolbar(w_current);
  +    
  +    return;
  +  }
  +
  +  SCREENtoWORLD(w_current, 
  +		w_current->last_x, w_current->last_y,
  +		&x, &y);
  +  x = snap_grid(w_current, x);
  +  y = snap_grid(w_current, y);
  +  
  +  o_box_modify(w_current, o_current, x, y, whichone);
  +  
  +  /* erase the temporary box */
  +  o_box_rubberbox_xor(w_current);
  +  
  +  /* draw the modified box */
  +  o_redraw_single(w_current, o_current);
  +}
  +
  +#ifndef HAS_GTK12
  +/*! \todo Finish function documentation!!!
  + *  \brief End process of modifying picture object with grip.
  + *  \par Function Description
  + * 
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Picture OBJECT to end modification on.
  + *  \param [in] whichone   Which grip is pointed to.
  + */
  +void o_grips_end_picture(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
  +{
  +  int picture_width, picture_height;
  +  int x, y;
  +  
  +  picture_width  = GET_PICTURE_WIDTH (w_current);
  +  picture_height = GET_PICTURE_HEIGHT(w_current);
  +
  +  /* don't allow zero width/height picturees
  +   * this ends the picture drawing behavior 
  +   * we want this? hack */
  +  if ((picture_width == 0) && (picture_height == 0)) {
  +    w_current->start_x = (-1);
  +    w_current->start_y = (-1);
  +    w_current->last_x  = (-1);
  +    w_current->last_y  = (-1);
  +    
  +    w_current->inside_action=0;
  +    i_set_state(w_current, SELECT);
  +    
  +    o_redraw_single(w_current, o_current);
  +    i_update_toolbar(w_current);
  +    
  +    return;
  +  }
  +  
  +  SCREENtoWORLD(w_current, 
  +		w_current->last_x, w_current->last_y,
  +		&x, &y);
  +  x = snap_grid(w_current, x);
  +  y = snap_grid(w_current, y);
  +  
  +  o_picture_modify(w_current, o_current, x, y, whichone);
  +  
  +  /* erase the temporary picture */
  +  o_picture_rubberbox_xor(w_current);
  +  
  +  /* draw the modified picture */
  +  o_redraw_single(w_current, o_current);
  +  
  +  w_current->current_pixbuf = NULL;
  +  w_current->pixbuf_filename = NULL;
  +  w_current->pixbuf_wh_ratio = 0;
  +}
  +#endif
  +
  +/*! \brief End process of modifying circle object with grip.
  + *  \par Function Description
  + *  This function ends the process of modifying the radius of the circle
  + *  object <B>*o_current</B>.
  + *  The modified circle is finally normally drawn.
  + *
  + *  A circle with a null radius is not allowed. In this case, the process
  + *  is stopped and the circle is left unchanged.
  + *
  + *  The last value of the radius is in <B>w_current->distance</B> in screen units.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Circle OBJECT to end modification on.
  + *  \param [in] whichone   Which grip is pointed to.
  + */
  +void o_grips_end_circle(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
  +{
  +  int radius;
  +  
  +  /* erase the temporary circle */
  +  o_circle_rubbercircle_xor(w_current);
  +  
  +  /* don't allow zero radius circles
  +   * this ends the circle drawing behavior 
  +   * we want this? hack */
  +  if ((w_current->start_x == w_current->last_x) &&
  +      (w_current->start_y == w_current->last_y)) {
  +    w_current->start_x = (-1);
  +    w_current->start_y = (-1);
  +    w_current->last_x  = (-1);
  +    w_current->last_y  = (-1);
  +    
  +    /* return to select mode */
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    i_update_toolbar(w_current);
  +    
  +    o_redraw_single(w_current, o_current);
  +    return;
  +  }
  +  
  +  /* convert the radius in world unit */
  +  radius = WORLDabs(w_current, w_current->distance);
  +  
  +  /* modify the radius of the circle */
  +  o_circle_modify(w_current, o_current, radius, -1, CIRCLE_RADIUS);
  +  
  +  /* display the new circle */
  +  o_redraw_single(w_current, o_current); 
  +}
  +
  +/*! \brief End process of modifying line object with grip.
  + *  \par Function Description
  + *  This function ends the process of modifying one end of the line
  + *  object <B>*o_current</B>.
  + *  This end is identified by <B>whichone</B>. The line object is modified
  + *  according to the <B>whichone</B> parameter and the last position of the
  + *  line end.
  + *  The modified line is finally normally drawn.
  + *
  + *  A line with a null width, i.e. when both ends are identical, is not
  + *  allowed. In this case, the process is stopped and the line unchanged.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Circle OBJECT to end modification on.
  + *  \param [in] whichone   Which grip is pointed to.
  + */
  +void o_grips_end_line(TOPLEVEL *w_current, OBJECT *o_current, int whichone)
  +{
  +  int x, y;
  +  
  +  /* erase the temporary line */
  +  o_line_rubberline_xor(w_current);
  +  
  +  /* don't allow zero length nets / lines / pins
  +   * this ends the net drawing behavior 
  +   * we want this? hack */
  +  if ((w_current->start_x == w_current->last_x) &&
  +      (w_current->start_y == w_current->last_y)) {
  +    w_current->start_x = (-1);
  +    w_current->start_y = (-1);
  +    w_current->last_x  = (-1);
  +    w_current->last_y  = (-1);
  +    
  +    /* return to select mode */
  +    w_current->inside_action=0;
  +    i_set_state(w_current, SELECT);
  +    i_update_toolbar(w_current);
  +    
  +    o_redraw_single(w_current, o_current);
  +    return;
  +  }
  +  
  +  /* convert the line end coords in world unit */
  +  SCREENtoWORLD(w_current, 
  +		w_current->last_x, w_current->last_y,
  +		&x, &y);
  +  x = snap_grid(w_current, x);
  +  y = snap_grid(w_current, y);
  +  
  +  /* modify the right line end according to whichone */
  +  o_line_modify(w_current, o_current, x, y, whichone);
  +  
  +  /* display the new line */
  +  o_redraw_single(w_current, o_current);
  +}
  +	
  +/*! \brief Get half the width and height of grip in screen units.
  + *  \par Function Description
  + *  According to the current zoom level, the function returns half the width
  + *  and height of a grip in screen units.
  + *
  + *  <B>GRIP_SIZE1</B> and <B>GRIP_SIZE2</B> and <B>GRIP_SIZE3</B> are macros defined
  + *  in libgeda #defines.h. They are the half width/height of a grip in
  + *  world unit for a determined range of zoom factors.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \return Half grip size in screen units.
  + */
  +int o_grips_size(TOPLEVEL *w_current)
  +{
  +  int factor, size;
  +  
  +  factor = (int) w_current->page_current->to_world_x_constant;
  +  if (factor > SMALL_ZOOMFACTOR1) {
  +    /* big zoom factor : small size converted to screen unit */
  +    size = SCREENabs(w_current, GRIP_SIZE1);
  +  } else if (factor > SMALL_ZOOMFACTOR2) {
  +    /* medium zoom factor : medium size converted to screen unit */
  +    size = SCREENabs(w_current, GRIP_SIZE2);
  +  } else {
  +    /* small zoom factor : big size converted to screen unit */
  +    size = SCREENabs(w_current, GRIP_SIZE3);
  +  }
  +  
  +  return size;
  +}
  +
  +/*! \brief Draw grip centered at <B>x</B>, <B>y</B>
  + *  \par Function Description
  + *  This function draws a grip centered at (<B>x</B>,<B>y</B>). Its color is
  + *  either the selection color or the overriding color from
  + *  <B>w_current->override_color</B>.
  + *
  + *  The size of the grip depends on the current zoom factor.
  + *
  + *  <B>x</B> and <B>y</B> are in screen unit.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Center x coordinate for drawing grip.
  + *  \param [in] y          Center y coordinate for drawing grip.
  + */
  +void o_grips_draw(TOPLEVEL *w_current, int x, int y)
  +{
  +  GdkColor *color;
  +  int size, x2size;
  +  
  +  /*
  +   * Depending on the current zoom level, the size of the grip is
  +   * determined. <B>size</B> is half the width and height of the grip
  +   * and <B>x2size</B> is the full width and height of the grip.
  +   */
  +  /* size is half the width of grip */
  +  size = o_grips_size(w_current);
  +  /* x2size is full width */
  +  x2size = 2 * size;
  +
  +  /*
  +   * The grip can be displayed or erased : if <B>w_current->override_color</B>
  +   * is not set the grip is drawn with the selection color ; if
  +   * <B>w_current->override_color</B> is set then the color it refers it
  +   * is used. This way the grip can be erased if this color is the
  +   * background color.
  +   */
  +  if (w_current->override_color != -1 ) {
  +    /* override : use the override_color instead */
  +    color = x_get_color(w_current->override_color);
  +  } else {
  +    /* use the normal selection color */
  +    color = x_get_color(w_current->select_color);
  +  }
  +  /* set the color for the grip */
  +  gdk_gc_set_foreground(w_current->gc, color);
  + 
  +  /* set the line options for grip : solid, 1 pix wide */
  +  gdk_gc_set_line_attributes(w_current->gc, 0, GDK_LINE_SOLID,
  +			     GDK_CAP_BUTT, GDK_JOIN_MITER);
  +	
  +  /*
  +   * A grip is a hollow square centered at (<B>x</B>,<B>y</B>) with a
  +   * width/height of <B>x2size</B>.
  +   */
  +  /* draw the grip in window */
  +  gdk_draw_rectangle(w_current->window, w_current->gc, FALSE,
  +		     x - size, y - size, x2size, x2size);
  +  /* draw the grip in backingstore */
  +  gdk_draw_rectangle(w_current->backingstore, w_current->gc, FALSE,
  +		     x - size, y - size, x2size, x2size);
  +}
  +
  +/*! \brief Erase grip centered at <B>x</B>,<B>y</B>
  + *  \par Function Description
  + *  This function erases a grip centered at (<B>x</B>,<B>y</B>). 
  + *  The size of the grip depends on the current zoom factor.
  + *
  + *  The grip is erased by drawing with the background color over the
  + *  visible grip.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Center x coordinate for drawing grip.
  + *  \param [in] y          Center y coordinate for drawing grip.
  + */
  +void o_grips_erase(TOPLEVEL *w_current, int x, int y)
  +{
  +  /* set overriding color */
  +  w_current->override_color = w_current->background_color;
  +  /* draw a grip with backgound color : erase grip */
  +  o_grips_draw(w_current, x, y);
  +  /* return to default */
  +  w_current->override_color = -1;
  +}
  
  
  
  1.20      +955 -604  eda/geda/gaf/gschem/src/o_line.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_line.c
  ===================================================================
  RCS file: o_line.c
  diff -N o_line.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_line.c	14 Jul 2006 02:23:55 -0000	1.20
  @@ -0,0 +1,1036 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \brief Draw a line on screen.
  + *  \par Function Description
  + *  This function is used to draw a line on screen. The line is described
  + *  in the object which is referred by <B>o_current</B>. The line is displayed
  + *  according to the current state, described in the TOPLEVEL object pointed
  + *  by <B>w_current</B>.
  + *
  + *  It first checks if the object is valid or not. If not it returns and do
  + *  not output anything. That should never happen though.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  The line OBJECT to draw.
  + */
  +void o_line_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int x1, y1, x2, y2;
  +  int line_width, length, space;
  +  GdkColor *color;
  +  GdkCapStyle line_end;
  +  void (*draw_func)() = NULL;
  +	
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  /*
  +   * The function now recalculates the OBJECT as a line. It involves
  +   * calculating every single dimensions according to the zoom factor
  +   * and position, @dots{}
  +   * It also recalculates the bounding box of the object and check whether
  +   *  this object is visible or not. If not there is no reason to draw it !
  +   */
  +  /* goes before visible, clipfixme */
  +  o_line_recalc(w_current, o_current);
  +	
  +  if (!o_line_visible(w_current, o_current->line, &x1, &y1, &x2, &y2)) {
  +    return;
  +  }
  +	
  +#if DEBUG
  +  printf("drawing line\n\n");
  +  printf("drawing line : %d,%d to %d,%d\n",
  +         o_current->line->x1, o_current->line->y1,
  +         o_current->line->x2, o_current->line->y2);
  +#endif
  +
  +  /*
  +   * As a line is definetely not a closed shape there is no need to define and
  +   * call any filling function. Another way to say that is that a line can
  +   * not be filled. It simply draws the line according to the type.
  +   *
  +   * The values describing the line type are extracted from the
  +   * <B>o_current</B> pointed structure. These are the width of the line, the
  +   * field called length and the field called space and the desired end type
  +   * for the line.
  +   *
  +   * Depending on the type of the line that has to be used to draw the box
  +   * the appropriate function is called. Values of space and length are
  +   * adapted to the type of line. The possible functions are the following :
  +   * #o_line_draw_solid(), #o_line_draw_dotted(), #o_line_draw_dashed() and
  +   * #o_line_draw_phantom().
  +   *
  +   * The combination <B>length</B> == 0 and <B>space</B> == 0 is avoided as it
  +   * leads to an endless loop in function called after. If such a case is
  +   * encountered the line is drawn as a solid line independently of its
  +   * initial type.
  +   *
  +   * Finally the function takes care of the grips.
  +   */
  +  if (w_current->override_color != -1 )
  +  color = x_get_color(w_current->override_color);
  +  else
  +  color = x_get_color(o_current->color);
  +	
  +  if(o_current->screen_line_width > 0) {
  +    line_width = o_current->screen_line_width;
  +  } else {
  +    line_width = 1;
  +  }
  +	
  +  switch(o_current->line_end) {
  +    case END_NONE:   line_end = GDK_CAP_BUTT;       break;
  +    case END_SQUARE: line_end = GDK_CAP_PROJECTING; break;
  +    case END_ROUND:  line_end = GDK_CAP_ROUND;      break;
  +    default: fprintf(stderr, _("Unknown end for line (%d)\n"),
  +                     o_current->line_end);
  +    line_end = GDK_CAP_BUTT; 
  +    break;
  +  }
  +
  +  length = o_current->screen_line_length;
  +  space = o_current->screen_line_space;
  +	
  +  switch(o_current->line_type) {
  +    case TYPE_SOLID:
  +      length = -1;
  +      space = -1;
  +      draw_func = (void *) o_line_draw_solid;
  +      break;
  +			
  +    case TYPE_DOTTED:
  +      length = -1; /* in ..._draw_dotted, length is unused */
  +      draw_func = (void *) o_line_draw_dotted;
  +      break;
  +			
  +    case TYPE_DASHED:
  +      draw_func = (void *) o_line_draw_dashed;
  +      break;
  +			
  +    case TYPE_CENTER:
  +      draw_func = (void *) o_line_draw_center;
  +      break;
  +			
  +    case TYPE_PHANTOM:
  +      draw_func = (void *) o_line_draw_phantom;
  +      break;
  +			
  +    case TYPE_ERASE:
  +      break;
  +			
  +    default:
  +      length = -1;
  +      space = -1;
  +      line_width = 0; /* just to be careful */
  +      fprintf(stderr, _("Unknown type for line (%d) !\n"),
  +              o_current->line_type);
  +      draw_func = (void *) o_line_draw_solid;
  +      break;
  +  }
  +
  +  if((length == 0) || (space == 0))
  +  draw_func = (void *) o_line_draw_solid;
  +
  +  (*draw_func)(w_current->window, w_current->gc, color, line_end,
  +               x1, y1, x2, y2, line_width, length, space);
  +  (*draw_func)(w_current->backingstore, w_current->gc, color, line_end,
  +               x1, y1, x2, y2, line_width, length, space);
  +
  +  /* reset line width and reset back to default */
  +  gdk_gc_set_line_attributes(w_current->gc, 0, GDK_LINE_SOLID,
  +                             GDK_CAP_NOT_LAST,
  +                             GDK_JOIN_MITER);
  +
  +  if (o_current->draw_grips && w_current->draw_grips == TRUE) {	
  +    /* pb20011010 - modified to use the new o_line_[draw|erase]_grips() */
  +    if (!o_current->selected) {
  +      /* object is no more selected, erase the grips */
  +      o_current->draw_grips = FALSE;
  +      o_line_erase_grips(w_current, o_current);
  +    } else {
  +      /* object is selected, draw the grips */
  +      o_line_draw_grips(w_current, o_current);
  +    }
  +  }
  +
  +#if DEBUG
  +  printf("drawing line\n");
  +#endif
  +}
  +
  +/*! \brief Draw a line with a solid line type.
  + *  \par Function Description
  + *  This function draws a line with a solid line type. The line is defined
  + *  by the coordinates of its two extremities. The parameters <B>length</B>
  + *  and <B>space</B> are unused here.
  + *
  + *  The line attributes are settled. Then it simply make a call to the
  + *  gdk original function.
  + *
  + *  \param [in] w           GdkWindow to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] cap         GdkCapStype line end cap style.
  + *  \param [in] x1          Upper x coordinate of Line.
  + *  \param [in] y1          Upper y coordinate of Line.
  + *  \param [in] x2          Lower x coordinate of Line.
  + *  \param [in] y2          Lower y coordinate of Line.
  + *  \param [in] line_width  Line width.
  + *  \param [in] length      (unused).
  + *  \param [in] space       (unused).
  + */
  +void o_line_draw_solid(GdkWindow *w, GdkGC *gc, GdkColor *color,
  +		       GdkCapStyle cap, gint x1, gint y1, gint x2, gint y2,
  +		       gint line_width, gint length, gint space)
  +{
  +  gdk_gc_set_foreground(gc, color);
  +
  +  /* Set the width, end type and join style of the line */
  +  gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_SOLID,
  +                             cap, GDK_JOIN_MITER);
  +
  +  /* Draw the line */
  +  gdk_draw_line(w, gc, x1, y1, x2, y2);
  +
  +}
  +
  +/*! \brief Draw a line with a dotted line type.
  + *  \par Function Description
  + *  This function draw a line with a dotted line type. The parameter
  + *  <B>space</B> represents the distance between two of the dots. The parameter
  + *  <B>length</B> is unused. The diameter of the dots is given by the width
  + *  of the line given by <B>line_width</B>.
  + *
  + *  The unit of <B>x1</B>, <B>y1</B> and <B>x2</B>, <B>y2</B> and
  + *  <B>line_width</B>, <B>length</B>, <B>space</B> is pixel.
  + *
  + *  A negative of null value for length or space leads to an endless loop.
  + *
  + *  \param [in] w           GdkWindow to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] cap         GdkCapStype line end cap style.
  + *  \param [in] x1          Upper x coordinate of Line.
  + *  \param [in] y1          Upper y coordinate of Line.
  + *  \param [in] x2          Lower x coordinate of Line.
  + *  \param [in] y2          Lower y coordinate of Line.
  + *  \param [in] line_width  Line width.
  + *  \param [in] length      (unused).
  + *  \param [in] space       Space between dots in pixels.
  + */
  +void o_line_draw_dotted(GdkWindow *w, GdkGC *gc, GdkColor *color,
  +			GdkCapStyle cap, gint x1, gint y1, gint x2, gint y2,
  +			gint line_width, gint length, gint space)
  +{
  +  double dx, dy, l, d;
  +  double dx1, dy1;
  +  double xa, ya;
  +
  +  gdk_gc_set_foreground(gc, color);
  +
  +  /*
  +   * It first finds the increments on x and y axis that match the space
  +   * on the line between two dots.
  +   *
  +   * Starting from one of the end of the line and incrementing the position
  +   * gives the coordinates of every dots on the line providing that the
  +   * second extremities is not exceeded.
  +   */
  +  dx = (double) (x2 - x1);
  +  dy = (double) (y2 - y1);
  +  l = sqrt((dx * dx) + (dy * dy));
  +
  +  dx1 = (dx * space) / l;
  +  dy1 = (dy * space) / l;
  +
  +  d = 0;
  +  xa = x1; ya = y1;
  +  while(d < l) {
  +
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a
  +     * different manner : if the real world width is equal to 0, then the
  +     * width is translated to 1 in screen coordinates. Drawing a circle with
  +     * a 1-diameter and the GDK function #gdk_draw_arc() is not possible.
  +     * So we needs to test whether the width is 1 or not.
  +     */
  +    if(line_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - line_width/2, 
  +		   ((int) ya) - line_width/2,
  +		   line_width, line_width, 0, FULL_CIRCLE);
  +    }
  +    
  +    d = d + space;
  +    xa = xa + dx1;
  +    ya = ya + dy1;
  +  }
  +	
  +}
  +
  +/*! \brief Draw a line with a dotted line type.
  + *  \par Function Description
  + *  This function draws a line with a dashed line type. The parameter
  + *  <B>space</B> respresents the distance between two of the dashes. The
  + *  parameter <B>length</B> represents the length of a dash.
  + *
  + *  The unit of <B>x1</B>, <B>y1</B> and <B>x2</B>, <B>y2</B> and
  + *  <B>line_width</B>, <B>length</B>, <B>space</B> is pixel.
  + *
  + *  A negative of null value for length or space leads to an endless loop.
  + *
  + *  \param [in] w           GdkWindow to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] cap         GdkCapStype line end cap style.
  + *  \param [in] x1          Upper x coordinate of Line.
  + *  \param [in] y1          Upper y coordinate of Line.
  + *  \param [in] x2          Lower x coordinate of Line.
  + *  \param [in] y2          Lower y coordinate of Line.
  + *  \param [in] line_width  Line width.
  + *  \param [in] length      Length of dashes in pixels.
  + *  \param [in] space       Space between dashes in pixels.
  + */
  +void o_line_draw_dashed(GdkWindow *w, GdkGC *gc, GdkColor *color,
  +			GdkCapStyle cap, gint x1, gint y1, gint x2, gint y2,
  +			gint line_width, gint length, gint space)
  +{
  +  double dx, dy, l, d;
  +  double dx1, dy1, dx2, dy2;
  +  double xa, ya, xb, yb;
  +
  +  gdk_gc_set_foreground(gc, color);
  +  gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_SOLID,
  +                             cap, GDK_JOIN_MITER);
  +
  +  /*
  +   * The function determines the increments on x and y axis that match
  +   * the space on the line between two dots. The same thing is done for length.
  +   *
  +   * Starting from one of the end of the line and incrementing the position
  +   * gives the coordinates of every dots on the line providing that the
  +   * second extremities is not exceeded. This is checked by first computing
  +   * the distance between the two extremities and then checking whether this
  +   * limit is exceeded by a new dash or not.
  +   *
  +   * It draws as many dashes of length <B>length</B> as possible.
  +   */
  +  dx = (double) (x2 - x1);
  +  dy = (double) (y2 - y1);
  +  l = sqrt((dx * dx) + (dy * dy));
  +
  +  dx1 = (dx * length) / l;
  +  dy1 = (dy * length) / l;
  +
  +  dx2 = (dx * space) / l;
  +  dy2 = (dy * space) / l;
  +  
  +  d = 0;
  +  xa = x1; ya = y1;
  +  while((d + length + space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +		
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +
  +  }
  +
  +  /*
  +   * When the above condition is not satisfied, then it is not possible
  +   * to draw a dash of length <B>length</B>. However it may be possible to
  +   * draw a shorter dash.
  +   */
  +  if((d + length) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +  } else {
  +    xb = x2;
  +    yb = y2;
  +  }
  +
  +  gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +
  +}
  +
  +/*! \brief Draw line with a centered line type.
  + *  \par Function Description.
  + *  This function draws a line with a centered line type. The parameter
  + *  <B>space</B> represents the distance between a dot and the dash. The
  + *  parameter <B>length</B> represents the length of a dash.
  + *
  + *  The unit of <B>x1</B>, <B>y1</B> and <B>x2</B>, <B>y2</B> and
  + *  <B>line_width</B>, <B>length</B>, <B>space</B> is pixel.
  + *
  + *  A negative of null value for length or space leads to an endless loop.
  + *
  + *  \param [in] w           GdkWindow to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] cap         GdkCapStype line end cap style.
  + *  \param [in] x1          Upper x coordinate of Line.
  + *  \param [in] y1          Upper y coordinate of Line.
  + *  \param [in] x2          Lower x coordinate of Line.
  + *  \param [in] y2          Lower y coordinate of Line.
  + *  \param [in] line_width  Line width.
  + *  \param [in] length      Length of dashes in pixels.
  + *  \param [in] space       Space between dashes in pixels.
  + */
  +void o_line_draw_center(GdkWindow *w, GdkGC *gc, GdkColor *color,
  +			GdkCapStyle cap, gint x1, gint y1, gint x2, gint y2,
  +			gint line_width, gint length, gint space)
  +{
  +  double dx, dy, l, d;
  +  double dx1, dy1, dx2, dy2;
  +  double xa, ya, xb, yb;
  +
  +  gdk_gc_set_foreground(gc, color);
  +  gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_SOLID,
  +                             cap, GDK_JOIN_MITER);
  +
  +  /*
  +   * The function determines the increments on x and y axis that match
  +   * the space on the line between two dots. The same thing is done for length.
  +   *
  +   * Starting from one of the end of the line and incrementing the position
  +   * gives the coordinates of every dots and dashes on the line providing
  +   * that the second extremity is not exceeded. This is checked by first
  +   * computing the distance between the two extremities and then checking
  +   * whether this limit is exceeded by a new dash or not.
  +   *
  +   * It draws as many sets of 'dash of length <B>length</B> and dot' as possible.
  +   */
  +  dx = (double) (x2 - x1);
  +  dy = (double) (y2 - y1);
  +  l = sqrt((dx * dx) + (dy * dy));
  +
  +  dx1 = (dx * length) / l;
  +  dy1 = (dy * length) / l;
  +
  +  dx2 = (dx * space) / l;
  +  dy2 = (dy * space) / l;
  +	
  +  d = 0;
  +  xa = x1; ya = y1;
  +  while((d + length + 2 * space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +		
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a different
  +     * manner : if the real world width is equal to 0, then the width is
  +     * translated to 1 in screen coordinates. Drawing a circle with a
  +     * 1-diameter and the GDK function #gdk_draw_arc() is not possible.
  +     * So we needs to test whether the width is 1 or not.
  +     */
  +  if(line_width == 1) {
  +	gdk_draw_point(w, gc, (int) xa, (int) ya);
  +  } else {
  +	gdk_draw_arc(w, gc, TRUE,
  +	     ((int) xa) - line_width/2, 
  +	     ((int) ya) - line_width/2,
  +	     line_width, line_width, 0, FULL_CIRCLE);
  +  }
  +
  +		
  +        d = d + space;
  +    xa = xa + dx2;
  +    ya = ya + dy2;
  +  }
  +}
  +
  +/*! \note This code was not inserted in the no web file, but it was present.
  +If the above condition is not satisfied, it may still be possible to continue drawing a part of the initial pattern. Here two cases are possible :
  +@itemize @bullet
  +@item
  +it is possible to draw a dash and a dot ;
  +@item
  +it is possible to draw a dash or a part of the original dash ;
  +@end itemize
  +
  +<<o_line.c : o_line_center()>>=
  +  if((d + length + space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +		
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +		
  +    <<o_line_draw_center() : drawing a dot>>
  +		
  +  } else {
  +    if(d + length < l) {
  +      xb = xa + dx1;
  +      yb = ya + dy1;
  +    } else {
  +      xb = x2;
  +      yb = y2;
  +    }
  +		
  +    gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +	
  +  }
  +
  +}
  +*/
  +
  +/*! \brief Draw a line with a phantom line type.
  + *  \par Function Description
  + *  This function draws a line with a phantom line type. The parameter
  + *  <B>space</B> represents the distance between a dot and a dash. The parameter
  + *  <B>length</B> represents the length of a dash.
  + *
  + *  The unit of <B>x1</B>, <B>y1</B> and <B>x2</B>, <B>y2</B> and
  + *  <B>line_width</B>, <B>length</B>, <B>space</B> is pixel.
  + *
  + *  A negative of null value for length or space leads to an endless loop.
  + *
  + *  \param [in] w           GdkWindow to draw in.
  + *  \param [in] gc          GdkGC graphics context to draw on.
  + *  \param [in] color       Circle fill color. 
  + *  \param [in] cap         GdkCapStype line end cap style.
  + *  \param [in] x1          Upper x coordinate of Line.
  + *  \param [in] y1          Upper y coordinate of Line.
  + *  \param [in] x2          Lower x coordinate of Line.
  + *  \param [in] y2          Lower y coordinate of Line.
  + *  \param [in] line_width  Line width.
  + *  \param [in] length      Length of dashes in pixels.
  + *  \param [in] space       Space between dashes in pixels.
  + */
  +void o_line_draw_phantom(GdkWindow *w, GdkGC *gc, GdkColor *color,
  +			 GdkCapStyle cap, gint x1, gint y1, gint x2, gint y2,
  +			 gint line_width, gint length, gint space)
  +{
  +  double dx, dy, l, d; 
  +  double dx1, dy1, dx2, dy2;
  +  double xa, ya, xb, yb;
  +
  +  gdk_gc_set_foreground(gc, color);
  +  gdk_gc_set_line_attributes(gc, line_width, GDK_LINE_SOLID,
  +			     cap, GDK_JOIN_MITER);
  +
  +  /*
  +   * The function determines the increments on x and y axis that match
  +   * the space on the line between two dots. The same thing is done for length.
  +   *
  +   * Starting from one of the end of the line and incrementing the position
  +   * gives the coordinates of every dots and dashes on the line providing
  +   * that the second extremity is not exceeded. This is checked by first
  +   * computing the distance between the two extremities and then checking
  +   * whether this limit is exceeded by a new dash or not.
  +   *
  +   * It draws as many sets of 'dash of length <B>length</B> and two dots'
  +   * as possible.
  +   */
  +  dx = (double) (x2 - x1);
  +  dy = (double) (y2 - y1);
  +  l = sqrt((dx * dx) + (dy * dy));
  +
  +  dx1 = (dx * length) / l;
  +  dy1 = (dy * length) / l;
  +
  +  dx2 = (dx * space) / l;
  +  dy2 = (dy * space) / l;
  +	
  +  d = 0;
  +  xa = x1; ya = y1;
  +  while((d + length + 3 * space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +		
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +
  +    
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a
  +     * different manner : if the real world width is equal to 0, then the
  +     * width is translated to 1 in screen coordinates. Drawing a circle with
  +     * a 1-diameter and the GDK function #gdk_draw_arc() is not possible.
  +     * So we needs to test whether the width is 1 or not.
  +     */
  +    if(line_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - line_width/2, 
  +		   ((int) ya) - line_width/2,
  +		   line_width, line_width, 0, FULL_CIRCLE);
  +    }
  +    
  +    d = d + space;
  +    xa = xa + dx2;
  +    ya = ya + dy2;
  +
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a different
  +     * manner : if the real world width is equal to 0, then the width is
  +     * translated to 1 in screen coordinates. Drawing a circle with a
  +     * 1-diameter and the GDK function #gdk_draw_arc() is not possible.
  +     * So we needs to test whether the width is 1 or not.
  +     */
  +    
  +    if(line_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - line_width/2, 
  +		   ((int) ya) - line_width/2,
  +		   line_width, line_width, 0, FULL_CIRCLE);
  +    }
  +    
  +    d = d + space;
  +    xa = xa + dx2;
  +    ya = ya + dy2;
  +  }
  +  
  +  /*
  +   * If the above condition is not satisfied, it may still be possible to
  +   * continue drawing a part of the original pattern.
  +   * Here three cases are possible :
  +   * <DL>
  +   *   <DT>*</DT><DD>it is possible to draw a dash and the two dots.
  +   *   <DT>*</DT><DD>it is possible to draw a dash and one of the two dots.
  +   *   <DT>*</DT><DD>it is possible to draw at least a part of the initial
  +   *                 dash.
  +   * </DL>
  +   */
  +
  +  if((d + length + 2 * space) < l) {
  +    d = d + length;
  +    xb = xa + dx1;
  +    yb = ya + dy1;
  +    gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +    
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +    
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a
  +     * different manner : if the real world width is equal to 0, then the
  +     * width is translated to 1 in screen coordinates. Drawing a circle with
  +     * a 1-diameter and the GDK function #gdk_draw_arc() is not possible.
  +     * So we needs to test whether the width is 1 or not.
  +     */  
  +    if(line_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - line_width/2, 
  +		   ((int) ya) - line_width/2,
  +		   line_width, line_width, 0, FULL_CIRCLE);
  +    }
  +
  +    d = d + space;
  +    xa = xb + dx2;
  +    ya = yb + dy2;
  +
  +    
  +    /*
  +     * Depending on the width of the line, dots has to be drawn in a different
  +     * manner : if the real world width is equal to 0, then the width is
  +     * translated to 1 in screen coordinates. Drawing a circle with a
  +     * 1-diameter and the GDK function #gdk_draw_arc() is not possible.
  +     * So we needs to test whether the width is 1 or not.
  +     */  
  +    if(line_width == 1) {
  +      gdk_draw_point(w, gc, (int) xa, (int) ya);
  +    } else {
  +      gdk_draw_arc(w, gc, TRUE,
  +		   ((int) xa) - line_width/2, 
  +		   ((int) ya) - line_width/2,
  +		   line_width, line_width, 0, FULL_CIRCLE);
  +    }
  +  } else {
  +    if(d + length + space < l) {
  +      d = d + length;
  +      xb = xa + dx1;
  +      yb = ya + dy1;
  +      gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +      
  +      d = d + space;
  +      xa = xb + dx2;
  +      ya = yb + dy2;
  +      
  +      /*
  +       * Depending on the width of the line, dots has to be drawn in a
  +       * different manner : if the real world width is equal to 0, then the
  +       * width is translated to 1 in screen coordinates. Drawing a circle
  +       * with a 1-diameter and the GDK function #gdk_draw_arc() is not
  +       * possible. So we needs to test whether the width is 1 or not.
  +       */
  +      if(line_width == 1) {
  +	gdk_draw_point(w, gc, (int) xa, (int) ya);
  +      } else {
  +	gdk_draw_arc(w, gc, TRUE,
  +		     ((int) xa) - line_width/2, 
  +		     ((int) ya) - line_width/2,
  +		     line_width, line_width, 0, FULL_CIRCLE);
  +      }
  +    } else {
  +      if(d + length < l) {
  +	xb = xa + dx1;
  +	yb = ya + dy1;
  +      } else {
  +	xb = x2;
  +	yb = y2;
  +      }	
  +      gdk_draw_line(w, gc, (int) xa, (int) ya, (int) xb, (int) yb);
  +    }
  +  }
  +}
  +
  +/*! \brief Erase line object.
  + *  \par Function Description
  + *  This function erases the line object described by <B>*o_current</B>.
  + *
  + *  It draws the line over the sheet with the background color.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Line OBJECT to erase.
  + */
  +void o_line_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  w_current->override_color = w_current->background_color;
  +  o_line_draw(w_current, o_current);
  +  w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  used in button cancel code in x_events.c
  + */
  +void o_line_eraserubber(TOPLEVEL *w_current)
  +{
  +  gdk_gc_set_foreground(w_current->gc,
  +			x_get_color(w_current->background_color) );
  +  gdk_draw_line(w_current->window, w_current->gc, w_current->start_x,
  +                w_current->start_y, w_current->last_x, w_current->last_y);
  +}
  +
  +/*! \brief Draw a line object after applying translation.
  + *  \par Function Description
  + *  This function is used to draw the line object described by
  + *  <B>*o_current</B> after applying a translation on the two directions of
  + *  <B>dx</B> and <B>dy</B> in screen unit. It uses and XOR function to draw the
  + *  translated line over the current sheet.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] dx         Delta x coordinate for line.
  + *  \param [in] dy         Delta y coordinate for line.
  + *  \param [in] o_current  Line OBJECT to draw.
  + */
  +void o_line_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  +{
  +  int color;
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  /* changed for dark color stuff */
  +  gdk_gc_set_foreground(w_current->outline_xor_gc,
  +                        x_get_darkcolor(color));
  +  gdk_draw_line(w_current->window, w_current->outline_xor_gc,
  +                o_current->line->screen_x[0]+dx,
  +                o_current->line->screen_y[0]+dy,
  +                o_current->line->screen_x[1]+dx,
  +                o_current->line->screen_y[1]+dy);
  +
  +  /* backing store? nope not here */
  +}
  +
  +/*! \brief Start process to input a new line.
  + *  \par Function Description
  + *  This function starts the process of interactively adding a line to
  + *  the current sheet.
  + *
  + *  During all the process, the line is internally represented by the two
  + *  ends of the line as (<B>w_current->start_x</B>,<B>w_current->start_y</B>) and
  + *  (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
  + *
  + *  A temporary line is xor-drawn during the process with the selection color
  + *  and changed according to the position of the mouse pointer.
  + */
  +void o_line_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  /* init start_[x|y], last_[x|y] to describe line */
  +  w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +  
  +  /* draw init xor */
  +  o_line_rubberline_xor(w_current);
  +}
  +
  +/*! \brief End the input of a line.
  + *  \par Function Description
  + *  This function ends the process of interactively adding a line to the
  + *  current sheet.
  + *
  + *  It first erases the last temporary line displayed, calculates the
  + *  corresponding world coordinates of the two ends of the line and finally
  + *  adds a new initialized line object to the list of object of the current
  + *  sheet.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_line_end(TOPLEVEL *w_current, int x, int y)
  +{
  +  int x1, y1;
  +  int x2, y2;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  /* Use last_x and _y from the last time you moved the mouse from the
  +     rubber function, so in otherwords... comment these out...
  +     w_current->last_x = fix_x(w_current, x);
  +     w_current->last_y = fix_y(w_current, y);
  +  */
  +
  +  /* erase xor image */
  +  o_line_rubberline_xor(w_current);
  +
  +  /* don't allow zero length lines */
  +  if ( (w_current->start_x == w_current->last_x) &&
  +       (w_current->start_y == w_current->last_y) ) {
  +    w_current->start_x = (-1);
  +    w_current->start_y = (-1);
  +    w_current->last_x = (-1);
  +    w_current->last_y = (-1);
  +    return;
  +  }
  +
  +  /* calculate the world coords of the two ends of the line */
  +  SCREENtoWORLD(w_current,
  +				w_current->start_x, w_current->start_y,
  +				&x1, &y1);
  +  SCREENtoWORLD(w_current,
  +				w_current->last_x, w_current->last_y,
  +				&x2, &y2);
  +  x1 = snap_grid(w_current, x1);
  +  y1 = snap_grid(w_current, y1);
  +  x2 = snap_grid(w_current, x2);
  +  y2 = snap_grid(w_current, y2);
  +	
  +  /* create the object */
  +  /* PB : modification in o_line_add() prototype */	
  +  w_current->page_current->object_tail =
  +  o_line_add(w_current,
  +             w_current->page_current->object_tail,
  +             OBJ_LINE, w_current->graphic_color, x1, y1, x2, y2);
  +
  +  /* draw it */
  +  o_redraw_single(w_current, w_current->page_current->object_tail);
  +  
  +  w_current->start_x = (-1);
  +  w_current->start_y = (-1);
  +  w_current->last_x = (-1);
  +  w_current->last_y = (-1);
  +  
  +  w_current->page_current->CHANGED=1;
  +
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \brief Draw temporary line while dragging end.
  + *  \par Function Description
  + *  This function manages the erase/update/draw process of temporary line
  + *  when modifying one end of the line.
  + *  The line is described by four <B>*w_current</B> variables : the first end
  + *  of the line is (<B>start_x</B>,<B>start_y</B>), the second end is
  + *  (<B>last_x</B>,<B>last_y</B>).
  + *  The first end is constant. The second end is updated to the (<B>x</B>,<B>y</B>).
  + * 
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] x          Current x coordinate of pointer in screen units.
  + *  \param [in] y          Current y coordinate of pointer in screen units.
  + */
  +void o_line_rubberline(TOPLEVEL *w_current, int x, int y)
  +{
  +  int diff_x, diff_y;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  /*
  +   * The current temporary line is described by the two points
  +   * (<B>w_current->start_x</B>,<B>w_current->start_y</B>) and
  +   * (<B>w_current->last_x</B>,<B>w_current->last_y</B>) as end of the line.
  +   *
  +   * This line is xor-drawn : if the line was already displayed, it is
  +   * erased. If the line was not already displayed it is drawn.
  +   */
  +  /* xor-draw a line at the old location */
  +  o_line_rubberline_xor(w_current);
  +
  +  /*
  +   * The coordinates of the moving end of the line are updated. Its new
  +   * coordinates are in <B>x</B> and <B>y</B> parameters and saved to
  +   * <B>w_current->last_x</B> and <B>w_current->last_y</B> respectively - after
  +   * being snapped to grid.
  +   */ 
  +  /* update the coordinate of the modified end */
  +  w_current->last_x = fix_x(w_current, x);
  +  w_current->last_y = fix_y(w_current, y);
  +  
  +  /* if the control key was pressed then draw ortho lines */
  +  if (w_current->CONTROLKEY) {
  +    diff_x = abs(w_current->last_x - w_current->start_x);
  +    diff_y = abs(w_current->last_y - w_current->start_y);
  +    
  +    if (diff_x >= diff_y) {
  +      w_current->last_y = w_current->start_y;
  +    } else {
  +      w_current->last_x = w_current->start_x;
  +    }
  +  }
  +  
  +  /*
  +   * The updated line is finally again xor-drawn : before the call to this
  +   * function, if the line was displayed, it has been erased, updated and
  +   * displayed again.
  +   */
  +  /* xor-draw the updated line */
  +  o_line_rubberline_xor(w_current);
  +}
  +
  +/*! \brief Draw line from TOPLEVEL object.
  + *  \par Function Description
  + *  This function draws a line with an exclusive or function over the sheet.
  + *  The color of the box is <B>w_current->select_color</B>. The line is
  + *  described by the two points (<B>w_current->start_x</B>,
  + *  <B>w_current->start_y</B>) and (<B>w_current->last_x</B>,<B>w_current->last_y</B>).
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + */
  +void o_line_rubberline_xor(TOPLEVEL *w_current)
  +{
  +  /* draw the circle from the w_current variables */
  +  /* with xor-function */
  +  gdk_gc_set_foreground(w_current->xor_gc, 
  +			x_get_darkcolor(w_current->select_color));
  +  gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +			     GDK_LINE_SOLID, GDK_CAP_NOT_LAST, 
  +			     GDK_JOIN_MITER);
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		w_current->start_x, w_current->start_y,
  +		w_current->last_x,  w_current->last_y);  
  +}
  +
  +/*! \brief Draw grip marks on line.
  + *  \par Function Description
  + *  This function draws the grips on the line object <B>o_current</B>.
  + *
  + *  A line has a grip at each end.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Line OBJECT to draw grip points on.
  + */
  +void o_line_draw_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  if (w_current->draw_grips == FALSE)
  +	  return;
  +
  +  /* draw the grip on line end 1 */
  +  o_grips_draw(w_current, 
  +	       o_current->line->screen_x[LINE_END1], 
  +	       o_current->line->screen_y[LINE_END1]);
  +  
  +  /* draw the grip on line end 2 */
  +  o_grips_draw(w_current,
  +	       o_current->line->screen_x[LINE_END2], 
  +	       o_current->line->screen_y[LINE_END2]);
  +}
  +
  +/*! \brief Erase grip marks from line.
  + *  \par Function Description
  + *  This function erases the grips on the line object <B>o_current</B>.
  + *
  + *  A line has a grip at each end.
  + *
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] o_current  Line OBJECT to erase grip marks from.
  + */
  +void o_line_erase_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  +{
  +  if (w_current->draw_grips == FALSE)
  +    return;
  +  
  +  /* erase the grip on line end 1 */
  +  o_grips_erase(w_current, 
  +		o_current->line->screen_x[LINE_END1],
  +		o_current->line->screen_y[LINE_END1]);
  +  
  +  /* erase the grip on line end 2 */
  +  o_grips_erase(w_current,
  +		o_current->line->screen_x[LINE_END2],
  +		o_current->line->screen_y[LINE_END2]);
  +  
  +}
  
  
  
  1.32      +1415 -308 eda/geda/gaf/gschem/src/o_misc.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_misc.c
  ===================================================================
  RCS file: o_misc.c
  diff -N o_misc.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_misc.c	14 Jul 2006 02:23:55 -0000	1.32
  @@ -0,0 +1,1820 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <ctype.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#include <libgen.h>
  +
  +#include <sys/types.h>
  +#include <sys/stat.h>
  +#include <unistd.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define FOCUS_SELECTION 0
  +#define FOCUS_SHEET 1
  +#define FOCUS_ALL 2
  +
  +#define SELECTION_ALL 0
  +#define SELECTION_UNNUMBERED 1
  +
  +#define AUTONUMBER_SKIP_NOT 0
  +#define AUTONUMBER_SKIP_PAGE 1
  +#define AUTONUMBER_SKIP_SELECTION 2
  +
  +#define AUTONUMBER_SORT_YX 1
  +#define AUTONUMBER_SORT_XY 2
  +#define AUTONUMBER_SORT_DIAGONAL 3
  +
  +/* break with the tradition here and input a list */
  +/*! \todo probably should go back and do the same for o_copy o_move
  + *  o_delete...
  + */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_edit(TOPLEVEL *w_current, SELECTION *list)
  +{
  +  char *equal_ptr;
  +  OBJECT *o_current;
  +#if 0 /* was HAS_LIBGTKEXTRA, no longer user */
  +  SELECTION *s_current;
  +  int object_count=0;
  +#endif
  +  int num_lines = 0;
  +
  +  if (list == NULL) {
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    return;
  +  }
  +
  +  o_current = list->selected_object;	
  +  if (o_current == NULL) {
  +    fprintf(stderr, _("Got an unexpected NULL in o_edit\n"));
  +    exit(-1);
  +  }
  +
  +#if 0 /* was HAS_LIBGTKEXTRA, no longer used */
  +  /* count up how many non-text objects exist in the selection */
  +  /* list.  Why?  Because if there are multiple objects, invoke the */
  +  /* multi_multi_edit dialog box */
  +  s_current = list;
  +  while (s_current != NULL) {
  +    if (s_current->selected_object) {
  +      if (s_current->selected_object->type != OBJ_TEXT) {
  +        object_count++;	
  +      }				
  +    }
  +    s_current=s_current->next;
  +  }
  +
  +  /* now decide what we want to do, either single edit or */
  +  /* multi multi edit */
  +  if (object_count == 1 && o_current->type != OBJ_TEXT) {
  +    x_multiattrib_open (w_current, o_current);
  +    return;
  +  } else if ( object_count > 1 ) {
  +    x_multiattrib_open (w_current, o_current);
  +    return;
  +  }
  +#endif
  +
  +
  +  /* for now deal with only the first item */
  +  switch(o_current->type) {
  +
  +    /* also add the ability to multi attrib edit: nets, busses, pins */
  +    case(OBJ_COMPLEX):
  +    case(OBJ_PLACEHOLDER):
  +    case(OBJ_NET):
  +    case(OBJ_PIN):
  +    case(OBJ_BUS):
  +    x_multiattrib_open (w_current, o_current);
  +    break;
  +
  +    case(OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +    picture_change_filename_dialog(w_current);
  +#endif
  +    break;
  +    case(OBJ_TEXT):
  +    if(strchr(o_current->text->string,'=')) {
  +
  +      /* now really make sure it's an attribute by 
  +       * checking that there are NO spaces around the ='s 
  +       */
  +      equal_ptr = strchr(o_current->text->string, '=');
  +
  +      /* and also make sure it is only a single line */
  +      num_lines = o_text_num_lines(o_current->text->string);
  +
  +      /* there is a possiblity for core dump yes? */
  +      /* by exceeding the size of the text_string? */
  +      /* or maybe not, since if the ='s is at the end of */
  +      /* the string, there better be a null after it! */
  +      if ( (*(equal_ptr + 1) != ' ') &&
  +           (*(equal_ptr - 1) != ' ') &&
  +           (num_lines == 1) ) {
  +	        attrib_edit_dialog(w_current,o_current, FROM_MENU); 
  +	/*	multi_attrib_edit(w_current, o_current); */
  +
  +      } else {
  +        o_text_edit(w_current, o_current);
  +      } 
  +    } else {
  +      o_text_edit(w_current, o_current);
  +    }
  +    break;
  +  }
  +
  +  /* has to be more extensive in the future */
  +  /* some sort of redrawing? */
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* This locks the entire selected list.  It does lock components, but does NOT
  + * change the color (of primatives of the components) though 
  + * this cannot be called recursively */
  +void o_lock(TOPLEVEL *w_current)
  +{
  +  OBJECT *object = NULL;
  +  SELECTION *s_current = NULL;
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +
  +  while(s_current != NULL) {
  +    object = s_current->selected_object;
  +    if (object) {
  +      /* check to see if locked_color is already being used */
  +      if (object->locked_color == -1) {
  +        object->sel_func = NULL;
  +        object->locked_color = object->color;
  +        object->color = w_current->lock_color;
  +        w_current->page_current->CHANGED=1;
  +      } else {
  +        s_log_message(_("Object alreadly locked\n"));
  +      }
  +    }
  +
  +    s_current=s_current->next;
  +  }
  +
  +  o_unselect_all(w_current);
  +  o_undo_savestate(w_current, UNDO_ALL);
  +  i_update_menus(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/* You can unlock something by selecting it with a bounding box... */
  +/* this will probably change in the future, but for now it's a
  +   something.. :-) */
  +/* this cannot be called recursively */
  +void o_unlock(TOPLEVEL *w_current)
  +{
  +  OBJECT *object = NULL;
  +  SELECTION *s_current = NULL;
  +
  +  s_current = w_current->page_current->selection2_head->next;
  +
  +  while(s_current != NULL) {
  +    object = s_current->selected_object;
  +    if (object) {
  +      /* only unlock if sel_func is not set to something */
  +      if (object->sel_func == NULL) {
  +        object->sel_func = select_func;
  +        object->color = object->locked_color;
  +        object->locked_color = -1;
  +        w_current->page_current->CHANGED = 1;
  +      } else {
  +        s_log_message(_("Object alreadly unlocked\n"));
  +      }
  +    }
  +
  +    s_current=s_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \brief Rotate all objects in list.
  + *  \par Function Description
  + *  Given the selection <B>list</B>, and the center of rotation
  + *  (<B>centerx</B>,<B>centery</B>, this function traverses all the selection
  + *  list, rotating each object.
  + *  The selection list contains a given object and all its attributes
  + *  (refdes, pinname, pinlabel, ...).
  + *  There is a second pass to run the rotate hooks of non-simple objects,
  + *  like pin or complex objects, for example.
  + * 
  + *  \param [in] w_current  The TOPLEVEL object.
  + *  \param [in] list       The list of objects to rotate.
  + *  \param [in] centerx    Center x coordinate of rotation.
  + *  \param [in] centery    Center y coordinate of rotation.
  + */
  +void o_rotate_90(TOPLEVEL *w_current, SELECTION *list,
  +		 int centerx, int centery)
  +{
  +  OBJECT *object;
  +  SELECTION *s_current;
  +  int new_angle;
  +  GList *other_objects=NULL;
  +  GList *connected_objects=NULL;
  +  OBJECT *o_current=NULL;
  +        
  +  /* this is okay if you just hit rotate and have nothing selected */
  +  if (list == NULL) {
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    return;
  +  }
  +
  +  s_current = list;
  +
  +  while (s_current != NULL) {
  +    object = s_current->selected_object;
  +
  +    if (!object) {
  +      fprintf(stderr, _("ERROR: NULL object in o_rotate_90!\n"));
  +      return;
  +    }
  +
  +    g_list_free(other_objects);
  +    other_objects = NULL;
  +    g_list_free(connected_objects);
  +    connected_objects = NULL;
  +
  +    switch(object->type) {
  +
  +
  +      case(OBJ_NET):
  +	if (!w_current->DONT_REDRAW) {
  +	  o_cue_undraw(w_current, object);
  +	  o_net_erase(w_current, object);
  +	  o_line_erase_grips(w_current, object);
  +	}
  +                                
  +        /* save the other objects */
  +        other_objects = s_conn_return_others(other_objects, object);
  +        s_conn_remove(w_current, object);
  +                                
  +        o_net_rotate(w_current, centerx, centery, 90, object);
  +        s_conn_update_object(w_current, object);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_net_draw(w_current, object);
  +                                
  +	  /* draw the other objects */
  +	  o_cue_undraw_list(w_current, other_objects);
  +	  o_cue_draw_list(w_current, other_objects);
  +	}
  +
  +        /* get other connected objects and redraw */
  +        connected_objects = s_conn_return_others(connected_objects, object);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_cue_undraw_list(w_current, connected_objects);
  +	  o_cue_draw_list(w_current, connected_objects);
  +	  
  +	  /* finally redraw the cues on the current object */
  +	  o_cue_draw_single(w_current, object); 
  +	}
  +        break;
  +
  +      case(OBJ_BUS):
  +	if (!w_current->DONT_REDRAW) {
  +	  o_cue_undraw(w_current, object);
  +	  o_bus_erase(w_current, object);
  +	  o_line_erase_grips(w_current, object);
  +        }
  +
  +        other_objects = s_conn_return_others(other_objects, object);
  +        s_conn_remove(w_current, object);
  +        
  +        o_bus_rotate(w_current, centerx, centery, 90, object);
  +        s_conn_update_object(w_current, object);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_bus_draw(w_current, object);
  +        
  +	  /* draw the other objects */
  +	  o_cue_undraw_list(w_current, other_objects);
  +	  o_cue_draw_list(w_current, other_objects);
  +	}
  +
  +        /* get other connected objects and redraw */
  +        connected_objects = s_conn_return_others(connected_objects, object);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_cue_undraw_list(w_current, connected_objects);
  +	  o_cue_draw_list(w_current, connected_objects);
  +
  +	  /* finally redraw the cues on the current object */
  +	  o_cue_draw_single(w_current, object); 
  +	}
  +        break;
  +
  +      case(OBJ_PIN):
  +	if (!w_current->DONT_REDRAW) {
  +	  o_cue_undraw(w_current, object);
  +	  o_pin_erase(w_current, object);
  +	  o_line_erase_grips(w_current, object);
  +	}
  +        
  +        other_objects = s_conn_return_others(other_objects, object);
  +        s_conn_remove(w_current, object);
  +        
  +        o_pin_rotate(w_current, centerx, centery, 
  +                     90, object);
  +        s_conn_update_object(w_current, object);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_pin_draw(w_current, object);
  +        
  +	  /* draw the other objects */
  +	  o_cue_undraw_list(w_current, other_objects);
  +	  o_cue_draw_list(w_current, other_objects);
  +	}
  +  
  +	/* get other connected objects and redraw */
  +        connected_objects = s_conn_return_others(connected_objects, object);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_cue_undraw_list(w_current, connected_objects);
  +	  o_cue_draw_list(w_current, connected_objects);
  +	  
  +	  /* finally redraw the cues on the current object */
  +	  o_cue_draw_single(w_current, object);
  +	}
  +        break;
  +
  +      case(OBJ_COMPLEX):
  +	if (!w_current->DONT_REDRAW) {
  +	  o_cue_undraw_objects(w_current, object->complex->prim_objs);
  +	  /* erase the current selection */
  +	  o_complex_erase(w_current, object);
  +	}
  +
  +        other_objects = s_conn_return_complex_others(other_objects, object);
  +        
  +        /* remove all conn references */
  +        o_current = object->complex->prim_objs;
  +        while(o_current != NULL) {
  +          s_conn_remove(w_current, o_current);
  +          o_current = o_current->next;
  +        }
  +      
  +        /* do the rotate */
  +        /*w_current->ADDING_SEL=1; NEWSEL: needed? */
  +        new_angle = (object->complex->angle + 90) % 360;
  +        o_complex_rotate(w_current, centerx, centery,
  +                         new_angle, 90, object);
  +        /*w_current->ADDING_SEL = 0; NEWSEL: needed? */
  +        s_conn_update_complex(w_current, object->complex->prim_objs);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_complex_draw(w_current, object);
  +	  
  +	  o_cue_undraw_list(w_current, other_objects);
  +	  o_cue_draw_list(w_current, other_objects);
  +	}
  +
  +        /* now draw the newly connected objects */
  +        connected_objects = s_conn_return_complex_others(connected_objects,
  +                                                         object);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_cue_undraw_list(w_current, connected_objects);
  +	  o_cue_draw_list(w_current, connected_objects);
  +	}
  +        break;
  +        
  +      case(OBJ_LINE):
  +	if (!w_current->DONT_REDRAW) {
  +	  o_line_erase_grips(w_current, object);
  +	  o_line_erase(w_current, object);
  +	}
  +
  +        o_line_rotate(w_current, centerx, centery, 
  +                      90, object);
  +
  +	if (!w_current->DONT_REDRAW) {
  +	  o_line_draw(w_current, object);
  +	}
  +        break;
  +
  +      case(OBJ_BOX):
  +	/* erase the current selection */
  +	if (!w_current->DONT_REDRAW) {
  +	  o_box_erase_grips(w_current, object);
  +	  o_box_erase(w_current, object);
  +	}
  +
  +        o_box_rotate(w_current, centerx, centery, 
  +                     90, object);
  +
  +	if (!w_current->DONT_REDRAW) {
  +	  o_box_draw(w_current, object);
  +	}
  +        break;
  +
  +      case(OBJ_PICTURE):
  +				/* erase the current selection */
  +#ifndef HAS_GTK12
  +	
  +	if (!w_current->DONT_REDRAW) {
  +	  o_picture_erase_grips(w_current, object);
  +	  o_picture_erase(w_current, object);
  +	}
  +	
  +        o_picture_rotate(w_current, centerx, centery, 
  +                     90, object);
  +
  +	if (!w_current->DONT_REDRAW) {
  +	  o_picture_draw(w_current, object);
  +	}
  +#endif
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +	if (!w_current->DONT_REDRAW) {
  +	  o_circle_erase_grips(w_current, object);
  +	  o_circle_erase(w_current, object);
  +	}
  +
  +        o_circle_rotate(w_current, centerx, centery, 
  +                        90, object);
  +
  +	if (!w_current->DONT_REDRAW) {
  +	  o_circle_draw(w_current, object);
  +	}
  +        break;
  +
  +      case(OBJ_ARC):
  +	if (!w_current->DONT_REDRAW) {
  +	  o_arc_erase(w_current, object);
  +	}
  +
  +#if 0 /* not needed anymore */
  +	SCREENtoWORLD(w_current, centerx, centery, 
  +		      &world_centerx, &world_centery);
  +        o_arc_rotate_world(w_current, world_centerx, world_centery, 90, object);
  +#endif
  +
  +        o_arc_rotate(w_current, centerx, centery, 90, object);
  +	if (!w_current->DONT_REDRAW) {
  +	  o_arc_draw(w_current, object);
  +	}
  +        break;
  +
  +      case(OBJ_TEXT):
  +	/* erase the current selection */
  +	if (!w_current->DONT_REDRAW) {
  +	  o_text_erase(w_current, object);
  +	}
  +
  +        new_angle = (object->text->angle + 90) % 360;
  +        o_text_rotate(w_current, centerx, centery,
  +                      new_angle, 90, object);
  +
  +	if (!w_current->DONT_REDRAW) {
  +	  o_text_draw(w_current, object);
  +	}
  +        break;
  +    }
  +    s_current = s_current->next;
  +  }
  +
  +  /* All objects were rotated. Do a 2nd pass to run the rotate hooks */
  +  /* Do not run any hooks for simple objects here, like text, since they
  +     were rotated in the previous pass, and the selection list can contain
  +     an object and all its attributes (text) */
  +  s_current = list;
  +  while (s_current != NULL) {
  +    object = s_current->selected_object;
  +
  +    if (!object) {
  +      fprintf(stderr, _("ERROR: NULL object in o_rotate_90!\n"));
  +      return;
  +    }
  +
  +    switch(object->type) {
  +      case(OBJ_PIN):
  +	/* Run the rotate pin hook */
  +	if (scm_hook_empty_p(rotate_pin_hook) == SCM_BOOL_F &&
  +	    object != NULL) {
  +	  scm_run_hook(rotate_pin_hook,
  +		       scm_cons(g_make_object_smob(w_current, object),
  +				SCM_EOL));
  +	}
  +	break;
  +
  +      case (OBJ_COMPLEX):
  +	/* Run the rotate hook */
  +	if (scm_hook_empty_p(rotate_component_object_hook) == SCM_BOOL_F &&
  +	    object != NULL) {
  +	  scm_run_hook(rotate_component_object_hook,
  +		       scm_cons(g_make_object_smob(w_current, object),
  +				SCM_EOL));
  +	}
  +	break;
  +    default:
  +	break;
  +    }
  +
  +    s_current = s_current->next;
  +  }
  +
  +  /* Don't save the undo state if we are inside an action */
  +  /* This is useful when rotating the selection while moving, for example */
  +  w_current->page_current->CHANGED = 1;
  +  if (!w_current->inside_action) {
  +    o_undo_savestate(w_current, UNDO_ALL);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_embed(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  gchar *new_basename;
  +
  +  /* check o_current is a complex and is not already embedded */
  +  if (o_current->type == OBJ_COMPLEX &&
  +      !o_complex_is_embedded (o_current))
  +  {
  +    /* change the clib of complex to "EMBEDDED" */
  +    if (o_current->complex_clib) {
  +      free (o_current->complex_clib);
  +    }
  +    o_current->complex_clib = g_strdup ("EMBEDDED");
  +
  +    /* change the basename to "EMBEDDED"+basename */
  +    new_basename = g_strconcat ("EMBEDDED",
  +                                o_current->complex_basename,
  +                                NULL);
  +    free (o_current->complex_basename);
  +    o_current->complex_basename = new_basename;
  +
  +    s_log_message (_("Component [%s] has been embedded\n"),
  +                   o_current->complex_basename + 8);
  +    
  +    /* page content has been modified */
  +    w_current->page_current->CHANGED = 1;
  +  }
  +
  +  /* If it's a picture and it's not embedded */
  +  if ( (o_current->type == OBJ_PICTURE) &&
  +       (o_current->picture->embedded == 0) ) {
  +
  +    o_current->picture->embedded = 1;
  +    
  +    s_log_message (_("Picture [%s] has been embedded\n"),
  +		   basename(o_current->picture->filename));
  +    
  +    
  +    /* page content has been modified */
  +    w_current->page_current->CHANGED = 1;
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_unembed(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  gchar *new_basename, *new_clib;
  +  const GSList *clibs;
  +  
  +  /* check o_current is an embedded complex */
  +  if (o_current->type == OBJ_COMPLEX &&
  +      o_complex_is_embedded (o_current))
  +  {
  +    /* get ride of the EMBEDDED word in basename */
  +    new_basename = g_strdup (o_current->complex_basename + 8);
  +    
  +    /* search for the symbol in the library */
  +    clibs = s_clib_search_basename (new_basename);
  +
  +    if (!clibs) {
  +      /* symbol not found in the symbol library: signal an error */
  +      s_log_message (_("Could not find component [%s], while trying to unembed. Component is still embedded\n"),
  +                     o_current->complex_basename + 8);
  +      
  +    } else {
  +      /* set the object new basename */
  +      free (o_current->complex_basename);
  +      o_current->complex_basename = new_basename;
  +
  +      /* set the object new clib */
  +      free (o_current->complex_clib);
  +      if (g_slist_next (clibs)) {
  +        s_log_message (_("More than one component found with name [%s]\n"),
  +                       new_basename);
  +        /* PB: for now, use the first directory in clibs */
  +        /* PB: maybe open a dialog to select the right one? */
  +      }
  +      new_clib = g_strdup ((gchar*)clibs->data);
  +      o_current->complex_clib = new_clib;
  +
  +      s_log_message (_("Component [%s] has been successfully unembedded\n"),
  +                     o_current->complex_basename);
  +      
  +      /* page content has been modified */
  +      w_current->page_current->CHANGED = 1;
  +      
  +    }
  +  }
  +
  +  /* If it's a picture and it's embedded */
  +  if ( (o_current->type == OBJ_PICTURE) &&
  +       (o_current->picture->embedded == 1) ) {
  +
  +    o_current->picture->embedded = 0;
  +    
  +    s_log_message (_("Picture [%s] has been unembedded\n"),
  +		   basename(o_current->picture->filename));
  +    
  +    
  +    /* page content has been modified */
  +    w_current->page_current->CHANGED = 1;
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_mirror(TOPLEVEL *w_current, SELECTION *list, int centerx, int centery)
  +{
  +  OBJECT *object;
  +  SELECTION *s_current;
  +  OBJECT *o_current = NULL;
  +  GList *other_objects=NULL;
  +  GList *connected_objects=NULL;
  +
  +  if (list == NULL) {
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    return;
  +  }
  +
  +  s_current = list;
  +
  +  while (s_current != NULL) {
  +
  +    object = s_current->selected_object;
  +
  +    if (!object) {
  +      fprintf(stderr, _("ERROR: NULL object in o_mirror!\n"));
  +      return;
  +    }
  +    
  +    g_list_free(other_objects);
  +    other_objects = NULL;
  +    g_list_free(connected_objects);
  +    connected_objects = NULL;
  +
  +    switch(object->type) {
  +
  +
  +      case(OBJ_NET):
  +        o_cue_undraw(w_current, object);
  +        o_net_erase(w_current, object);
  +        o_line_erase_grips(w_current, object);
  +        
  +        other_objects = s_conn_return_others(other_objects, object);
  +        s_conn_remove(w_current, object);
  +
  +        o_net_mirror(w_current, centerx, centery, object);
  +        s_conn_update_object(w_current, object);
  +        o_net_draw(w_current, object);
  +        
  +        /* draw the other objects */
  +        o_cue_undraw_list(w_current, other_objects);
  +        o_cue_draw_list(w_current, other_objects);
  +
  +        /* get other connected objects and redraw */
  +        connected_objects = s_conn_return_others(connected_objects, object);
  +        o_cue_undraw_list(w_current, connected_objects);
  +        o_cue_draw_list(w_current, connected_objects);
  +
  +        /* finally redraw the cues on the current object */
  +        o_cue_draw_single(w_current, object); 
  +        break;
  +
  +      case(OBJ_PIN):
  +        o_cue_undraw(w_current, object);
  +        o_pin_erase(w_current, object);
  +        o_line_erase_grips(w_current, object);
  +        
  +        other_objects = s_conn_return_others(other_objects, object);
  +        s_conn_remove(w_current, object);
  +
  +        o_pin_mirror(w_current, centerx, centery, object);
  +        s_conn_update_object(w_current, object);
  +        o_pin_draw(w_current, object);
  +
  +        /* draw the other objects */
  +        o_cue_undraw_list(w_current, other_objects);
  +        o_cue_draw_list(w_current, other_objects);
  +
  +        /* get other connected objects and redraw */
  +        connected_objects = s_conn_return_others(connected_objects, object);
  +        o_cue_undraw_list(w_current, connected_objects);
  +        o_cue_draw_list(w_current, connected_objects);
  +
  +        /* finally redraw the cues on the current object */
  +        o_cue_draw_single(w_current, object); 
  +        break;
  +
  +      case(OBJ_BUS):
  +        o_bus_erase(w_current, object);
  +        o_line_erase_grips(w_current, object);
  +
  +        other_objects = s_conn_return_others(other_objects, object);
  +        s_conn_remove(w_current, object);
  +        
  +        o_bus_mirror(w_current, centerx, centery, object);
  +        s_conn_update_object(w_current, object);
  +        o_bus_draw(w_current, object);
  +        
  +        /* draw the other objects */
  +        o_cue_undraw_list(w_current, other_objects);
  +        o_cue_draw_list(w_current, other_objects);
  +
  +        /* get other connected objects and redraw */
  +        connected_objects = s_conn_return_others(connected_objects, object);
  +        o_cue_undraw_list(w_current, connected_objects);
  +        o_cue_draw_list(w_current, connected_objects);
  +
  +        /* finally redraw the cues on the current object */
  +        o_cue_draw_single(w_current, object); 
  +        break;
  +        
  +      case(OBJ_COMPLEX):
  +        o_cue_undraw_objects(w_current, object->complex->prim_objs);
  +        /* erase the current selection */
  +        o_complex_erase(w_current, object);
  +
  +        other_objects = s_conn_return_complex_others(other_objects, object);
  +        
  +        /* remove all conn references */
  +        o_current = object->complex->prim_objs;
  +        while(o_current != NULL) {
  +          s_conn_remove(w_current, o_current);
  +          o_current = o_current->next;
  +        }
  +      
  +        o_complex_mirror(w_current, centerx, centery, object);
  +        s_conn_update_complex(w_current, object->complex->prim_objs);
  +        o_complex_draw(w_current, object);
  +
  +        o_cue_undraw_list(w_current, other_objects);
  +        o_cue_draw_list(w_current, other_objects);
  +
  +        /* now draw the newly connected objects */
  +        connected_objects = s_conn_return_complex_others(connected_objects,
  +                                                         object);
  +        o_cue_undraw_list(w_current, connected_objects);
  +        o_cue_draw_list(w_current, connected_objects);
  +        break;
  +
  +      case(OBJ_LINE):
  +        o_line_erase_grips(w_current, object);
  +        o_line_erase(w_current, object);
  +        o_line_mirror(w_current,
  +                      centerx, centery, object);
  +        o_line_draw(w_current, object);
  +        break;
  +
  +      case(OBJ_BOX):
  +        o_box_erase_grips(w_current, object);
  +        o_box_erase(w_current, object);
  +        o_box_mirror(w_current,
  +                     centerx, centery, object);
  +        o_box_draw(w_current, object);
  +        break;
  +
  +      case(OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +        o_picture_erase_grips(w_current, object);
  +        o_picture_erase(w_current, object);
  +        o_picture_mirror(w_current,
  +			 centerx, centery, object);
  +        o_picture_draw(w_current, object);
  +#endif
  +        break;
  +
  +      case(OBJ_CIRCLE):
  +        o_circle_erase_grips(w_current, object);
  +        o_circle_erase(w_current, object);
  +        o_circle_mirror(w_current,
  +                        centerx, centery, object);
  +        o_circle_draw(w_current, object);
  +        break;
  +
  +      case(OBJ_ARC):
  +        o_arc_erase(w_current, object);
  +#if 0 /* not needed anymore */
  +	SCREENtoWORLD(w_current, centerx, centery, 
  +		      &world_centerx, &world_centery);
  +#endif
  +        o_arc_mirror(w_current, centerx, centery, object);
  +        o_arc_draw(w_current, object);
  +        break;
  +
  +      case(OBJ_TEXT):
  +        o_text_erase(w_current, object);
  +        o_text_mirror(w_current,
  +                      centerx, centery, object);
  +        o_text_draw(w_current, object);
  +        break;
  +
  +    }
  +
  +    s_current = s_current->next;
  +
  +  }
  +
  +  /* All objects were rotated. Do a 2nd pass to run the rotate hooks */
  +  /* Do not run any hooks for simple objects here, like text, since they
  +     were rotated in the previous pass, and the selection list can contain
  +     an object and all its attributes (text) */
  +  s_current = list;
  +  while (s_current != NULL) {
  +    object = s_current->selected_object;
  +
  +    if (!object) {
  +      fprintf(stderr, _("ERROR: NULL object in o_rotate_90!\n"));
  +      return;
  +    }
  +
  +    switch(object->type) {
  +      case(OBJ_PIN):
  +	/* Run the rotate pin hook */
  +	if (scm_hook_empty_p(mirror_pin_hook) == SCM_BOOL_F &&
  +	    object != NULL) {
  +	  scm_run_hook(rotate_pin_hook,
  +		       scm_cons(g_make_object_smob(w_current, object),
  +				SCM_EOL));
  +	}
  +	break;
  +
  +      case (OBJ_COMPLEX):
  +	/* Run the rotate pin hook */
  +	if (scm_hook_empty_p(rotate_component_object_hook) == SCM_BOOL_F &&
  +	    object != NULL) {
  +	  scm_run_hook(mirror_component_object_hook,
  +		       scm_cons(g_make_object_smob(w_current, object),
  +				SCM_EOL));
  +	}
  +	break;
  +    default:
  +	break;
  +    }
  +
  +    s_current = s_current->next;
  +  }
  +
  +
  +  w_current->page_current->CHANGED=1;
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_edit_show_hidden_lowlevel(TOPLEVEL *w_current, OBJECT *o_list)
  +{
  +  OBJECT *o_current = o_list;
  +
  +  if (o_current == NULL) {
  +    return;
  +  }
  +
  +  while(o_current != NULL) {
  +    if (o_current->type == OBJ_TEXT && o_current->visibility == INVISIBLE) {
  +
  +      /* don't toggle the visibility flag */
  +
  +      if (w_current->show_hidden_text) {
  +        /* draw the text object if it hidden  */
  +        if (o_current->text->prim_objs == NULL) {
  +          o_text_recreate(w_current, o_current);
  +        }
  +        o_text_recalc(w_current, o_current);
  +        o_text_draw(w_current, o_current);
  +      } else {
  +        /* object is hidden and we are now NOT drawing it, so */
  +        /* get rid of the extra primitive data */
  +        o_text_recreate(w_current, o_current);
  +        o_text_recalc(w_current, o_current);
  +        /* unfortunately, you cannot erase the old visible text here */
  +        /* because o_text_draw will just return */
  +      }    
  +    }
  +
  +    if (o_current->type == OBJ_COMPLEX || o_current->type == OBJ_PLACEHOLDER) {
  +      o_edit_show_hidden_lowlevel(w_current, o_current->complex->prim_objs);
  +      o_complex_recalc(w_current, o_current);
  +    }
  +   
  +    o_current = o_current->next;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_edit_show_hidden(TOPLEVEL *w_current, OBJECT *o_list)
  +{
  +  /* this function just shows the hidden text, but doesn't toggle it */
  +  /* this function does not change the CHANGED bit, no real changes are */
  +  /* made to the schematic */
  +  
  +  /* toggle show_hidden_text variable, which when it is true */
  +  /* means that hidden text IS drawn */
  +  w_current->show_hidden_text = !w_current->show_hidden_text;
  +  i_show_state(w_current, NULL); /* update screen status */
  +
  +  o_edit_show_hidden_lowlevel(w_current, o_list);
  +  o_redraw_all_fast(w_current);
  +
  +  if (w_current->show_hidden_text) {
  +    s_log_message(_("Hidden text is now visible\n"));
  +  } else {
  +    s_log_message(_("Hidden text is now invisible\n"));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_edit_make_visible(TOPLEVEL *w_current, OBJECT *o_list)
  +{
  +  /* this function actually changes the visibility flag */
  +  OBJECT *o_current = NULL;
  +
  +  if (o_list == NULL)
  +  return;
  +  o_current = o_list;
  +
  +  while(o_current != NULL) {
  +
  +    if (o_current->type == OBJ_TEXT) {
  +      if (o_current->visibility == INVISIBLE) {
  +        o_current->visibility = VISIBLE;
  +
  +        if (o_current->text->prim_objs == NULL) {
  +          o_text_recreate(w_current, o_current);
  +        }
  +
  +        o_text_draw(w_current, o_current);
  +
  +        w_current->page_current->CHANGED = 1; 
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +
  +}
  +
  +#define FIND_WINDOW_HALF_SIZE (5000)
  +
  +OBJECT *last_o = NULL;
  +int skiplast;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +int o_edit_find_text(TOPLEVEL * w_current, OBJECT * o_list, char *stext,
  +		     int descend, int skip)
  +{
  +
  +  char *attrib = NULL;
  +  int count = 0;
  +  PAGE *parent = NULL;
  +  char *current_filename = NULL;
  +  int page_control = 0;
  +  int pcount = 0;
  +  int rv;
  +  int text_screen_height;
  +
  +  OBJECT *o_current = NULL;
  +
  +  skiplast = skip;
  +  o_current = o_list;
  +
  +  if (o_current == NULL) {
  +    return 1;
  +  }
  +
  +  while (o_current != NULL) {
  +
  +    if (descend) {
  +      if (o_current->type == OBJ_COMPLEX) {
  +	parent = w_current->page_current;
  +	attrib = o_attrib_search_name_single_count(o_current,
  +						   "source", count);
  +
  +	/* if above is null, then look inside symbol */
  +	if (attrib == NULL) {
  +	  attrib = o_attrib_search_name(o_current->
  +					complex->
  +					prim_objs, "source", count);
  +	  /*          looking_inside = TRUE; */
  +	}
  +
  +	if (attrib) {
  +	  pcount = 0;
  +	  current_filename = u_basic_breakup_string(attrib, ',', pcount);
  +	  if (current_filename != NULL) {
  +	    page_control =
  +		s_hierarchy_down_schematic_single(w_current,
  +						  current_filename,
  +						  parent,
  +						  page_control,
  +						  HIERARCHY_NORMAL_LOAD);
  +	    /* o_redraw_all(w_current); */
  +
  +	    rv = o_edit_find_text(w_current,
  +				  w_current->page_current->object_head,
  +				  stext, descend, skiplast);
  +	    if (!rv) {
  +	      return 0;
  +	    }
  +	    s_hierarchy_up(w_current, w_current->page_current->up);
  +	  }
  +	}
  +      }
  +    }
  +
  +    if (o_current->type == OBJ_TEXT) {
  +     /* replaced strcmp with strstr to simplify the search */
  +      if (strstr(o_current->text->string,stext)) {
  +	/*            printf(_("Found %s\n"), stext);
  +	   if (!o_current->selected&&(!descend)) {
  +	   o_selection_add(w_current->page_current->selection2_head,
  +	   o_current);
  +	   } */
  +	if (!skiplast) {
  +
  +#if 0 /* replaced by code below by avh, might not quite be right though */
  +	  set_window(w_current, o_current->text->x - FIND_WINDOW_HALF_SIZE,
  +		     o_current->text->x + FIND_WINDOW_HALF_SIZE,
  +		     o_current->text->y - FIND_WINDOW_HALF_SIZE,
  +		     o_current->text->y + FIND_WINDOW_HALF_SIZE);
  +          correct_aspect(w_current);
  +
  +#endif
  +          a_zoom(w_current, ZOOM_FULL, DONTCARE, A_PAN_DONT_REDRAW);
  +          text_screen_height =  SCREENabs(w_current,
  +                                          o_text_height(o_current->
  +							text->string,
  +                                                        o_current->
  +                                                        text->size));
  +          /* this code will zoom/pan till the text screen height is about */
  +          /* 50 pixels high, perhaps a future enhancement will be to make */
  +          /* this number configurable */
  +          while (text_screen_height < 50) {
  +            a_zoom(w_current, ZOOM_IN, DONTCARE, A_PAN_DONT_REDRAW);
  +            text_screen_height =  SCREENabs(w_current,
  +                                            o_text_height(o_current->
  +							  text->string,
  +                                                          o_current->
  +                                                          text->size));
  +          }
  +	  a_pan_general(w_current, o_current->text->x, o_current->text->y, 
  +			1, 0);
  +
  +	  last_o = o_current;
  +	  break;
  +	}
  +	if (last_o == o_current) {
  +	  skiplast = 0;
  +	}
  +
  +      }
  +    }
  +    o_current = o_current->next;
  +
  +    if (o_current == NULL) {
  +      return 1;
  +    }
  +  }
  +  return (o_current == NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +int autonumber_sort_numbers(gconstpointer a, gconstpointer b) {
  +  if (GPOINTER_TO_INT(a) < GPOINTER_TO_INT(b))
  +    return -1;
  +  if (GPOINTER_TO_INT(a) > GPOINTER_TO_INT(b))
  +    return 1;
  +  return 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +int autonumber_sort_xy(gconstpointer a, gconstpointer b) {
  +  OBJECT *aa, *bb;
  +  aa=(OBJECT *) a;  bb=(OBJECT *) b;
  +  if (aa->text->x < bb->text->x)
  +    return -1;
  +  if (aa->text->x > bb->text->x)
  +    return 1;
  +  /* x == x */
  +  if (aa->text->y > bb->text->y)
  +    return -1;
  +  if (aa->text->y < bb->text->y)
  +    return 1;
  +  return 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +int autonumber_sort_yx(gconstpointer a, gconstpointer b) {
  +  OBJECT *aa, *bb;
  +  aa=(OBJECT *) a;  bb=(OBJECT *) b;
  +  if (aa->text->y > bb->text->y)
  +    return -1;
  +  if (aa->text->y < bb->text->y)
  +    return 1;
  +  /* x == x */
  +  if (aa->text->x < bb->text->x)
  +    return -1;
  +  if (aa->text->x > bb->text->x)
  +    return 1;
  +  return 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +int autonumber_sort_diagonal(gconstpointer a, gconstpointer b) {
  +  OBJECT *aa, *bb;
  +  aa=(OBJECT *) a;  bb=(OBJECT *) b;
  +  if (aa->text->x - aa->text->y < bb->text->x - bb->text->y)
  +    return -1;
  +  if (aa->text->x - aa->text->y > bb->text->x - bb->text->y)
  +    return 1;
  +  return 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void autonumber_find(TOPLEVEL * w_current, OBJECT * o_list, char *stext, 
  +		     GSList **used_numbers, int skip)
  +{
  +  OBJECT *o_current = NULL;
  +  char *attrib = NULL;
  +  int count = 0;
  +  PAGE *parent = NULL;
  +  char *current_filename = NULL;
  +  int page_control = 0;
  +  int pcount = 0;
  +  int l, m;
  +
  +  for (o_current = o_list; o_current != NULL; o_current=o_current->next) {
  +    if (o_current->type == OBJ_TEXT && skip != AUTONUMBER_SKIP_PAGE) {
  +      if (!(o_current->selected) || skip != AUTONUMBER_SKIP_SELECTION) {
  +	if ((l = strlen(o_current->text->string) - strlen(stext)) > 0) {
  +	  if (!strncmp(stext, o_current->text->string, strlen(stext))) {
  +	    if (isdigit((int) o_current->text->string[strlen(stext)])) {
  +	      sscanf(o_current->text->string + strlen(stext), "%d", &m);
  +	      *used_numbers = g_slist_append(*used_numbers,GINT_TO_POINTER(m));
  +	      /* printf(" %d\n", m);*/
  +	    }
  +	  }
  +	}
  +      }
  +    }
  +    if (o_current->type == OBJ_COMPLEX) {
  +      parent = w_current->page_current;
  +      attrib = o_attrib_search_name_single_count(o_current,
  +						 "source", count);
  +
  +      /* if above is null, then look inside symbol */
  +      if (attrib == NULL) {
  +	attrib = o_attrib_search_name(o_current->
  +				      complex->prim_objs, "source", count);
  +	/* looking_inside = TRUE; */
  +      }
  +
  +      if (attrib) {
  +	pcount = 0;
  +	current_filename = u_basic_breakup_string(attrib, ',', pcount);
  +	if (current_filename != NULL) {
  +	  /* printf("autonumber_find: recursion filename \"%s\"\n",
  +	     current_filename); */
  +	  page_control =
  +	    s_hierarchy_down_schematic_single(w_current,
  +					      current_filename,
  +					      parent,
  +					      page_control,
  +					      HIERARCHY_NORMAL_LOAD);
  +	  if (page_control != -1) {
  +	    autonumber_find(w_current, w_current->page_current->object_head,
  +			    stext, used_numbers, AUTONUMBER_SKIP_NOT);
  +	    s_hierarchy_up(w_current, w_current->page_current->up);
  +	  }
  +	  else {
  +	    s_log_message(_("Cannot find source [%s]\n"),
  +			  current_filename);
  +	    fprintf(stderr,
  +		    _("Cannot find source [%s]\n"), current_filename);
  +	  }
  +	}
  +      } 
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void autonumber_text(TOPLEVEL * w_current, char *stext, GSList **used, 
  +		     int *currentnumber, int unnumbered, int searchfocus, 
  +		     int sortorder)
  +{
  +  GSList *o_list = NULL;
  +  OBJECT *o_current = NULL;
  +  GSList *o_list_complex = NULL;
  +  OBJECT *o_complex_current = NULL;
  +  GSList *item;
  +
  +  char *attrib = NULL;
  +  int count = 0;
  +  PAGE *parent = NULL;
  +  char *current_filename = NULL;
  +  int page_control = 0;
  +  int save_page_control = 0;
  +  int pcount = 0;
  +
  +  char *ss;
  +  int l;
  +
  +  o_current = w_current->page_current->object_head;
  +
  +  for (o_current = w_current->page_current->object_head; o_current != NULL;
  +       o_current = o_current->next) {
  +    if (o_current->type == OBJ_COMPLEX) {
  +      o_list_complex = g_slist_append(o_list_complex, o_current);
  +    }
  +    if (o_current->type == OBJ_TEXT) {
  +      if (searchfocus != FOCUS_SELECTION || o_current->selected) {
  +	if ((l = strlen(o_current->text->string) - strlen(stext)) > 0) {
  +	  if (!strncmp(stext, o_current->text->string, strlen(stext))) {
  +	    if (o_current->text->string[strlen(stext)] == '?'
  +		|| (isdigit((int) o_current->text->string[strlen(stext)])
  +		    && unnumbered == SELECTION_ALL)){
  +	      o_list=g_slist_append(o_list,o_current);
  +	      /* printf("autonumber_text: text \"%s\" \n", 
  +		 o_current->text->string);*/
  +	    }
  +	  }
  +	}
  +      }
  +    }
  +  }
  +
  +  /* sort o_list */
  +  switch (sortorder) {
  +  case AUTONUMBER_SORT_YX:
  +    o_list=g_slist_sort(o_list,autonumber_sort_yx);
  +    break;
  +  case AUTONUMBER_SORT_XY:
  +    o_list=g_slist_sort(o_list,autonumber_sort_xy);
  +    break;
  +  case AUTONUMBER_SORT_DIAGONAL:
  +    o_list=g_slist_sort(o_list,autonumber_sort_diagonal);
  +    break;
  +  default:
  +    ; /* unsorted file order */
  +  }
  +
  +  for (item=o_list; item != NULL; item=g_slist_next(item)) {
  +    o_current= item->data;
  +    free(o_current->text->string);
  +
  +    while (*used != NULL && *currentnumber > GPOINTER_TO_INT((*used)->data)) {
  +      *used=(*used)->next;
  +    }
  +
  +    while (*used != NULL && *currentnumber == GPOINTER_TO_INT((*used)->data)) {
  +      *used=(*used)->next;
  +      (*currentnumber)++;
  +      while (*used != NULL && *currentnumber > GPOINTER_TO_INT((*used)->data))
  +	*used=(*used)->next;
  +    }
  +
  +    /* printf("autonumber_text: currentnumber %d\n",*currentnumber);*/
  +
  +    ss = g_strdup_printf("%s%d", stext, (*currentnumber)++);
  +    /*            printf("%s\n", ss); */
  +    o_current->text->string =
  +      (char *) malloc(sizeof(char) * (strlen(ss) + 1));
  +    strcpy(o_current->text->string, ss);
  +    free(ss);
  +    o_text_erase(w_current, o_current);
  +    o_text_recreate(w_current, o_current);
  +    o_text_draw(w_current, o_current);
  +    w_current->page_current->CHANGED = 1;
  +  }
  +
  +  /* only walk down the hierarchy if requested */
  +  if (searchfocus == FOCUS_ALL) {
  +    for (item=o_list_complex; item != NULL; item=g_slist_next(item)) {
  +      o_complex_current= item->data;
  +      parent = w_current->page_current;
  +      attrib = o_attrib_search_name_single_count(o_complex_current,
  +						 "source", count);
  +
  +      /* if above is null, then look inside symbol */
  +      if (attrib == NULL) {
  +	attrib = o_attrib_search_name(o_complex_current->
  +				      complex->prim_objs, "source", count);
  +	/*            looking_inside = TRUE; */
  +      }
  +
  +      if (attrib) {
  +	pcount = 0;
  +	current_filename = u_basic_breakup_string(attrib, ',', pcount);
  +	if (current_filename != NULL) {
  +	  save_page_control = page_control;
  +	  page_control =
  +	    s_hierarchy_down_schematic_single(w_current,
  +					      current_filename,
  +					      parent,
  +					      page_control,
  +					      HIERARCHY_NORMAL_LOAD);
  +	  if (page_control != -1) {
  +	    autonumber_text(w_current, stext, used, currentnumber, 
  +			    unnumbered, searchfocus, sortorder);
  +	    s_hierarchy_up(w_current, w_current->page_current->up);
  +	  }
  +	  else {
  +	    /* restore if we failed to load the page */
  +	    page_control = save_page_control;
  +	  }
  +	}
  +      }
  +    }
  +  }
  +  g_slist_free(o_list);
  +  g_slist_free(o_list_complex);
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_edit_autonumber_text(TOPLEVEL * w_current, char * searchtext,
  +			    int startnumber,int searchfocus,
  +			    int unnumbered, int sortorder)
  +{
  +  GSList *used_numbers=NULL;
  +  GSList *searchtext_list=NULL;
  +  GSList *item;
  +  char* stext=NULL;
  +  int skip_numbering=AUTONUMBER_SKIP_NOT;
  +  GSList *used_iterator=NULL;  /* used in recursive autonumber_text */
  +  int currentnumber;           /* used in recursive autonumber_text */
  +
  +  /* Step2: if searchtext has an asterisk at the end we have to find
  +     all matching searchtextes. 
  +     The function can take care of the selection options.
  +     The search function should return all possibles searchtexts that have
  +     its own number space.
  +     This requires something like:
  +       grep searchtext | sort | uniq
  +     in the object list down the hierarchy.
  +
  +     Example:  "refdes=*" will match each text that starts with "refdes="
  +     and has a trailing "?" (and a trailing number if the "all"-option is set.
  +     The function should return a list of all possible prefixes:
  +     refdes=R, refdes=C in the same way the searchstring is entered.
  +
  +     If there is only one search pattern, it becomes a single item
  +     in the searchtext list */
  +
  +  if (searchtext[strlen(searchtext)-1] == '*') {
  +    fprintf(stderr,"o_edit_autonumber_text: multiple searchtext option\n"
  +	    "  not implemented yet\n");
  +    /* collect the possible searchtextes, not implemented yet */
  +  }
  +  else {
  +    /* single searchtext */
  +    searchtext_list=g_slist_append (searchtext_list, searchtext);
  +  }
  +
  +  /* Step3: iterate over the search item in the list */
  +  for (item=searchtext_list; item !=NULL; item=g_slist_next(item)) {
  +    stext = item->data;
  +    /* printf("o_edit_autonumber_text: iterate text: \"%s\"\n",stext);*/
  +    /* Step3.1: get the used numbers, ignore numbers that will be overwritten*/
  +    if (unnumbered==SELECTION_ALL && searchfocus==FOCUS_ALL) {
  +      ; /* all numbers will be overwritten, don't search */
  +    }
  +    else {
  +      if (unnumbered == SELECTION_ALL && searchfocus == FOCUS_SHEET)
  +	skip_numbering = AUTONUMBER_SKIP_PAGE;
  +      if (unnumbered == SELECTION_ALL && searchfocus == FOCUS_SELECTION)
  +	skip_numbering = AUTONUMBER_SKIP_SELECTION;
  +
  +      autonumber_find(w_current, w_current->page_current->object_head, 
  +		   stext, &used_numbers, skip_numbering);
  +    }
  +
  +    /* printf("o_edit_autonumber_text: listlength: %d\n",
  +       g_slist_length(used_numbers)); */
  +    /* sort used numbers */
  +    used_numbers=g_slist_sort(used_numbers,autonumber_sort_numbers);
  +
  +  /* Step3.2: get a list of all matching objects 
  +              sort the list (sort option)
  +	      renumber all objects (start number option)
  +     this whole step is done in the autonumber_text function */
  +    used_iterator=used_numbers;
  +    currentnumber=startnumber;
  +    autonumber_text(w_current, stext, &used_iterator, &currentnumber, 
  +		    unnumbered, searchfocus, sortorder);
  +    g_slist_free(used_numbers);
  +    used_numbers=NULL;
  +  }
  +  g_slist_free(searchtext_list);
  +  o_redraw_all(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_edit_hide_specific_text(TOPLEVEL * w_current, OBJECT * o_list,
  +			       char *stext)
  +{
  +  OBJECT *o_current = NULL;
  +
  +  if (o_list == NULL)
  +    return;
  +
  +  o_current = o_list;
  +
  +  while (o_current != NULL) {
  +
  +    if (o_current->type == OBJ_TEXT) {
  +      if (!strncmp(stext, o_current->text->string, strlen(stext))) {
  +	if (o_current->visibility == VISIBLE) {
  +	  o_current->visibility = INVISIBLE;
  +
  +	  if (o_current->text->prim_objs == NULL) {
  +	    o_text_recreate(w_current, o_current);
  +	  }
  +	  w_current->page_current->CHANGED = 1;
  +	}
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +  o_redraw_all(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_edit_show_specific_text(TOPLEVEL * w_current, OBJECT * o_list,
  +			       char *stext)
  +{
  +  OBJECT *o_current = NULL;
  +
  +  if (o_list == NULL)
  +    return;
  +
  +  o_current = o_list;
  +
  +  while (o_current != NULL) {
  +
  +    if (o_current->type == OBJ_TEXT) {
  +      if (!strncmp(stext, o_current->text->string, strlen(stext))) {
  +	if (o_current->visibility == INVISIBLE) {
  +	  o_current->visibility = VISIBLE;
  +
  +	  if (o_current->text->prim_objs == NULL) {
  +	    o_text_recreate(w_current, o_current);
  +	  }
  +	  o_text_draw(w_current, o_current);
  +	  w_current->page_current->CHANGED = 1;
  +	}
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void o_update_component(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  OBJECT *tmp_list, *new_complex;
  +  ATTRIB *new_attribs, *a_current;
  +  gboolean is_embedded;
  +  gchar *basename, *clib;
  +
  +  is_embedded = o_complex_is_embedded (o_current);
  +
  +  /* identify symbol name */
  +  if (is_embedded) {
  +    const GSList *clibs;
  +    
  +    /* skip over EMBEDDED word */
  +    basename = g_strdup (o_current->complex_basename + 8);
  +
  +    /* search for basename in component library */
  +    clibs    = s_clib_search_basename (basename);
  +    if (!clibs) {
  +      s_log_message (_("Could not unembedded component, could not find appropriate .sym file\n"));
  +      s_log_message (_("Component still embedded and not updated\n"));
  +      return;
  +    }
  +    if (g_slist_next (clibs)) {
  +      s_log_message (_("More than one component found with name [%s]\n"),
  +                     basename);
  +      /* PB: for now, use the first directory in clibs */
  +      /* PB: maybe open a dialog to select the right one? */
  +    }
  +    clib = (gchar*)clibs->data;
  +  } else {
  +    basename = o_current->complex_basename;
  +    clib     = o_current->complex_clib;
  +  }
  +
  +  /* erase the complex object */
  +  o_erase_single (w_current, o_current);
  +  /* delete its connections */
  +  s_conn_remove_complex (w_current, o_current);
  +  /* and unselect but keep it in the selection list */
  +  o_selection_unselect (o_current);
  +
  +  /* build a temporary list and add a complex to this list */
  +  tmp_list = s_basic_init_object ("update component");
  +  new_complex = o_complex_add (w_current,
  +                               tmp_list,
  +                               OBJ_COMPLEX,
  +                               WHITE,
  +                               o_current->complex->x,
  +                               o_current->complex->y,
  +                               o_current->complex->angle,
  +                               o_current->complex->mirror,
  +                               clib, basename, 1, TRUE);
  +
  +  /* updating the old complex with data from the new one */
  +  /* first process the prim_objs: */
  +  /*   - delete the prim_objs of the old component */
  +  s_delete_list_fromstart (w_current, 
  +                           o_current->complex->prim_objs);
  +  /*   - put the prim_objs of the new component in the old one */
  +  o_current->complex->prim_objs = new_complex->complex->prim_objs;
  +  /*   - reset the new complex prim_objs */
  +  new_complex->complex->prim_objs = NULL;
  +
  +  /* then process the attributes: */
  +  new_attribs = new_complex->attribs;
  +  /*   - check each attrib of the new complex */
  +  a_current = new_attribs ? new_attribs->next : NULL;
  +  while (a_current != NULL) {
  +    OBJECT *o_attrib;
  +    gchar *name, *value;
  +    g_assert (a_current->object->type == OBJ_TEXT);
  +    o_attrib_get_name_value (a_current->object->text->string,
  +                             &name, &value);
  +        
  +    if (o_attrib_search_name (o_current, name, 0) == NULL) {
  +      /* attribute with same name not found in old component: */
  +      /* add new attribute to old component */
  +            
  +      /* make a copy of the attribute object */
  +      o_list_copy_to (w_current, o_current,
  +                      a_current->object, NORMAL_FLAG, &o_attrib);
  +      if (o_current->attribs == NULL) {
  +        /* object has no attribute list: create it */
  +        o_current->attribs = add_attrib_head(o_current);
  +      }
  +      /* add the attribute to old */
  +      o_attrib_add (w_current, o_current->attribs, o_attrib);
  +      /* redraw the attribute object */
  +      o_redraw_single (w_current, o_attrib);
  +      /* note: this object is unselected (not added to selection). */
  +    }
  +
  +    a_current = a_current->next;
  +  }
  +    
  +  /* finally delete the temp list with the updated complex */
  +  s_delete_list_fromstart (w_current, tmp_list);
  +  /* reconnect, re-select and redraw */
  +  s_conn_update_complex (w_current, o_current->complex->prim_objs);
  +  o_selection_select (o_current, SELECT_COLOR);
  +  o_redraw_single (w_current, o_current);
  +    
  +  if (is_embedded) {
  +    /* we previously allocated memory for basename and clib */
  +    g_free (basename);
  +    g_free (clib);
  +  }
  +    
  +  /* mark the page as modified */
  +  w_current->page_current->CHANGED = 1;
  +  o_undo_savestate (w_current, UNDO_ALL);
  +    
  +}
  +
  +/*! \brief Do autosave on all pages that are marked.
  + *  \par Function Description
  + *  Looks for pages with the do_autosave_backup flag activated and
  + *  autosaves them.
  + *
  + *  \param [in] toplevel  The TOPLEVEL object to search for autosave's.
  + */
  +void o_autosave_backups(TOPLEVEL *toplevel)
  +{
  +  PAGE *p_save, *p_current;
  +  gchar *backup_filename;
  +  gchar *real_filename;
  +  gchar *only_filename;
  +  gchar *dirname;
  +  mode_t saved_umask;
  +  mode_t mask;
  +  struct stat st;
  +
  +  g_assert (toplevel->page_head != NULL &&
  +            toplevel->page_head->pid == -1);
  +
  +  /* save current page */
  +  p_save = toplevel->page_current;
  +  
  +  for (p_current = toplevel->page_head->next;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +
  +    if (p_current->do_autosave_backup == 0) {
  +      continue;
  +    }
  +    if (p_current->ops_since_last_backup != 0) {
  +      /* make p_current the current page of toplevel */
  +      s_page_goto (toplevel, p_current);
  +      
  +      /* Get the real filename and file permissions */
  +      real_filename = follow_symlinks (p_current->page_filename, NULL);
  +      
  +      if (real_filename == NULL) {
  +	s_log_message (_("o_autosave_backups: Can't get the real filename of %s."), p_current->page_filename);
  +	fprintf (stderr, "o_autosave_backups: Can't get the real filename of %s.\n", p_current->page_filename);
  +      }
  +      else {
  +	/* Get the directory in which the real filename lives */
  +	dirname = g_path_get_dirname (real_filename);
  +	only_filename = g_path_get_basename(real_filename);  
  +      
  +
  +	backup_filename = g_strdup_printf("%s%c"AUTOSAVE_BACKUP_FILENAME_STRING,
  +					  dirname, G_DIR_SEPARATOR, only_filename);
  +	
  +	/* If there is not an existing file with that name, compute the
  +	 * permissions and uid/gid that we will use for the newly-created file.
  +	 */
  +	
  +	if (stat (real_filename, &st) != 0)
  +	  {
  +	    struct stat dir_st;
  +	    int result;
  +	    
  +	    /* Use default permissions */
  +	    saved_umask = umask(0);
  +	    st.st_mode = 0666 & ~saved_umask;
  +	    umask(saved_umask);
  +	    st.st_uid = getuid ();
  +	    
  +	    result = stat (dirname, &dir_st);
  +	    
  +	    if (result == 0 && (dir_st.st_mode & S_ISGID))
  +	      st.st_gid = dir_st.st_gid;
  +	    else
  +	      st.st_gid = getgid ();
  +	  }
  +	g_free (dirname);
  +	g_free (only_filename);
  +	g_free (real_filename);
  +
  +	/* Make the backup file writable before saving a new one */
  +	if ( g_file_test (backup_filename, G_FILE_TEST_EXISTS) && 
  +	     (! g_file_test (backup_filename, G_FILE_TEST_IS_DIR))) {
  +	  saved_umask = umask(0);
  +	  if (chmod(backup_filename, (S_IWRITE|S_IWGRP|S_IWOTH) & 
  +		    ((~saved_umask) & 0777)) != 0) {
  +	    s_log_message (_("Could NOT set previous backup file [%s] read-write\n"), 
  +			   backup_filename);	    
  +	  }
  +	  umask(saved_umask);
  +	}
  +	
  +	if (o_save (toplevel, backup_filename)) {
  +
  +	  p_current->ops_since_last_backup = 0;
  +          p_current->do_autosave_backup = 0;
  +
  +	  /* Make the backup file readonly so a 'rm *' command will ask 
  +	     the user before deleting it */
  +	  saved_umask = umask(0);
  +	  mask = (S_IWRITE|S_IWGRP|S_IEXEC|S_IXGRP|S_IXOTH);
  +	  mask = (~mask)&0777;
  +	  mask &= ((~saved_umask) & 0777);
  +	  if (chmod(backup_filename,mask) != 0) {
  +	    s_log_message (_("Could NOT set backup file [%s] readonly\n"), 
  +			   backup_filename);	    
  +	  }
  +	  umask(saved_umask);
  +	} else {
  +	  s_log_message (_("Could NOT save backup file [%s]\n"), 
  +			 backup_filename);
  +	}
  +	g_free (backup_filename);
  +      }
  +    }
  +  }
  +  /* restore current page */
  +  s_page_goto (toplevel, p_save);
  +}
  
  
  
  1.28      +175 -236  eda/geda/gaf/gschem/src/o_move.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_move.c
  ===================================================================
  RCS file: o_move.c
  diff -N o_move.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_move.c	14 Jul 2006 02:23:55 -0000	1.28
  @@ -0,0 +1,655 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_move_start(TOPLEVEL * w_current, int x, int y)
  +{
  +  if (w_current->page_current->selection2_head->next != NULL) {
  +
  +    /* Save the current state. When rotating the selection when moving,
  +       we have to come back to here */
  +    o_undo_savestate(w_current, UNDO_ALL);
  +    w_current->last_drawb_mode = -1;
  +    w_current->event_state = MOVE;
  +
  +    w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +    w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +
  +    o_erase_selected(w_current);
  +    
  +    o_drawbounding(w_current, NULL,
  +                   w_current->page_current->selection2_head->next,
  +                   x_get_darkcolor(w_current->bb_color), TRUE);
  +
  +    if (w_current->netconn_rubberband) {
  +      o_move_prep_rubberband(w_current);
  +      o_move_stretch_rubberband(w_current);
  +    }
  +
  +    w_current->inside_action = 1;
  +  }
  +}
  +
  +#define SINGLE     0
  +#define COMPLEX    1
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  type can be SINGLE or COMPLEX
  + *  which basically controls if this is a single object or a complex
  + */
  +void o_move_end_lowlevel(TOPLEVEL * w_current, OBJECT * list, int type,
  +			 int diff_x, int diff_y,
  +			 int screen_diff_x, int screen_diff_y,
  +			 GList** other_objects, GList** connected_objects)
  +{
  +  OBJECT *o_current;
  +  OBJECT *object;
  +
  +  o_current = list;
  +  while (o_current != NULL) {
  +
  +    object = o_current;
  +    switch (object->type) {
  +
  +      case (OBJ_NET):
  +        /* save the other objects and remove object's connections */
  +        *other_objects = s_conn_return_others(*other_objects, object);
  +        s_conn_remove(w_current, object);
  +
  +        /* do the actual translation */
  +        o_net_translate_world(w_current, diff_x, diff_y, object);
  +        s_conn_update_object(w_current, object);
  +        *connected_objects = s_conn_return_others(*connected_objects, object);
  +        break;
  +
  +      case (OBJ_BUS):
  +        /* save the other objects and remove object's connections */
  +        *other_objects = s_conn_return_others(*other_objects, object);
  +        s_conn_remove(w_current, object);
  +
  +        o_bus_translate_world(w_current, diff_x, diff_y, object);
  +        s_conn_update_object(w_current, object);
  +        *connected_objects = s_conn_return_others(*connected_objects, object);
  +        break;
  +
  +      case (OBJ_PIN):
  +        /* save the other objects and remove object's connections */
  +        *other_objects = s_conn_return_others(*other_objects, object);
  +        s_conn_remove(w_current, object);
  +        
  +        o_pin_translate_world(w_current, diff_x, diff_y, object);
  +        s_conn_update_object(w_current, object);
  +        *connected_objects = s_conn_return_others(*connected_objects, object);
  +        break;
  +
  +      case (OBJ_LINE):
  +        o_line_translate_world(w_current, diff_x, diff_y, object);
  +        break;
  +
  +      case (OBJ_BOX):
  +        o_box_translate_world(w_current, diff_x, diff_y, object);
  +        break;
  +
  +      case (OBJ_PICTURE):
  +#ifndef HAS_GTK12
  +        o_picture_translate_world(w_current, diff_x, diff_y, object);
  +#endif
  +        break;
  +
  +      case (OBJ_CIRCLE):
  +        o_circle_translate_world(w_current, diff_x, diff_y, object);
  +        break;
  +
  +      case (OBJ_TEXT):
  +        o_text_translate_world(w_current, diff_x, diff_y, object);
  +        break;
  +
  +      case (OBJ_ARC):
  +        o_arc_translate_world(w_current, diff_x, diff_y, object);
  +        break;
  +
  +      case (OBJ_COMPLEX):
  +      case (OBJ_PLACEHOLDER):
  +	o_complex_world_translate (w_current, diff_x, diff_y, 
  +				   object->complex->prim_objs);
  +	break;
  +    }
  +
  +    if (type == COMPLEX) {
  +      o_current = o_current->next;
  +    } else {
  +      o_current = NULL;
  +    }
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_move_end(TOPLEVEL * w_current)
  +{
  +  SELECTION *s_current = NULL;
  +  OBJECT *object;
  +  int diff_x, diff_y;
  +  int screen_diff_x, screen_diff_y;
  +  int lx, ly;
  +  int sx, sy;
  +  int left, top, right, bottom;
  +  GList *other_objects = NULL;
  +  GList *connected_objects = NULL;
  +  GList *rubbernet_objects = NULL; 
  +  GList *rubbernet_other_objects = NULL;
  +  GList *rubbernet_connected_objects = NULL;
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  if (!object) {
  +    /* actually this is an error condition hack */
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    return;
  +  }
  +
  +  screen_diff_x = w_current->last_x - w_current->start_x;
  +  screen_diff_y = w_current->last_y - w_current->start_y;
  +
  +  SCREENtoWORLD(w_current, w_current->last_x, w_current->last_y,
  +                &lx, &ly);
  +  SCREENtoWORLD(w_current, w_current->start_x, w_current->start_y,
  +                &sx, &sy);
  +
  +  diff_x = lx - sx;
  +  diff_y = ly - sy;
  +
  +  if (w_current->netconn_rubberband)
  +  {
  +    o_move_end_rubberband(w_current, diff_x, diff_y,
  +                          &rubbernet_objects, &rubbernet_other_objects,
  +                          &rubbernet_connected_objects);
  +  }
  +
  +  if (w_current->actionfeedback_mode == OUTLINE) {
  +    o_drawbounding(w_current, NULL,
  +                   w_current->page_current->selection2_head->next,
  +                   x_get_darkcolor(w_current->bb_color), TRUE);
  +  }
  +  
  +  /* skip over head node */
  +  s_current = w_current->page_current->selection2_head->next;
  +
  +  while (s_current != NULL) {
  +
  +    if (s_current->selected_object == NULL) {
  +      fprintf(stderr, _("ERROR: NULL object in o_move_end!\n"));
  +      exit(-1);
  +    }
  +
  +
  +    object = s_current->selected_object;
  +    switch (object->type) {
  +      case (OBJ_NET):
  +      case (OBJ_PIN):
  +      case (OBJ_BUS):
  +      case (OBJ_LINE):
  +      case (OBJ_BOX):
  +      case (OBJ_PICTURE):
  +      case (OBJ_CIRCLE):
  +      case (OBJ_ARC):
  +      case (OBJ_TEXT):
  +        o_move_end_lowlevel(w_current, object, SINGLE, diff_x, diff_y,
  +                            screen_diff_x, screen_diff_y,
  +                            &other_objects, &connected_objects);
  +        break;
  +
  +      case (OBJ_COMPLEX):
  +      case (OBJ_PLACEHOLDER):
  +
  +        if (scm_hook_empty_p(move_component_hook) == SCM_BOOL_F &&
  +            object != NULL) {
  +          scm_run_hook(move_component_hook,
  +                       scm_cons (g_make_attrib_smob_list
  +                                 (w_current, object), SCM_EOL));
  +        }
  +
  +        /* this next section of code is from */
  +        /* o_complex_world_translate_toplevel */
  +        object->complex->x = object->complex->x + diff_x;
  +        object->complex->y = object->complex->y + diff_y;
  +
  +        WORLDtoSCREEN(w_current, object->complex->x,
  +                      object->complex->y,
  +                      &object->complex->screen_x,
  +                      &object->complex->screen_y);
  +
  +        o_move_end_lowlevel(w_current, object->complex->prim_objs,
  +                            COMPLEX, diff_x, diff_y,
  +                            screen_diff_x, screen_diff_y,
  +                            &other_objects, &connected_objects);
  +
  +
  +        get_complex_bounds(w_current, object->complex->prim_objs,
  +                           &left, &top, &right, &bottom);
  +
  +        object->left = left;
  +        object->top = top;
  +        object->right = right;
  +        object->bottom = bottom;
  +
  +        break;
  +    }
  +
  +    s_current = s_current->next;
  +  }
  +
  +  /* Remove the undo saved in o_move_start */
  +  o_undo_remove_last_undo(w_current);
  +
  +  /* erase the bounding box */
  +  if (w_current->actionfeedback_mode == BOUNDINGBOX) {
  +    o_drawbounding(w_current, NULL,
  +                   w_current->page_current->selection2_head->next,
  +                   x_get_darkcolor(w_current->bb_color), FALSE);
  +  }
  +
  +  /* Draw the objects that were moved (and connected/disconnected objects) */
  +  o_draw_selected(w_current);
  +  o_cue_undraw_list(w_current, other_objects);
  +  o_cue_draw_list(w_current, other_objects);
  +  o_cue_undraw_list(w_current, connected_objects);
  +  o_cue_draw_list(w_current, connected_objects);
  +
  +  /* Draw the connected nets/buses that were also changed */
  +  o_draw_list(w_current, rubbernet_objects);
  +  o_cue_undraw_list(w_current, rubbernet_objects);
  +  o_cue_draw_list(w_current, rubbernet_objects);
  +  o_cue_undraw_list(w_current, rubbernet_other_objects);
  +  o_cue_draw_list(w_current, rubbernet_other_objects);
  +  o_cue_undraw_list(w_current, rubbernet_connected_objects);
  +  o_cue_draw_list(w_current, rubbernet_connected_objects);
  + 
  +  w_current->page_current->CHANGED = 1;
  +  o_undo_savestate(w_current, UNDO_ALL);
  +
  +  g_list_free(other_objects);
  +  g_list_free(connected_objects);
  +  g_list_free(rubbernet_objects);
  +  g_list_free(rubbernet_other_objects);
  +  g_list_free(rubbernet_connected_objects);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_move_return_whichone(OBJECT * object, int x, int y)
  +{
  +  if (object->line->x[0] == x && object->line->y[0] == y) {
  +    return (0);
  +  }
  +
  +  if (object->line->x[1] == x && object->line->y[1] == y) {
  +    return (1);
  +  }
  +
  +  fprintf(stderr,
  +          _("DOH! tried to find the whichone, but didn't find it!\n"));
  +  return (-1);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_move_check_endpoint(TOPLEVEL * w_current, OBJECT * object)
  +{
  +  GList *cl_current;
  +  CONN *c_current;
  +  int whichone;
  +
  +  if (!object)
  +  return;
  +
  +  if (object->type != OBJ_NET && object->type != OBJ_PIN &&
  +      object->type != OBJ_BUS) {
  +    fprintf(stderr,
  +            _("Got a non line object in o_move_check_endpoint\n"));
  +    return;
  +  }
  +
  +  cl_current = object->conn_list;
  +  while (cl_current != NULL) {
  +
  +    c_current = (CONN *) cl_current->data;
  +
  +    if (c_current->other_object != NULL) {
  +
  +      /* really make sure that the object is not selected */
  +      if (c_current->other_object->saved_color == -1 &&
  +          c_current->other_object->selected == FALSE) {
  +
  +        if (c_current->type == CONN_ENDPOINT ||
  +            (c_current->type == CONN_MIDPOINT &&
  +             c_current->other_whichone != -1)) {
  +
  +          whichone =
  +            o_move_return_whichone(c_current->other_object,
  +                                   c_current->x, c_current->y);
  +
  +#if DEBUG
  +          printf
  +            ("FOUND: %s type: %d, whichone: %d, x,y: %d %d\n",
  +             c_current->other_object->name, c_current->type,
  +             whichone, c_current->x, c_current->y);
  +#endif
  +
  +#if DEBUG
  +          printf("other x,y: %d %d\n", c_current->x,
  +                 c_current->y);
  +          printf("type: %d return: %d real: [ %d %d ]\n",
  +                 c_current->type, whichone, c_current->whichone,
  +                 c_current->other_whichone);
  +#endif
  +
  +          if (whichone >= 0 && whichone <= 1) {
  +            w_current->page_current->stretch_tail =
  +              s_stretch_add(w_current->page_current->
  +                            stretch_head,
  +                            c_current->other_object,
  +                            c_current, whichone);
  +            
  +            if (c_current->other_object->type == OBJ_NET || 
  +                c_current->other_object->type == OBJ_BUS) {
  +              o_erase_single(w_current, c_current->other_object);
  +            }
  +          }
  +
  +        }
  +      }
  +    }
  +    cl_current = cl_current->next;
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_move_prep_rubberband(TOPLEVEL * w_current)
  +{
  +  SELECTION *s_current;
  +  OBJECT *object;
  +  OBJECT *o_current;
  +
  +  s_stretch_remove_most(w_current,
  +                        w_current->page_current->stretch_head);
  +  w_current->page_current->stretch_tail =
  +  w_current->page_current->stretch_head;
  +
  +#if DEBUG
  +  printf("\n\n\n");
  +  s_stretch_print_all(w_current->page_current->stretch_head);
  +  printf("\n\n\n");
  +#endif
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +  while (s_current != NULL) {
  +    object = s_current->selected_object;
  +    if (object) {
  +      switch (object->type) {
  +        case (OBJ_NET):
  +        case (OBJ_PIN):
  +        case (OBJ_BUS):
  +          o_move_check_endpoint(w_current, object);
  +          break;
  +
  +        case (OBJ_COMPLEX):
  +        case (OBJ_PLACEHOLDER):
  +          o_current = object->complex->prim_objs;
  +          while (o_current != NULL) {
  +
  +            if (o_current->type == OBJ_PIN) {
  +              o_move_check_endpoint(w_current, o_current);
  +            }
  +
  +            o_current = o_current->next;
  +          }
  +
  +          break;
  +
  +      }
  +    }
  +    s_current = s_current->next;
  +  }
  +
  +#if DEBUG
  +  printf("\n\n\n\nfinished building scretch list:\n");
  +  s_stretch_print_all(w_current->page_current->stretch_head);
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_move_zero_length(OBJECT * object)
  +{
  +#if DEBUG
  +  printf("x: %d %d y: %d %d\n",
  +         object->line->x[0], object->line->x[1],
  +         object->line->y[0], object->line->y[1]);
  +#endif
  +
  +  if (object->line->x[0] == object->line->x[1] &&
  +      object->line->y[0] == object->line->y[1]) {
  +    return TRUE;
  +  } else {
  +    return FALSE;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_move_end_rubberband(TOPLEVEL * w_current, int world_diff_x,
  +			   int world_diff_y,
  +			   GList** objects,
  +			   GList** other_objects, GList** connected_objects)
  +{
  +  STRETCH *s_current;
  +  OBJECT *object;
  +  int x, y;
  +  int whichone;
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->stretch_head->next;
  +
  +  while (s_current != NULL) {
  +    
  +    object = s_current->object;
  +    if (object) {
  +      whichone = s_current->whichone;
  +
  +      switch (object->type) {
  +        
  +        case (OBJ_NET):
  +          
  +          /* save the other objects and remove object's connections */
  +          *other_objects =
  +            s_conn_return_others(*other_objects, object);
  +          s_conn_remove(w_current, object);
  +
  +          x = object->line->x[whichone];
  +          y = object->line->y[whichone];
  +
  +#if DEBUG
  +          printf("OLD: %d, %d\n", x, y);
  +          printf("diff: %d, %d\n", world_diff_x, world_diff_y);
  +#endif
  +
  +          x = x + world_diff_x;
  +          y = y + world_diff_y;
  +
  +#if DEBUG
  +          printf("NEW: %d, %d\n", x, y);
  +#endif
  +
  +          object->line->x[whichone] = x;
  +          object->line->y[whichone] = y;
  +
  +
  +          if (o_move_zero_length(object)) {
  +            o_delete_net(w_current, object);
  +          } else {
  +            o_net_recalc(w_current, object);
  +            s_tile_update_object(w_current, object);
  +            s_conn_update_object(w_current, object);
  +            *connected_objects =
  +              s_conn_return_others(*connected_objects, object);
  +            *objects = g_list_append(*objects, object);
  +          }
  +
  +          break;
  +
  +        case (OBJ_PIN):
  +
  +          /* not valid to do with pins */
  +
  +          break;
  +
  +        case (OBJ_BUS):
  +
  +          /* save the other objects and remove object's connections */
  +          *other_objects =
  +            s_conn_return_others(*other_objects, object);
  +          s_conn_remove(w_current, object);
  +
  +          x = object->line->x[whichone];
  +          y = object->line->y[whichone];
  +
  +#if DEBUG
  +          printf("OLD: %d, %d\n", x, y);
  +          printf("diff: %d, %d\n", world_diff_x, world_diff_y);
  +#endif
  +          x = x + world_diff_x;
  +          y = y + world_diff_y;
  +
  +#if DEBUG
  +          printf("NEW: %d, %d\n", x, y);
  +#endif
  +          object->line->x[whichone] = x;
  +          object->line->y[whichone] = y;
  +
  +          if (o_move_zero_length(object)) {
  +            o_delete_bus(w_current, object);
  +          } else {
  +            o_bus_recalc(w_current, object);
  +            s_tile_update_object(w_current, object);
  +            s_conn_update_object(w_current, object);
  +            *connected_objects =
  +              s_conn_return_others(*connected_objects, object);
  +            *objects = g_list_append(*objects, object);
  +          }
  +
  +          break;
  +      }
  +    }
  +    
  +    s_current = s_current->next;
  +  }
  +
  +#if DEBUG
  +  /*! \bug FIXME: moved_objects doesn't exist? */
  +  /*printf("%d\n", g_list_length(*moved_objects));*/
  +  printf("%d\n", g_list_length(*other_objects));
  +  printf("%d\n", g_list_length(*connected_objects));
  +#endif
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_move_stretch_rubberband(TOPLEVEL * w_current)
  +{
  +
  +  STRETCH *s_current;
  +  OBJECT *object;
  +  int diff_x, diff_y;
  +  int whichone;
  +
  +  diff_x = w_current->last_x - w_current->start_x;
  +  diff_y = w_current->last_y - w_current->start_y;
  +
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->stretch_head->next;
  +  while (s_current != NULL) {
  +
  +    object = s_current->object;
  +    if (object) {
  +      whichone = s_current->whichone;
  +      switch (object->type) {
  +        case (OBJ_NET):
  +          o_net_draw_xor_single(w_current,
  +                                diff_x, diff_y, whichone, object);
  +          break;
  +
  +        case (OBJ_BUS):
  +          o_bus_draw_xor_single(w_current,
  +                                diff_x, diff_y, whichone, object);
  +          break;
  +      }
  +    }
  +    s_current = s_current->next;
  +  }
  +}
  
  
  
  1.26      +1033 -493 eda/geda/gaf/gschem/src/o_net.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_net.c
  ===================================================================
  RCS file: o_net.c
  diff -N o_net.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_net.c	14 Jul 2006 02:23:55 -0000	1.26
  @@ -0,0 +1,1154 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_net_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int size;
  +  int x1, y1, x2, y2; /* screen coords */
  +
  +#if NET_DEBUG /* debug */
  +  char *tempstring;
  +  GdkFont *font;
  +#endif
  +
  +  if (o_current == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  o_net_recalc(w_current, o_current);
  +
  +  /* reuse line's routine */
  +  if (!o_line_visible(w_current, o_current->line, &x1, &y1, &x2, &y2)) {
  +    return;
  +  }
  +
  +#if DEBUG
  +  printf("drawing net\n\n");
  +#endif
  +
  +  if (w_current->net_style == THICK ) {
  +    size = SCREENabs(w_current, NET_WIDTH);
  +
  +    if (size < 0)
  +      size=0;
  +
  +    gdk_gc_set_line_attributes(w_current->gc, size, 
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_BUTT,
  +                               GDK_CAP_NOT_LAST);
  +
  +    gdk_gc_set_line_attributes(w_current->bus_gc, size, 
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_BUTT,
  +                               GDK_CAP_NOT_LAST);
  +  }
  +
  +  if (w_current->override_color != -1 ) {
  +
  +    gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(w_current->override_color));
  +
  +    gdk_draw_line(w_current->window, w_current->gc,
  +                  x1, y1, x2, y2);
  +    gdk_draw_line(w_current->backingstore, w_current->gc,
  +                  x1, y1, x2, y2);
  +  } else {
  +
  +    gdk_gc_set_foreground(w_current->gc,
  +                          x_get_color(o_current->color));
  +    gdk_draw_line(w_current->window, w_current->gc,
  +                  x1, y1, x2, y2);
  +    gdk_draw_line(w_current->backingstore, w_current->gc,
  +                  x1, y1, x2, y2);
  +
  +
  +#if NET_DEBUG
  +    /* temp debug only */
  +    font = gdk_fontset_load ("10x20");
  +    tempstring = g_strdup_printf("%s", o_current->name);
  +    gdk_draw_text (w_current->window,
  +                   font,
  +                   w_current->gc,
  +                   x1+20, y1+20,
  +                   tempstring,
  +                   strlen(tempstring));
  +    gdk_draw_text (w_current->backingstore,
  +                   font,
  +                   w_current->gc,
  +                   x1+20, y1+20,
  +                   tempstring,
  +                   strlen(tempstring));
  +    gdk_font_unref(font);
  +    free(tempstring);
  +#endif
  +  }
  +
  +#if DEBUG 
  +  printf("drew net\n\n");
  +#endif
  +
  +  /* yes zero is right for the width -> use hardware lines */
  +  if (w_current->net_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->gc, 0, 
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +
  +    gdk_gc_set_line_attributes(w_current->bus_gc, 0, 
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  if (o_current->draw_grips && w_current->draw_grips == TRUE) {	
  +
  +	  /* pb20011109 - modified to use the new o_line_[draw|erase]_grips() */
  +	  /*              reuse the line functions */
  +	  if (!o_current->selected) {
  +		  /* object is no more selected, erase the grips */
  +		  o_current->draw_grips = FALSE;
  +		  o_line_erase_grips(w_current, o_current);
  +	  } else {
  +		  /* object is selected, draw the grips */
  +		  o_line_draw_grips(w_current, o_current);
  +	  }
  +
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_net_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  w_current->override_color = w_current->background_color;
  +  o_net_draw(w_current, o_current);
  +  w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_net_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  +{
  +  int size;
  +  int color;
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  gdk_gc_set_foreground(w_current->outline_xor_gc,
  +			x_get_darkcolor(color));
  +
  +  if (w_current->net_style == THICK ) {
  +    size = SCREENabs(w_current, NET_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->outline_xor_gc, size+1,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_draw_line(w_current->window, w_current->outline_xor_gc,
  +                o_current->line->screen_x[0]+dx,
  +                o_current->line->screen_y[0]+dy,
  +                o_current->line->screen_x[1]+dx,
  +                o_current->line->screen_y[1]+dy);
  +
  +  /* backing store ? not approriate here */
  +
  +  if (w_current->net_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->outline_xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_net_draw_xor_single(TOPLEVEL *w_current, int dx, int dy, int whichone,
  +			   OBJECT *o_current)
  +{
  +  int color;
  +  int dx1 = -1, dx2 = -1, dy1 = -1,dy2 = -1;
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  gdk_gc_set_foreground(w_current->outline_xor_gc,
  +			x_get_darkcolor(color));
  +
  +#if 0 /* if I had this enabled, than xoring would leave a lot of mouse drops */
  +  if (w_current->net_style == THICK ) {
  +    size = SCREENabs(w_current, NET_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->outline_xor_gc, size+1,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +#endif
  +
  +  if (whichone == 0) {
  +    dx1 = dx;
  +    dy1 = dy;
  +    dx2 = 0;
  +    dy2 = 0;
  +  } else if (whichone == 1) {
  +    dx2 = dx;
  +    dy2 = dy;
  +    dx1 = 0;
  +    dy1 = 0;
  +  } else {
  +    fprintf(stderr, _("Got an invalid which one in o_net_draw_xor_single\n"));
  +  }
  +
  +  gdk_draw_line(w_current->window, w_current->outline_xor_gc,
  +                o_current->line->screen_x[0]+dx1,
  +                o_current->line->screen_y[0]+dy1,
  +                o_current->line->screen_x[1]+dx2,
  +                o_current->line->screen_y[1]+dy2);
  +
  +  /* backing store ? not approriate here */
  +
  +#if 0 /* if I had this enabled, than xoring would leave a lot of mouse drops */
  +  if (w_current->net_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->outline_xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_net_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  int size;
  +
  +  /* initalize all parameters used when drawing the new net */
  +  w_current->last_x = w_current->start_x = w_current->second_x = 
  +    fix_x(w_current, x);
  +  w_current->last_y = w_current->start_y = w_current->second_y = 
  +    fix_y(w_current, y);
  +
  +#if 0 /* not ready for prime time use, this is the snap any point #if 0 */
  +  int distance1;
  +  int distance2;
  +  OBJECT *real;
  +  OBJECT *o_current;
  +  int temp_x, temp_y;
  +  o_current = o_CONN_search_closest_range(w_current,
  +                                          w_current->page_current->object_head,
  +                                          w_current->start_x, w_current->start_y,
  +                                          &temp_x, &temp_y, 200, NULL, NULL);
  +
  +  if (o_current) {
  +    w_current->last_x = w_current->start_x = temp_x;
  +    w_current->last_y = w_current->start_y = temp_y;
  +  } else {
  +    w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +    w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +  }
  +#endif
  +
  +#if 0 /* not ready for prime time use */
  +  /* new net extenstion stuff */
  +  o_current = w_current->page_current->selection_head->next;
  +  if (o_current != NULL && w_current->event_state == STARTDRAWNET) {
  +    if (o_current->type == OBJ_NET) {
  +      if (o_current->line) {
  +
  +        real = o_list_sear( /* ch */ 
  +                           w_current->page_current->object_head,
  +                           o_current);
  +
  +        if (!real) {
  +          fprintf(stderr, _("selected a nonexistant object!\n"));
  +          exit(-1);
  +        }
  +        distance1 = dist(
  +                         real->line->screen_x[0],
  +                         real->line->screen_y[0],
  +                         w_current->start_x, w_current->start_y);
  +
  +        distance2 = dist(
  +                         real->line->screen_x[1],
  +                         real->line->screen_y[1],
  +                         w_current->start_x, w_current->start_y);
  +
  +        printf("%d %d\n", distance1, distance2);
  +
  +        if (distance1 < distance2) {
  +          w_current->last_x = w_current->start_x =
  +            real->line->screen_x[0];
  +          w_current->last_y = w_current->start_y =
  +            real->line->screen_y[0];
  +        } else {
  +          w_current->last_x = w_current->start_x =
  +            real->line->screen_x[1];
  +          w_current->last_y = w_current->start_y =
  +            real->line->screen_y[1];
  +        }
  +      }
  +    } else if (o_current->type == OBJ_COMPLEX || 
  +               o_current->type == OBJ_PLACEHOLDER) {
  +      real = o_list_sear( /* ch */
  +                         w_current->page_current->object_head,
  +                         o_current);
  +
  +      if (!real) {
  +        fprintf(stderr, _("selected a nonexistant object!\n"));
  +        exit(-1);
  +      }
  +
  +      o_CONN_search_closest(w_current, o_current->complex,
  +                            w_current->start_x, w_current->start_y,
  +                            &temp_x, &temp_y, NULL);
  +      w_current->last_x = w_current->start_x = temp_x;
  +      w_current->last_y = w_current->start_y = temp_y;
  +    }
  +
  +  }
  +#endif
  +
  +  if (w_current->net_style == THICK ) {
  +    size = SCREENabs(w_current, NET_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->xor_gc, 
  +		w_current->start_x, w_current->start_y, 
  +		w_current->last_x, w_current->last_y);
  +
  +  if (w_current->net_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_net_end(TOPLEVEL *w_current, int x, int y)
  +{
  +  int x1, y1;
  +  int x2, y2;
  +  int x3, y3;
  +  int color;
  +  int size;
  +  int primary_zero_length, secondary_zero_length;
  +  int found_primary_connection = FALSE;
  +
  +  /*int temp_x, temp_y;*/
  +  /* OBJECT *o_current;*/
  +  GList *other_objects = NULL;
  +  OBJECT *new_net = NULL;
  +  
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return(FALSE);
  +  }
  +
  +  if (w_current->override_net_color == -1) {
  +    color = w_current->net_color;
  +  } else {
  +    color = w_current->override_net_color;
  +  }
  +
  +  size = SCREENabs(w_current, NET_WIDTH);
  +
  +  if (w_current->net_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +			x_get_darkcolor(w_current->select_color) );
  +
  +  /* Erase primary rubber net line */
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		w_current->start_x, w_current->start_y,
  +		w_current->last_x, w_current->last_y);
  +
  +  /* Erase secondary rubber net line */
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		 w_current->last_x, w_current->last_y,
  +		 w_current->second_x, w_current->second_y);
  +
  +  if (w_current->net_style == THICK) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +			       GDK_LINE_SOLID,
  +			       GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  +    gdk_gc_set_line_attributes(w_current->gc, size,
  +			       GDK_LINE_SOLID,
  +			       GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  +  }
  +
  +
  +  /* See if either of the nets are zero length.  We'll only add */
  +  /* the non-zero ones */
  +  primary_zero_length = (w_current->start_x == w_current->last_x) &&
  +      (w_current->start_y == w_current->last_y);
  + 
  +  secondary_zero_length = (w_current->last_x == w_current->second_x) &&
  +      (w_current->last_y == w_current->second_y);
  +
  +  /* If both nets are zero length... */
  +  /* this ends the net drawing behavior we want this? hack */
  +  if ( primary_zero_length && secondary_zero_length ) {
  +    w_current->start_x = (-1);
  +    w_current->start_y = (-1);
  +    w_current->last_x = (-1);
  +    w_current->last_y = (-1);
  +    w_current->second_x = (-1);
  +    w_current->second_y = (-1);
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, STARTDRAWNET);
  +    o_net_eraserubber(w_current);
  +    
  +    return (FALSE);
  +  }
  +#if 0				/* not ready for prime time use */
  +  /* second attempt at all snapping */
  +  o_current = o_CONN_search_closest_range(w_current,
  +					  w_current->page_current->
  +					  object_head, w_current->last_x,
  +					  w_current->last_y, &temp_x,
  +					  &temp_y, 200, NULL, NULL);
  +
  +  if (o_current) {
  +    w_current->last_x = temp_x;
  +    w_current->last_y = temp_y;
  +  } else {
  +    w_current->last_x = fix_x(w_current, x);
  +    w_current->last_y = fix_y(w_current, y);
  +  }
  +#endif
  +
  +
  +  /* Primary net runs from (x1,y1)-(x2,y2) */
  +  /* Secondary net from (x2,y2)-(x3,y3) */
  +  SCREENtoWORLD(w_current, w_current->start_x, w_current->start_y, &x1,	&y1);
  +  SCREENtoWORLD(w_current, w_current->last_x, w_current->last_y, &x2, &y2);
  +  SCREENtoWORLD(w_current, w_current->second_x, w_current->second_y, &x3, &y3);
  +
  +  /* Snap points to closest grid location */
  +  x1 = snap_grid(w_current, x1);
  +  y1 = snap_grid(w_current, y1);
  +  x2 = snap_grid(w_current, x2);
  +  y2 = snap_grid(w_current, y2);
  +  x3 = snap_grid(w_current, x3);
  +  y3 = snap_grid(w_current, y3);
  +
  +  w_current->save_x = w_current->second_x;
  +  w_current->save_y = w_current->second_y;
  +
  +  if (!primary_zero_length ) {
  +  /* create primary net */
  +      w_current->page_current->object_tail =
  +	  new_net = o_net_add(w_current,
  +			      w_current->page_current->object_tail,
  +			      OBJ_NET, color, x1, y1, x2, y2);
  +  
  +      /* conn stuff */
  +      /* LEAK CHECK 1 */
  +      other_objects = s_conn_return_others(other_objects,
  +					   w_current->page_current->
  +					   object_tail);
  +
  +      if (o_net_add_busrippers(w_current, new_net, other_objects)) {
  +	  g_list_free(other_objects);
  +	  other_objects = NULL;
  +	  other_objects = s_conn_return_others(other_objects, new_net);
  +      }
  +
  +#if DEBUG 
  +      printf("primary:\n"); 
  +      s_conn_print(new_net->conn_list);
  +#endif
  +
  +      gdk_gc_set_foreground(w_current->gc, x_get_color(color));
  +      gdk_draw_line(w_current->window, w_current->gc,
  +		    new_net->line->screen_x[0], new_net->line->screen_y[0],
  +		    new_net->line->screen_x[1], new_net->line->screen_y[1]);
  +      gdk_draw_line(w_current->backingstore, w_current->gc,
  +		    new_net->line->screen_x[0], new_net->line->screen_y[0],
  +		    new_net->line->screen_x[1], new_net->line->screen_y[1]);
  +
  +      if (w_current->net_style == THICK) {
  +	  gdk_gc_set_line_attributes(w_current->gc, 0,
  +				     GDK_LINE_SOLID,
  +				     GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  +      }
  +
  +      o_cue_undraw_list(w_current, other_objects);
  +      o_cue_draw_list(w_current, other_objects);
  +      o_cue_draw_single(w_current, new_net);
  +
  +      /* Go off and search for valid connection on this newly created net */
  +      found_primary_connection = s_conn_net_search(new_net, 1, 
  +                                                   new_net->conn_list);
  +      if (found_primary_connection)
  +      {
  +      	/* if a net connection is found, reset start point of next net */
  +	w_current->save_x = w_current->last_x;
  +	w_current->save_y = w_current->last_y;
  +      }
  +
  +      /* you don't want to consolidate nets which are drawn non-ortho */
  +      if (w_current->net_consolidate == TRUE && !w_current->CONTROLKEY) {
  +	  o_net_consolidate_segments(w_current, new_net);
  +      }
  +  }
  +
  +
  +  /* If the second net is not zero length, add it as well */
  +  /* Also, a valid net connection from the primary net was not found */
  +  if (!secondary_zero_length && !found_primary_connection) {
  +      
  +      /* Add secondary net */
  +      w_current->page_current->object_tail =
  +	  new_net = o_net_add(w_current,
  +			      w_current->page_current->object_tail,
  +			      OBJ_NET, color, x2, y2, x3, y3);
  +  
  +      /* conn stuff */
  +      /* LEAK CHECK 2 */
  +      other_objects = s_conn_return_others(other_objects,
  +					   w_current->page_current->
  +					   object_tail);
  +
  +      if (o_net_add_busrippers(w_current, new_net, other_objects)) {
  +	  g_list_free(other_objects);
  +	  other_objects = NULL;
  +	  other_objects = s_conn_return_others(other_objects, new_net);
  +      }
  +#if DEBUG
  +      s_conn_print(new_net->conn_list);
  +#endif
  +
  +      gdk_gc_set_foreground(w_current->gc, x_get_color(color));
  +      gdk_draw_line(w_current->window, w_current->gc,
  +		    new_net->line->screen_x[0], new_net->line->screen_y[0],
  +		    new_net->line->screen_x[1], new_net->line->screen_y[1]);
  +      gdk_draw_line(w_current->backingstore, w_current->gc,
  +		    new_net->line->screen_x[0], new_net->line->screen_y[0],
  +		    new_net->line->screen_x[1], new_net->line->screen_y[1]);
  +
  +      if (w_current->net_style == THICK) {
  +	  gdk_gc_set_line_attributes(w_current->gc, 0,
  +				     GDK_LINE_SOLID,
  +				     GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  +      }
  +
  +      o_cue_undraw_list(w_current, other_objects);
  +      o_cue_draw_list(w_current, other_objects);
  +      o_cue_draw_single(w_current, new_net);
  +
  +      /* you don't want to consolidate nets which are drawn non-ortho */
  +      if (w_current->net_consolidate == TRUE && !w_current->CONTROLKEY) {
  +	  o_net_consolidate_segments(w_current, new_net);
  +      }
  +  }
  +  
  +  /* LEAK CHECK 3 */
  +  g_list_free(other_objects);
  +
  +  w_current->page_current->CHANGED = 1;
  +  w_current->start_x = w_current->save_x;
  +  w_current->start_y = w_current->save_y;
  +  o_undo_savestate(w_current, UNDO_ALL);
  +
  +#if 0				/* a false attempt at ending the rubberbanding.. */
  +  if (conn_count) {
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, STARTDRAWNET);
  +    o_net_eraserubber(w_current);
  +  }
  +#endif
  +
  +  return (TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_net_rubbernet(TOPLEVEL *w_current, int x, int y)
  +{
  +  int diff_x, diff_y;
  +  int size;
  +  int ortho;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  if (w_current->net_style == THICK) {
  +    size = SCREENabs(w_current, NET_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +			       GDK_LINE_SOLID,
  +			       GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  +  }
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +			x_get_darkcolor(w_current->select_color));
  +
  +  /* Orthognal mode enabled when Control Key is NOT pressed */
  +  ortho = !w_current->CONTROLKEY;
  +
  +  /* Erase primary line */
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		w_current->start_x, w_current->start_y,
  +		w_current->last_x, w_current->last_y);
  +  /* Erase secondary line*/
  +  if ( w_current->second_x != -1 && w_current->second_y != -1 ) {
  +      gdk_draw_line(w_current->window, w_current->xor_gc,
  +		    w_current->last_x, w_current->last_y,
  +		    w_current->second_x, w_current->second_y);
  +  }
  + 
  +  /* In orthogonal mode secondary line is the same as the first */
  +  if (!ortho)
  +  {
  +      w_current->second_x = w_current->last_x;
  +      w_current->second_y = w_current->last_y;
  +  }
  +
  +  w_current->last_x = fix_x(w_current, x);
  +  w_current->last_y = fix_y(w_current, y);
  +
  +  /* If you press the control key then you can draw non-ortho nets */
  +  if (ortho) {
  +    diff_x = abs(w_current->last_x - w_current->start_x);
  +    diff_y = abs(w_current->last_y - w_current->start_y);
  +
  +    /* calculate the co-ordinates necessary to draw the lines*/
  +    /* Pressing the shift key will cause the vertical and horizontal lines to switch places */
  +    if ( !w_current->SHIFTKEY ) {
  +      w_current->last_y = w_current->start_y;
  +      w_current->second_x = w_current->last_x;
  +      w_current->second_y = fix_y(w_current,y);
  +    } else {
  +      w_current->last_x = w_current->start_x;
  +      w_current->second_x = fix_x(w_current,x);
  +      w_current->second_y = w_current->last_y;
  +    }
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +			x_get_darkcolor(w_current->select_color));
  +  
  +  /* draw primary line */
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		w_current->start_x, w_current->start_y,
  +		w_current->last_x, w_current->last_y);
  +
  +  /* Draw secondary line */
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		w_current->last_x, w_current->last_y,
  +		w_current->second_x, w_current->second_y);
  +
  +  if (w_current->net_style == THICK) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +			       GDK_LINE_SOLID,
  +			       GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  used in button cancel code in x_events.c
  + */
  +void o_net_eraserubber(TOPLEVEL *w_current)
  +{
  +  int size;
  +
  +  if (w_current->net_style == THICK) {
  +    size = SCREENabs(w_current, NET_WIDTH);
  +
  +    if (size < 0)
  +      size = 0;
  +
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +			       GDK_LINE_SOLID,
  +			       GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  +  }
  +
  +#if 0
  +  gdk_gc_set_foreground(w_current->gc,
  +			x_get_color(w_current->background_color));
  +#endif
  +
  +  /* Erase primary primary rubber net line */
  +  gdk_draw_line(w_current->window, w_current->xor_gc, w_current->start_x,
  +		w_current->start_y, w_current->last_x, w_current->last_y);
  +
  +  /* Erase secondary rubber net line */
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +		w_current->last_x, w_current->last_y,
  +		w_current->second_x, w_current->second_y);
  +
  +  if (w_current->net_style == THICK) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +			       GDK_LINE_SOLID,
  +			       GDK_CAP_NOT_LAST, GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  used in x_event_expose() in x_events.c
  + */
  +void o_net_xorrubber(TOPLEVEL *w_current)
  +{
  +  int size;
  +
  +  if (w_current->net_style == THICK ) {
  +
  +    size = SCREENabs(w_current, NET_WIDTH);
  +
  +    if (size < 0)
  +      size=0;
  +
  +    gdk_gc_set_line_attributes(w_current->gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->gc,
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->gc, 
  +		w_current->start_x, w_current->start_y, 
  +		w_current->last_x, w_current->last_y);
  +  gdk_draw_line(w_current->window, w_current->gc, 
  +		w_current->second_x, w_current->second_y, 
  +		w_current->last_x, w_current->last_y);
  +
  +  if (w_current->net_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int o_net_add_busrippers(TOPLEVEL *w_current, OBJECT *net_obj,
  +			 GList *other_objects)
  +
  +{
  +  int color;
  +  GList *cl_current = NULL;
  +  OBJECT *bus_object = NULL;
  +  CONN *found_conn = NULL;
  +  int done;
  +  int otherone;
  +  BUS_RIPPER rippers[2];
  +  int ripper_count = 0;
  +  int i;
  +  double length;
  +  int sign;
  +  double distance1, distance2;
  +  int first, second;
  +  int made_changes = FALSE;
  +  const int ripper_size = w_current->bus_ripper_size;
  +  int complex_angle = 0;
  +  char *clib = NULL;
  +  
  +  length = o_line_length(net_obj);
  +
  +  if (!other_objects) {
  +    return(FALSE);
  +  }
  +  
  +  if (length <= ripper_size) {
  +    return(FALSE);
  +  }
  +
  +  if (w_current->override_net_color == -1) {
  +    color = w_current->net_color;
  +  } else {
  +    color = w_current->override_net_color;
  +  }
  +
  +  
  +  /* check for a bus connection and draw rippers if so */
  +  cl_current = other_objects;
  +  while (cl_current != NULL) {
  +    
  +    bus_object = (OBJECT *) cl_current->data;
  +    if (bus_object && bus_object->type == OBJ_BUS) {
  +      /* yes, using the net routine is okay */
  +      int bus_orientation = o_net_orientation(bus_object);
  +      int net_orientation = o_net_orientation(net_obj);
  +
  +      /* find the CONN structure which is associated with this object */
  +      GList *cl_current2 = net_obj->conn_list;
  +      done = FALSE;
  +      while (cl_current2 != NULL && !done) {
  +	CONN *tmp_conn = (CONN *) cl_current2->data;
  +
  +	if (tmp_conn && tmp_conn->other_object &&
  +	    tmp_conn->other_object == bus_object) {
  +
  +	  found_conn = tmp_conn;
  +	  done = TRUE;
  +	}
  +
  +	cl_current2 = cl_current2->next;
  +      }
  +
  +      if (!found_conn) {
  +        return(FALSE);
  +      }
  +      
  +      otherone = !found_conn->whichone;
  +      
  +      /* now deal with the found connection */
  +      if (bus_orientation == HORIZONTAL && net_orientation == VERTICAL) {
  +	/* printf("found horiz bus %s %d!\n", bus_object->name, 
  +           found_conn->whichone);*/
  +
  +        sign = bus_object->bus_ripper_direction;
  +        if (!sign) {
  +          if (bus_object->line->x[0] < bus_object->line->x[1]) {
  +            first = 0;
  +            second = 1;
  +          } else {
  +            first = 1;
  +            second = 0;
  +          }
  +              
  +          distance1 = abs(bus_object->line->x[first] -
  +                          net_obj->line->x[found_conn->whichone]);
  +          distance2 = abs(bus_object->line->x[second] -
  +                          net_obj->line->x[found_conn->whichone]);
  +          
  +          if (distance1 <= distance2) {
  +            sign = 1;
  +          } else {
  +            sign = -1;
  +          }
  +          bus_object->bus_ripper_direction = sign;
  +        }
  +        /* printf("hor sign: %d\n", sign); */
  +
  +        if (net_obj->line->y[otherone] < bus_object->line->y[0]) {
  +          /* new net is below bus */
  +          /*printf("below\n");*/
  +
  +          if (ripper_count >= 2) {
  +            /* try to exit gracefully */
  +            fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
  +            made_changes = FALSE;
  +            break;
  +          }
  +
  +          if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
  +            /* non-symmetric */
  +            if (sign == 1) {
  +              complex_angle = 0;
  +            } else {
  +              complex_angle = 90;
  +            }
  +          } else {
  +            /* symmetric */
  +            complex_angle = 0;
  +          }
  +
  +          net_obj->line->y[found_conn->whichone] -= ripper_size;
  +          o_net_recalc(w_current, net_obj);
  +          rippers[ripper_count].x[0] = 
  +            net_obj->line->x[found_conn->whichone];
  +          rippers[ripper_count].y[0] =
  +            net_obj->line->y[found_conn->whichone];
  +          rippers[ripper_count].x[1] =
  +            net_obj->line->x[found_conn->whichone] + sign*ripper_size;       
  +          rippers[ripper_count].y[1] =
  +            net_obj->line->y[found_conn->whichone] + ripper_size;
  +          ripper_count++;
  +          /* printf("done\n"); */
  +          made_changes++;
  +          
  +        } else {
  +          /* new net is above bus */
  +          /* printf("above\n"); */
  +
  +          if (ripper_count >= 2) {
  +            /* try to exit gracefully */
  +            fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
  +            made_changes = FALSE;
  +            break;
  +          }
  +
  +          if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
  +            /* non-symmetric */
  +            if (sign == 1) {
  +              complex_angle = 270;
  +            } else {
  +              complex_angle = 180;
  +            }
  +          } else {
  +            /* symmetric */
  +            complex_angle = 180;
  +          }
  +          
  +          net_obj->line->y[found_conn->whichone] += ripper_size;
  +          o_net_recalc(w_current, net_obj);
  +          rippers[ripper_count].x[0] = 
  +            net_obj->line->x[found_conn->whichone];
  +          rippers[ripper_count].y[0] =
  +            net_obj->line->y[found_conn->whichone];
  +          rippers[ripper_count].x[1] =
  +            net_obj->line->x[found_conn->whichone] + sign*ripper_size;      
  +          rippers[ripper_count].y[1] =
  +            net_obj->line->y[found_conn->whichone] - ripper_size;
  +            ripper_count++;
  +            
  +            /* printf("done\n"); */
  +          made_changes++;
  +        }
  +        
  +        
  +      } else if (bus_orientation == VERTICAL &&
  +		 net_orientation == HORIZONTAL) {
  +
  +	/* printf("found vert bus %s %d!\n", bus_object->name,
  +           found_conn->whichone); */
  +
  +        sign = bus_object->bus_ripper_direction;
  +        if (!sign) {
  +          if (bus_object->line->y[0] < bus_object->line->y[1]) {
  +            first = 0;
  +            second = 1;
  +          } else {
  +            first = 1;
  +            second = 0;
  +          }
  +
  +          distance1 = abs(bus_object->line->y[first] -
  +                          net_obj->line->y[found_conn->whichone]);
  +          distance2 = abs(bus_object->line->y[second] -
  +                          net_obj->line->y[found_conn->whichone]);
  +          
  +          if (distance1 <= distance2) {
  +            sign = 1;
  +          } else {
  +            sign = -1;
  +          }
  +          bus_object->bus_ripper_direction = sign;
  +        } 
  +        /* printf("ver sign: %d\n", sign); */
  +
  +        
  +        if (net_obj->line->x[otherone] < bus_object->line->x[0]) {
  +          /* new net is to the left of the bus */
  +          /* printf("left\n"); */
  +          
  +          if (ripper_count >= 2) {
  +            /* try to exit gracefully */
  +            fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
  +            made_changes = FALSE;
  +            break;
  +          }
  +
  +          if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
  +            /* non-symmetric */
  +            if (sign == 1) {
  +              complex_angle = 0;
  +            } else {
  +              complex_angle = 270;
  +            }
  +          } else {
  +            /* symmetric */
  +            complex_angle = 270;
  +          }
  +
  +          net_obj->line->x[found_conn->whichone] -= ripper_size;
  +          o_net_recalc(w_current, net_obj);
  +          rippers[ripper_count].x[0] = 
  +            net_obj->line->x[found_conn->whichone];
  +          rippers[ripper_count].y[0] =
  +            net_obj->line->y[found_conn->whichone];
  +          rippers[ripper_count].x[1] =
  +            net_obj->line->x[found_conn->whichone] + ripper_size;
  +          rippers[ripper_count].y[1] =
  +            net_obj->line->y[found_conn->whichone] + sign*ripper_size;
  +          ripper_count++;
  +                    
  +          made_changes++;
  +        } else {
  +          /* new net is to the right of the bus */
  +          /* printf("right\n"); */
  +
  +          if (ripper_count >= 2) {
  +            /* try to exit gracefully */
  +            fprintf(stderr, _("Tried to add more than two bus rippers. Internal gschem error.\n"));
  +            made_changes = FALSE;
  +            break;
  +          }
  +
  +          if (w_current->bus_ripper_rotation == NON_SYMMETRIC) {
  +            /* non-symmetric */
  +            if (sign == 1) {
  +              complex_angle = 90;
  +            } else {
  +              complex_angle = 180;
  +            }
  +          } else {
  +            /* symmetric */
  +            complex_angle = 90;
  +          }
  +
  +          net_obj->line->x[found_conn->whichone] += ripper_size;
  +          o_net_recalc(w_current, net_obj);
  +          rippers[ripper_count].x[0] = 
  +            net_obj->line->x[found_conn->whichone];
  +          rippers[ripper_count].y[0] =
  +            net_obj->line->y[found_conn->whichone];
  +          rippers[ripper_count].x[1] =
  +            net_obj->line->x[found_conn->whichone] - ripper_size;
  +          rippers[ripper_count].y[1] =
  +            net_obj->line->y[found_conn->whichone] + sign*ripper_size;
  +          ripper_count++;
  +
  +          made_changes++;
  +        }
  +      }
  +    }
  +
  +
  +    cl_current = cl_current->next;
  +  }
  + 
  +  if (made_changes) {
  +    s_conn_remove(w_current, net_obj);
  +
  +    if (w_current->bus_ripper_type == COMP_BUS_RIPPER) {
  +      const GSList *clibs = s_clib_search_basename (w_current->bus_ripper_symname);
  +      if (clibs != NULL) {
  +        clib = (gchar*)clibs->data;
  +      }
  +    }
  +    
  +    for (i = 0; i < ripper_count; i++) {
  +      if (w_current->bus_ripper_type == NET_BUS_RIPPER) {
  +        w_current->page_current->object_tail =
  +          o_net_add(w_current, w_current->page_current->object_tail,
  +                    OBJ_NET, color,
  +                    rippers[i].x[0], rippers[i].y[0],
  +                    rippers[i].x[1], rippers[i].y[1]);
  +      } else {
  +
  +        if (clib) {
  +          w_current->page_current->object_tail = 
  +          (OBJECT *) o_complex_add(
  +                                   w_current,
  +                                   w_current->page_current->object_tail,
  +                                   OBJ_COMPLEX, WHITE,
  +                                   rippers[i].x[0], rippers[i].y[0],
  +                                   complex_angle, 0,
  +                                   clib,
  +                                   w_current->bus_ripper_symname, 1, TRUE);
  +          
  +          o_complex_draw(w_current,w_current->page_current->object_tail);
  +        } else {
  +          s_log_message(_("Could not find %s in any component-library\n"),
  +                        w_current->bus_ripper_symname);
  +        }
  +      }
  +    }
  +    
  +    s_conn_update_object(w_current, net_obj);
  +    return(TRUE);
  +  }
  +
  +  return(FALSE);
  +}
  
  
  
  1.1                  eda/geda/gaf/gschem/src/o_picture.c
  
  Index: o_picture.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * gschem - gEDA Schematic Capture
   * Copyright (C) 1998-2000 Ales V. Hvezda
   *
   * 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 USA
   */
  #include <config.h>
  #include <math.h>
  #include <stdio.h>
  
  #include <libgeda/libgeda.h>
  #ifndef HAS_GTK12
  #include <gdk-pixbuf/gdk-pixbuf.h>
  #endif
  #include "../include/globals.h"
  #include "../include/prototype.h"
  
  #ifndef HAS_GTK12
  
  /* This works, but using one macro inside of other doesn't */
  #define GET_PICTURE_WIDTH(w)			\
  	abs((w)->last_x - (w)->start_x) 
  #define GET_PICTURE_HEIGHT(w)			\
  	(w)->pixbuf_wh_ratio == 0 ? 0 : abs((w)->last_x - (w)->start_x)/(w)->pixbuf_wh_ratio
  #define GET_PICTURE_LEFT(w)				\
  	min((w)->start_x, (w)->last_x);
  #define GET_PICTURE_TOP(w)				\
  	(w)->start_y < (w)->last_y ? (w)->start_y  : \
                                       (w)->start_y-abs((w)->last_x - (w)->start_x)/(w)->pixbuf_wh_ratio;
  
  /*! \brief Start process to input a new picture.
   *  \par Function Description
   *  This function starts the process to input a new picture. Parameters
   *  for this picture are put into/extracted from the <B>w_current</B> toplevel
   *  structure.
   *  <B>x</B> and <B>y</B> are current coordinates of the pointer in screen
   *  coordinates.
   *
   *  The first step is to input one corner of the picture. This corner is
   *  (<B>x</B>,<B>y</B>) snapped to the grid and saved in
   *  <B>w_current->start_x</B> and <B>w_current->start_y</B>.
   *
   *  The other corner will be saved in (<B>w_current->last_x</B>,
   *  <B>w_current->last_y</B>).
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] x          Current x coordinate of pointer in screen units.    
   *  \param [in] y          Current y coordinate of pointer in screen units.
   */
  void o_picture_start(TOPLEVEL *w_current, int x, int y)
  {
  #if DEBUG
    printf("o_picture_start called\n");
  #endif
    /* init start_[x|y], last_[x|y] to describe box */
    w_current->last_x = w_current->start_x = fix_x(w_current, x);
    w_current->last_y = w_current->start_y = fix_y(w_current, y);
  
    /* start to draw the box */
    o_picture_rubberbox_xor(w_current);
  
  }
  
  /*! \brief End the input of a circle.
   *  \par Function Description
   *  This function ends the input of the second corner of a picture.
   *  The (<B>x</B>,<B>y</B>) point is set to be this second corner. The picture
   *  is then defined by (<B>w_current->start_x</B>,<B>w_current->start_y</B>
   *  and (<B>w_current->last_x</B>,<B>w_current->last_y</B> that is a snapped
   *  version of (<B>x</B>,<B>y</B>).
   *  <B>x</B> and <B>y</B> are in screen unit.
   *
   *  The temporary picture is erased ; a new picture object is allocated,
   *  initialized and linked to the object list ; The object is finally
   *  drawn on the current sheet.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] x          Current x coordinate of pointer in screen units.
   *  \param [in] y          Current y coordinate of pointer in screen units.
   */
  void o_picture_end(TOPLEVEL *w_current, int x, int y)
  {
    int x1, y1;
    int x2, y2;
    int picture_width, picture_height;
    int picture_left, picture_top;
  
    if (w_current->inside_action == 0) {
      o_redraw(w_current, w_current->page_current->object_head);
      return;
    }
  
    /* get the last coords of the pointer */
    w_current->last_x = fix_x(w_current, x);
    w_current->last_y = fix_y(w_current, y);
  
    /* erase the temporary picture */
    o_picture_rubberbox_xor(w_current);
    
    picture_width  = GET_PICTURE_WIDTH (w_current);
    picture_height = GET_PICTURE_HEIGHT(w_current);
    picture_left   = GET_PICTURE_LEFT  (w_current);
    picture_top    = GET_PICTURE_TOP   (w_current);
  
    /* pictures with null width and height are not allowed */
    if ((picture_width == 0) && (picture_height == 0)) {
      /* cancel the object creation */
      w_current->start_x = (-1);
      w_current->start_y = (-1);
      w_current->last_x  = (-1);
      w_current->last_y  = (-1);
      return;
    }
  
    /* calculate the world coords of the upper left and lower right corners */
    SCREENtoWORLD(w_current, picture_left, picture_top, &x1, &y1);
    SCREENtoWORLD(w_current,
                  picture_left + picture_width,
  		picture_top + picture_height, &x2, &y2);
    x1 = snap_grid(w_current, x1);
    y1 = snap_grid(w_current, y1);
    x2 = snap_grid(w_current, x2);
    y2 = snap_grid(w_current, y2);
  
    /* create the object */
    w_current->page_current->object_tail = 
    o_picture_add(w_current,
                  w_current->page_current->object_tail,
  		w_current->current_pixbuf,
  		w_current->pixbuf_filename,
  		w_current->pixbuf_wh_ratio,
                  OBJ_PICTURE, x1, y1, x2, y2, 0, FALSE, FALSE);
  
    /* draw it */
    o_redraw_single(w_current, w_current->page_current->object_tail);
    
  #if DEBUG
    printf("coords: %d %d %d %d\n", x1, y2, x2, y2);
  #endif
  	
    w_current->start_x = (-1);
    w_current->start_y = (-1);
    w_current->last_x  = (-1);
    w_current->last_y  = (-1);
  	
    w_current->page_current->CHANGED = 1;
  
    o_undo_savestate(w_current, UNDO_ALL);
  
  }
  #endif
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void picture_selection_dialog (TOPLEVEL *w_current)
  {
  #ifdef HAS_GTK12
    GtkWidget *dialog, *label, *okay_button;
    
    /* Create the widgets */
    
    dialog = gtk_dialog_new();
    label = gtk_label_new (_("Gschem doesn't support pictures if it has been compiled using GTK 1.2"));
    okay_button = gtk_button_new_with_label(_("OK"));
     
    /* Ensure that the dialog box is destroyed when the user clicks ok. */
    
    gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked",
  			     GTK_SIGNAL_FUNC (gtk_widget_destroy), dialog);
    gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
  		     okay_button);
    
    /* Add the label, and show everything we've added to the dialog. */
    
    gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
  		     label);
    gtk_widget_show_all (dialog);
  #else
    GtkWidget *file_selector;
    
    /* Create the selector */
    if (!w_current->pfswindow) {
  #if DEBUG
      printf("Creating new picture file selection dialog\n");
  #endif
      w_current->pfswindow = gtk_file_selection_new (_("Please select a picture file."));
      file_selector = w_current->pfswindow;
      if (w_current->pixbuf_filename)
        gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_selector), w_current->pixbuf_filename);
      gtk_window_position(GTK_WINDOW (w_current->pfswindow),
  			GTK_WIN_POS_NONE);
      
      g_signal_connect (G_OBJECT (file_selector), "destroy",
  		      G_CALLBACK (picture_selection_cancel), w_current);
      
      
      g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_selector)->ok_button),
  		      "clicked",
  		      G_CALLBACK (picture_selection_ok),
  		      w_current);
      
      /* 
       * Ensure that the dialog box is destroyed when the user clicks the
       * cancel button.
       */
      g_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_selector)->cancel_button),
  		      "clicked",
  		      G_CALLBACK (picture_selection_cancel),
  		      w_current); 
      
    }
  
    /* Display that dialog */
    if (!GTK_WIDGET_VISIBLE (w_current->pfswindow)) {
      gtk_widget_show (w_current->pfswindow);
  #if 0
      gtk_grab_add (w_current->pfswindow);
  #endif
    } else {
      gdk_window_raise(w_current->pfswindow->window);
    }
  #endif
  }
  
  #ifndef HAS_GTK12
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void picture_selection_ok (GtkWidget *widget, TOPLEVEL *w_current)
  {
    GtkWidget *file_selector = (GtkWidget *)w_current->pfswindow;
    const gchar *selected_filename;
    GdkPixbuf *pixbuf;
    GError *error;
    
  
    selected_filename = (char *) g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_selector)));
  #if DEBUG
    g_print ("Selected picture: %s\n", selected_filename);
  #endif   
    picture_selection_cancel(widget, w_current);
    
    error = NULL;
    pixbuf = gdk_pixbuf_new_from_file (selected_filename, &error);
  
    if (!pixbuf) {
      GtkWidget *dialog;
      
      dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
                                       GTK_DIALOG_DESTROY_WITH_PARENT,
                                       GTK_MESSAGE_ERROR,
                                       GTK_BUTTONS_CLOSE,
                                       _("Failed to load picture: %s"),
                                       error->message);
      g_error_free (error);
       
      g_signal_connect (dialog, "response",
                        G_CALLBACK (gtk_widget_destroy), NULL);
  
      gtk_widget_show (dialog);
      return;
    }
  
  #if DEBUG
    printf("Picture loaded succesfully.\n");
  #endif
  
    exit_if_null(w_current);
  
    o_erase_rubber(w_current);
  
    i_update_middle_button(w_current, i_callback_add_picture, _("Picture"));
    w_current->inside_action = 0;
  
    o_picture_set_pixbuf(w_current, pixbuf, (char *) selected_filename);
    /* o_picture_set_pixbuf allocates memory for filename, so free the pointer */
    free((char *)selected_filename);
  
    w_current->page_current->CHANGED=1;
  
    i_allow_expose();
    i_set_state(w_current, DRAWPICTURE);
     
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void picture_selection_cancel (GtkWidget *widget, TOPLEVEL *w_current)
  {
    i_set_state(w_current, SELECT);
    i_update_toolbar(w_current);
    gtk_widget_destroy(w_current->pfswindow);
    w_current->pfswindow=NULL;
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   *  \note
   * used in button cancel code in x_events.c
   */
  void o_picture_eraserubber(TOPLEVEL *w_current)
  {
  #if DEBUG
    printf("o_picture_eraserubber called\n");
  #endif
    o_picture_rubberbox_xor(w_current);
  }
  
  /*! \brief Draw temporary picture while dragging edge.
   *  \par Function Description
   *  This function is used to draw the box while dragging one of its edge or
   *  angle. It erases the previous temporary box drawn before, and draws
   *  a new updated one. <B>x</B> and <B>y</B> are the new position of the mobile
   *  point, ie the mouse.
   *
   *  The old values are inside the <B>w_current</B> pointed structure. Old
   *  width, height and left and top values are recomputed by the corresponding
   *  macros. The box is then erased by performing a xor-drawing over the box.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] x          Current x coordinate of pointer in screen units.
   *  \param [in] y          Current y coordinate of pointer in screen units.
   */
  void o_picture_rubberbox(TOPLEVEL *w_current, int x, int y)
  {
  #if DEBUG
    printf("o_picture_rubberbox called\n");
  #endif
    if (w_current->inside_action == 0) {
      o_redraw(w_current, w_current->page_current->object_head);
      return;
    }
  
    /* erase the previous temporary box */
    o_picture_rubberbox_xor(w_current);
  
    /*
     * New values are fixed according to the <B>x</B> and <B>y</B> parameters. These are saved in <B>w_current</B> pointed structure as new temporary values. The new box is then drawn.
  
     */
  
    /* update the coords of the corner */
    w_current->last_x = fix_x(w_current, x);
    w_current->last_y = fix_y(w_current, y);
  
    /* draw the new temporary box */
    o_picture_rubberbox_xor(w_current);
    
  }
  
  /*! \brief Draw picture from TOPLEVEL object.
   *  \par Function Description
   *  This function draws the box from the variables in the toplevel
   *  structure <B>*w_current</B>.
   *  One corner of the box is at (<B>w_current->start_x</B>,
   *  <B>w_current->start_y</B>) and the second corner is at
   *  (<B>w_current->last_x</B>,<B>w_current->last_y</B>.
   *
   *  The box is drawn with a xor-function over the current sheet with the
   *  selection color.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   */
  void o_picture_rubberbox_xor(TOPLEVEL *w_current)
  {
    int picture_width, picture_height, picture_left, picture_top;
    
    /* get the width/height and the upper left corner of the picture */
    picture_width  = GET_PICTURE_WIDTH (w_current);
    picture_height = GET_PICTURE_HEIGHT(w_current);
    picture_left   = GET_PICTURE_LEFT  (w_current);
    picture_top    = GET_PICTURE_TOP   (w_current);
    
  #if DEBUG
    printf("o_picture_rubberbox_xor called:\n");
    printf("pixbuf wh ratio: %i\n", w_current->pixbuf_wh_ratio);
    printf("start: %i, %i\n", w_current->start_x, w_current->start_y);
    printf("last: %i, %i\n", w_current->last_x, w_current->last_y);
    printf("Left: %i\nTop: %i\nWidth: %i\nHeight: %i\n",
  	 picture_left, picture_top, picture_width, picture_height);
  #endif
    /* draw the picture from the previous variables */
    gdk_gc_set_foreground(w_current->xor_gc, 
  			x_get_darkcolor(w_current->select_color)); 
    gdk_gc_set_line_attributes(w_current->xor_gc, 0, 
  			     GDK_LINE_SOLID, GDK_CAP_NOT_LAST, 
  			     GDK_JOIN_MITER);
    gdk_draw_rectangle(w_current->window, w_current->xor_gc,
  		     FALSE, picture_left, picture_top,
  		     picture_width, picture_height);
  }
  
  /*! \brief Draw a picture on the screen.
   *  \par Function Description
   *  This function is used to draw a picture on screen. The picture is
   *  described in the OBJECT which is referred by <B>o_current</B>. The picture
   *  is displayed according to the current state, described in the
   *  TOPLEVEL object pointed by <B>w_current</B>.
   *
   *  It first checks if the OBJECT pointed is valid or not. If not it
   *  returns and do not output anything. That should never happen though.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] o_current  Picture OBJECT to draw.
   */
  void o_picture_draw(TOPLEVEL *w_current, OBJECT *o_current)
  {
    int wleft, wright, wtop, wbottom; /* world bounds */
    if (o_current->picture == NULL) {
      return;
    }
  
    /*
     * The function now recalculates the OBJECT as a picture. It involves
     * calculating every single dimensions according to the zoom factor the
     * position, @dots{}.
     * It also recalculates the bounding picture of the object and check
     * whether this object is visible or not. If not there is no reason to
     * draw it !
     */
    o_picture_recalc(w_current, o_current);
  
    /* Get read to check for visibility of this line by using it's
     * bounding picture
     */
    world_get_picture_bounds(w_current, o_current->picture,
                             &wleft, &wtop, &wright, &wbottom);
  	
    if (!visible(w_current, wleft, wtop, wright, wbottom)) {
      return;
    }
  	
  #if  DEBUG 
    printf("drawing picture\n\n");
    
    printf("drawing picture: %d %d %d %d\n",
           o_current->picture->screen_upper_x,
           o_current->picture->screen_upper_y,
           o_current->picture->screen_upper_x +
           abs(o_current->picture->screen_lower_x -
               o_current->picture->screen_upper_x),
           o_current->picture->screen_upper_y +
           abs(o_current->picture->screen_lower_y -
               o_current->picture->screen_upper_y));
  #endif
  
    /*
     * First, the picture is drawn.
     * Finally the function takes care of the grips.
     */
  
    if (o_current->picture->displayed_picture != NULL) {
      free(o_current->picture->displayed_picture);
      o_current->picture->displayed_picture = NULL;
    }
    /* If it's not drawing using the background color then draw the image */
    if (w_current->override_color != w_current->background_color) { 
      GdkPixbuf *temp_pixbuf1, *temp_pixbuf2;
  
      /* Create a copy of the pixbuf rotated */
      temp_pixbuf1 = gdk_pixbuf_rotate(o_current->picture->original_picture, 
  				    o_current->picture->angle);
  
      if (temp_pixbuf1 == NULL) {
        fprintf(stderr, "Couldn't get enough memory for rotating the picture\n");
        return;
      }
  
      temp_pixbuf2 = gdk_pixbuf_mirror_flip(temp_pixbuf1,
  					  o_current->picture->mirrored, FALSE);
      free(temp_pixbuf1);
  
      if (temp_pixbuf2 == NULL) {
        fprintf(stderr, "Couldn't get enough memory for mirroring the picture\n");
        return;
      }
  
      o_current->picture->displayed_picture = 
      gdk_pixbuf_scale_simple(temp_pixbuf2, 
                              abs(o_current->picture->screen_lower_x -
                                  o_current->picture->screen_upper_x), 
                              abs(o_current->picture->screen_lower_y - 
                                  o_current->picture->screen_upper_y), 
                              GDK_INTERP_BILINEAR);
      free(temp_pixbuf2);
  
      if (o_current->picture->displayed_picture == NULL) {
        fprintf(stderr, "Couldn't get enough memory for scaling the picture\n");
        return;
      }
  
      gdk_draw_pixbuf(w_current->window, w_current->gc,
  		    o_current->picture->displayed_picture, 
  		    0, 0, o_current->picture->screen_upper_x,
  		    o_current->picture->screen_upper_y, 
  		    -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
      gdk_draw_pixbuf(w_current->backingstore, w_current->gc,
  		    o_current->picture->displayed_picture, 
  		    0, 0, o_current->picture->screen_upper_x,
  		    o_current->picture->screen_upper_y, 
  		    -1, -1, GDK_RGB_DITHER_NONE, 0, 0);
    }
    else {
      /* Erase the picture, drawing a rectangle with the background color */
      gdk_gc_set_foreground(w_current->gc, 
  			  x_get_color(w_current->background_color));
      gdk_draw_rectangle(w_current->window, w_current->gc, TRUE, 
  		       o_current->picture->screen_upper_x,
  		       o_current->picture->screen_upper_y,
  		       abs(o_current->picture->screen_lower_x -
  			   o_current->picture->screen_upper_x), 
  		       abs(o_current->picture->screen_lower_y - 
  			   o_current->picture->screen_upper_y));
      gdk_draw_rectangle(w_current->backingstore, w_current->gc, TRUE, 
  		       o_current->picture->screen_upper_x,
  		       o_current->picture->screen_upper_y,
  		       abs(o_current->picture->screen_lower_x -
  			   o_current->picture->screen_upper_x), 
  		       abs(o_current->picture->screen_lower_y - 
  			   o_current->picture->screen_upper_y));
    }
  
    /* Grip specific stuff */
    if ((o_current->draw_grips == TRUE) && (w_current->draw_grips == TRUE)) {
        if (!o_current->selected) {
  	/* object is no more selected, erase the grips */
  	o_current->draw_grips = FALSE;
  	o_picture_erase_grips(w_current, o_current); 
        } else {
  	/* object is selected, draw the grips on the picture */
  	o_picture_draw_grips(w_current, o_current); 
        }
    }
  }
  
  /*! \brief Draw grip marks on picture.
   *  \par Function Description
   *  This function draws four grips on the corners of the picture described
   *  by <B>*o_current</B>.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] o_current  Picture OBJECT to draw grip points on.
   */
  void o_picture_draw_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  {
  #if DEBUG
    printf("o_picture_draw_grips called\n");
  #endif
    if (w_current->draw_grips == FALSE)
  	  return;
  
    /* grip on upper left corner (whichone = PICTURE_UPPER_LEFT) */
    o_grips_draw(w_current,
  	       o_current->picture->screen_upper_x,
  	       o_current->picture->screen_upper_y);
    
    /* grip on upper right corner (whichone = PICTURE_UPPER_RIGHT) */
    o_grips_draw(w_current,
  	       o_current->picture->screen_lower_x,
  	       o_current->picture->screen_upper_y);
    
    /* grip on lower left corner (whichone = PICTURE_LOWER_LEFT) */
    o_grips_draw(w_current,
  	       o_current->picture->screen_upper_x,
  	       o_current->picture->screen_lower_y);
    
    /* grip on lower right corner (whichone = PICTURE_LOWER_RIGHT) */
    o_grips_draw(w_current,
  	       o_current->picture->screen_lower_x,
  	       o_current->picture->screen_lower_y);
    
    /* Box surrounding the picture */
    gdk_draw_rectangle(w_current->window, w_current->gc, FALSE, 
  		     o_current->picture->screen_upper_x,
  		     o_current->picture->screen_upper_y,
  		     abs(o_current->picture->screen_upper_x -
  			 o_current->picture->screen_lower_x),
  		     abs(o_current->picture->screen_upper_y -
  			 o_current->picture->screen_lower_y));
    gdk_draw_rectangle(w_current->backingstore, w_current->gc, FALSE, 
  		     o_current->picture->screen_upper_x,
  		     o_current->picture->screen_upper_y,
  		     abs(o_current->picture->screen_upper_x -
  			 o_current->picture->screen_lower_x),
  		     abs(o_current->picture->screen_upper_y -
  			 o_current->picture->screen_lower_y));
  }
  
  /*! \brief Erase grip marks from box.
   *  \par Function Description
   *  This function erases the four grips displayed on the <B>*o_current</B>
   *  picture object. These grips are on each of the corner.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] o_current  Picture OBJECT to erase grip marks from.
   */
  void o_picture_erase_grips(TOPLEVEL *w_current, OBJECT *o_current) 
  {
  #if DEBUG
    printf("o_picture_erase_grips called\n");
  #endif
    if (w_current->draw_grips == FALSE)
  	  return;
  
    /* grip on upper left corner (whichone = PICTURE_UPPER_LEFT) */
    o_grips_erase(w_current,
  		o_current->picture->screen_upper_x,
  		o_current->picture->screen_upper_y);
    
    /* grip on upper right corner (whichone = PICTURE_UPPER_RIGHT) */
    o_grips_erase(w_current,
  		o_current->picture->screen_lower_x,
  		o_current->picture->screen_upper_y);
    
    /* grip on lower left corner (whichone = PICTURE_LOWER_LEFT) */
    o_grips_erase(w_current,
  		o_current->picture->screen_upper_x,
  		o_current->picture->screen_lower_y);
    
    /* grip on lower right corner (whichone = PICTURE_LOWER_RIGHT) */
    o_grips_erase(w_current,
  		o_current->picture->screen_lower_x,
  		o_current->picture->screen_lower_y);
    
    /* Box surrounding the picture */
    gdk_draw_rectangle(w_current->window, w_current->gc, FALSE, 
  		     o_current->picture->screen_upper_x,
  		     o_current->picture->screen_upper_y,
  		     abs(o_current->picture->screen_upper_x -
  			 o_current->picture->screen_lower_x),
  		     abs(o_current->picture->screen_upper_y -
  			 o_current->picture->screen_lower_y));
    gdk_draw_rectangle(w_current->backingstore, w_current->gc, FALSE, 
  		     o_current->picture->screen_upper_x,
  		     o_current->picture->screen_upper_y,
  		     abs(o_current->picture->screen_upper_x -
  			 o_current->picture->screen_lower_x),
  		     abs(o_current->picture->screen_upper_y -
  			 o_current->picture->screen_lower_y));
  }
  
  /*! \brief Erase a picture described by OBJECT.
   *  \par Function Description
   *  This function erases a picture, described in a <B>OBJECT</B> structure
   *  pointed by <B>o_current</B>.
   *
   *  It makes a call to the function #o_picture_draw() after setting
   *  the special color. Therefore a picture is drawn with background color
   *  over the previous one.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] o_current  Picture OBJECT to erase.
   */
  void o_picture_erase(TOPLEVEL *w_current, OBJECT *o_current)
  {
  #if DEBUG
    printf("o_picture_erase called\n");
  #endif
      gdk_gc_set_foreground(w_current->gc,
                            x_get_color(w_current->background_color));
      w_current->override_color = w_current->background_color;
      o_picture_draw(w_current, o_current);
      w_current->override_color = -1;
  }
  
  /*! \brief Draw a picture described by OBJECT with translation
   *  \par Function Description
   *  This function daws the picture object described by <B>*o_current</B>
   *  translated by the vector (<B>dx</B>,<B>dy</B>) with an xor-function over
   *  the current sheet.
   *  The translation vector is in screen unit.
   *
   *  The picture is displayed with the color of the object.
   *
   *  \param [in] w_current  The TOPLEVEL object.
   *  \param [in] dx         Delta x coordinate for picture.
   *  \param [in] dy         Delta y coordinate for picture.
   *  \param [in] o_current  Picture OBJECT to draw.
   */
  void o_picture_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  {
    int screen_x1, screen_y1;
    int screen_x2, screen_y2;
    int color;
  
  #if DEBUG
    printf("o_picture_draw_xor called.\n");
  #endif
    if (o_current->picture == NULL) {
      return;
    }
  
    screen_x1 = o_current->picture->screen_upper_x;
    screen_y1 = o_current->picture->screen_upper_y;
    screen_x2 = o_current->picture->screen_lower_x;
    screen_y2 = o_current->picture->screen_lower_y;
  
    if (o_current->saved_color != -1) {
      color = o_current->saved_color;
    } else {
      color = o_current->color;
    }
    
    gdk_gc_set_foreground(w_current->outline_xor_gc,
                          x_get_darkcolor(color));
    
    gdk_draw_rectangle(w_current->window,
                       w_current->outline_xor_gc, FALSE,
                       screen_x1 + dx,
                       screen_y1 + dy,
                       abs(screen_x2 - screen_x1),
                       abs(screen_y2 - screen_y1));
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void picture_change_selection_cancel (GtkWidget *widget, TOPLEVEL *w_current)
  {
    i_set_state(w_current, SELECT);
    i_update_toolbar(w_current);
    gtk_widget_destroy(w_current->pcfswindow);
    w_current->pcfswindow=NULL;
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void picture_change_selection_ok (GtkWidget *widget, TOPLEVEL *w_current)
  {
    GtkWidget *file_selector = (GtkWidget *)w_current->pcfswindow;
    const gchar *selected_filename;
    GdkPixbuf *pixbuf;
    GError *error;
    SELECTION *list;  
  
    selected_filename = (char *) g_strdup(gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_selector)));
  #if DEBUG
    g_print ("Selected picture: %s\n", selected_filename);
  #endif   
    picture_change_selection_cancel(widget, w_current);
    
    error = NULL;
    pixbuf = gdk_pixbuf_new_from_file (selected_filename, &error);
  
    if (!pixbuf) {
      GtkWidget *dialog;
      
      dialog = gtk_message_dialog_new (GTK_WINDOW (w_current->main_window),
                                       GTK_DIALOG_DESTROY_WITH_PARENT,
                                       GTK_MESSAGE_ERROR,
                                       GTK_BUTTONS_CLOSE,
                                       _("Failed to load picture: %s"),
                                       error->message);
      g_error_free (error);
       
      g_signal_connect (dialog, "response",
                        G_CALLBACK (gtk_widget_destroy), NULL);
  
      gtk_widget_show (dialog);
      return;
    }
  #if DEBUG
    printf("Picture loaded succesfully.\n");
  #endif
  
    exit_if_null(w_current);
  
    o_erase_rubber(w_current);
  
    w_current->inside_action = 0;
  
    list = w_current->page_current->selection2_head->next;
    while (list != NULL) {
      OBJECT *object;
      
      object = list->selected_object;
      if (object == NULL) {
        fprintf(stderr, _("ERROR: NULL object!\n"));
        exit(-1);
      }
      if (!object->attached_to) {
        /* It's selected. Then change picture if it's a picture */
        if (object->type == OBJ_PICTURE) {
  	/* Erase previous picture */
  	o_picture_erase(w_current, object);
  
  	/* Change picture attributes */
  	if (object->picture->original_picture != NULL) {
  	  free(object->picture->original_picture);
  	  object->picture->original_picture=NULL;
  	}
  	
  	if (object->picture->filename != NULL) {
  	  free(object->picture->filename);
  	  object->picture->filename=NULL;
  	}
  	/* Create a copy of the pixbuf rotated */
  	object->picture->original_picture = gdk_pixbuf_rotate(pixbuf, 0);
  	
  	if (object->picture->original_picture == NULL) {
  	  fprintf(stderr, "change picture: Couldn't get enough memory for the new picture\n");
  	  return;
  	}
  
  	object->picture->filename = (char *) g_strdup(selected_filename);
    
  	object->picture->ratio = gdk_pixbuf_get_width(pixbuf) / 
  	  gdk_pixbuf_get_height(pixbuf);
  	/* Draw new picture */
  	o_picture_draw(w_current, object);
  
        }
      }
      list = list->next;
    }
    
    free ((char *) selected_filename);
    free(pixbuf);
    w_current->page_current->CHANGED=1;
  
    i_allow_expose();
     
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Description
   *
   */
  void picture_change_filename_dialog (TOPLEVEL *w_current)
  {
  
     GtkWidget *file_selector;
  
     /* Create the selector */
     if (!w_current->pcfswindow) {
  #if DEBUG
       printf("Creating change picture file selection dialog\n");
  #endif
       w_current->pcfswindow = gtk_file_selection_new (_("Please select a picture file."));
       file_selector = w_current->pcfswindow;
       if (w_current->pixbuf_filename)
         gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_selector),
  				       w_current->pixbuf_filename);
       gtk_window_position(GTK_WINDOW(w_current->pcfswindow),
                           GTK_WIN_POS_NONE);
       
       g_signal_connect (G_OBJECT(file_selector), "destroy",
  		       G_CALLBACK(picture_change_selection_cancel),
  		       w_current);
       
       
       g_signal_connect (GTK_OBJECT(GTK_FILE_SELECTION(file_selector)->ok_button),
                         "clicked",
                         G_CALLBACK(picture_change_selection_ok),
                         w_current);
     			   
       /* 
        * Ensure that the dialog box is destroyed when the user clicks the
        * cancel button.
        */
       g_signal_connect (GTK_OBJECT(GTK_FILE_SELECTION(file_selector)->cancel_button),
  		       "clicked",
  		       G_CALLBACK (picture_change_selection_cancel),
  		       w_current); 
     		       
     }
  
     /* Display that dialog */
     if (!GTK_WIDGET_VISIBLE (w_current->pcfswindow)) {
       gtk_widget_show (w_current->pcfswindow);
       #if 0
       gtk_grab_add (w_current->pcfswindow);
       #endif
     } else {
       gdk_window_raise(w_current->pcfswindow->window);
     }
  }
  #endif
  
  
  
  1.22      +304 -281  eda/geda/gaf/gschem/src/o_pin.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_pin.c
  ===================================================================
  RCS file: o_pin.c
  diff -N o_pin.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_pin.c	14 Jul 2006 02:23:55 -0000	1.22
  @@ -0,0 +1,367 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/x_states.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int size;
  +  int x1, y1, x2, y2; /* screen coords */
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  o_pin_recalc(w_current, o_current);
  +
  +  /* reuse line's routine */
  +  if (!o_line_visible(w_current, o_current->line, &x1, &y1, &x2, &y2)) {
  +    return;
  +  }
  +
  +#if DEBUG
  +  printf("drawing pin\n\n");
  +#endif
  +
  +  if (w_current->pin_style == THICK ) {
  +    size = SCREENabs(w_current, PIN_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->gc, size, GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  if (w_current->override_color != -1 ) {
  +    gdk_gc_set_foreground(w_current->gc,
  +			  x_get_color(w_current->override_color));
  +    gdk_draw_line(w_current->window, w_current->gc,
  +                  x1, y1, x2, y2);
  +    gdk_draw_line(w_current->backingstore, w_current->gc,
  +                  x1, y1, x2, y2);
  +  } else {
  +    gdk_gc_set_foreground(w_current->gc, x_get_color(o_current->color));
  +    gdk_draw_line(w_current->window, w_current->gc,
  +                  x1, y1, x2, y2);
  +    gdk_draw_line(w_current->backingstore, w_current->gc,
  +                  x1, y1, x2, y2);
  +  }
  +
  +  /* draw the cue directly */
  +  o_cue_draw_lowlevel(w_current, o_current, o_current->whichend);
  +  
  +  /* yes zero is right for the width -> use hardware lines */
  +  if (w_current->pin_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->gc, 0, GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +#if DEBUG
  +  printf("drawing pin\n");
  +#endif
  +
  +  if (o_current->draw_grips && w_current->draw_grips == TRUE) {	
  +    /* pb20011109 - modified to use the new o_line_[draw|erase]_grips() */
  +    /*              reuse the line functions */
  +    if (!o_current->selected) {
  +      /* object is no more selected, erase the grips */
  +      o_current->draw_grips = FALSE;
  +      o_line_erase_grips(w_current, o_current);
  +    } else {
  +      /* object is selected, draw the grips */
  +      o_line_draw_grips(w_current, o_current);
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  w_current->override_color = w_current->background_color;
  +  o_pin_draw(w_current, o_current);
  +  w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  +{
  +  int size;
  +  int color;
  +
  +  if (o_current->line == NULL) {
  +    return;
  +  }
  +
  +  if (o_current->saved_color != -1) {
  +    color = o_current->saved_color;
  +  } else {
  +    color = o_current->color;
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc, x_get_darkcolor(color));
  +
  +  if (w_current->pin_style == THICK ) {
  +    size = SCREENabs(w_current, PIN_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_draw_line(w_current->window, w_current->xor_gc,
  +                o_current->line->screen_x[0]+dx,
  +                o_current->line->screen_y[0]+dy,
  +                o_current->line->screen_x[1]+dx,
  +                o_current->line->screen_y[1]+dy);
  +
  +  if (w_current->pin_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  int size;
  +  w_current->last_x = w_current->start_x = fix_x(w_current, x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, y);
  +
  +  if (w_current->pin_style == THICK ) {
  +    size = SCREENabs(w_current, PIN_WIDTH);
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc, 
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->xor_gc, 
  +		w_current->start_x, w_current->start_y, 
  +		w_current->last_x, w_current->last_y);
  +
  +  if (w_current->pin_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_end(TOPLEVEL *w_current, int x, int y)
  +{
  +  int x1, y1;
  +  int x2, y2;
  +  int color;
  +  GList *other_objects = NULL;
  +  OBJECT *o_current, *o_current_pin;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  if (w_current->override_pin_color == -1) {
  +    color = w_current->pin_color;
  +  } else {
  +    color = w_current->override_pin_color;
  +  }
  +
  +  /* removed 3/15 to see if we can get pins to be ortho only */
  +  /* w_current->last_x = fix_x(w_current, x);
  +     w_current->last_y = fix_y(w_current, y);*/
  +
  +  /* don't allow zero length pins */
  +  if ( (w_current->start_x == w_current->last_x) &&
  +       (w_current->start_y == w_current->last_y) ) {
  +         w_current->start_x = (-1);
  +         w_current->start_y = (-1);
  +         w_current->last_x = (-1);
  +         w_current->last_y = (-1);
  +         return;
  +  }
  +
  +  SCREENtoWORLD(w_current, w_current->start_x,w_current->start_y, &x1, &y1);
  +  SCREENtoWORLD(w_current, w_current->last_x, w_current->last_y, &x2, &y2);
  +  x1 = snap_grid(w_current, x1);
  +  y1 = snap_grid(w_current, y1);
  +  x2 = snap_grid(w_current, x2);
  +  y2 = snap_grid(w_current, y2);
  +
  +  w_current->page_current->object_tail =
  +  o_pin_add(w_current,
  +            w_current->page_current->object_tail,
  +            OBJ_PIN, color,
  +            x1, y1, x2, y2,
  +            PIN_TYPE_NET, 0);
  +
  +  o_current = o_current_pin = w_current->page_current->object_tail;
  +
  +  if (scm_hook_empty_p(add_pin_hook) == SCM_BOOL_F &&
  +      o_current != NULL) {
  +    scm_run_hook(add_pin_hook,
  +		 scm_cons(g_make_object_smob(w_current, o_current),
  +			  SCM_EOL));
  +  }
  +
  +  other_objects = s_conn_return_others(other_objects, o_current_pin);
  +  o_cue_undraw_list(w_current, other_objects);
  +  o_cue_draw_list(w_current, other_objects);
  +  g_list_free(other_objects);
  +  o_cue_draw_single(w_current, o_current_pin); 
  +  o_pin_draw(w_current, o_current_pin);
  +
  +  w_current->start_x = (-1);
  +  w_current->start_y = (-1);
  +  w_current->last_x = (-1);
  +  w_current->last_y = (-1);
  +  w_current->page_current->CHANGED=1;
  +
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_pin_rubberpin(TOPLEVEL *w_current, int x, int y)
  +{
  +  int size;
  +  int diff_x, diff_y;
  +
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +
  +  size = SCREENabs(w_current, PIN_WIDTH);
  +
  +  if (w_current->pin_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc, 
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->xor_gc, 
  +		w_current->start_x, w_current->start_y, 
  +		w_current->last_x, w_current->last_y);
  +
  +  w_current->last_x = fix_x(w_current, x);
  +  w_current->last_y = fix_y(w_current, y);
  +
  +  diff_x = abs(w_current->last_x - w_current->start_x);
  +  diff_y = abs(w_current->last_y - w_current->start_y);
  +
  +  if (diff_x >= diff_y) {
  +    w_current->last_y = w_current->start_y;
  +  } else {
  +    w_current->last_x = w_current->start_x;
  +  }
  +
  +  gdk_gc_set_foreground(w_current->xor_gc, 
  +			x_get_darkcolor(w_current->select_color) );
  +  gdk_draw_line(w_current->window, w_current->xor_gc, 
  +		w_current->start_x, w_current->start_y, 
  +		w_current->last_x, w_current->last_y);
  +
  +  if (w_current->pin_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  used in o_stretch.c
  + */
  +void o_pin_eraserubber(TOPLEVEL *w_current)
  +{
  +  int size;
  +
  +  if (w_current->net_style == THICK ) {
  +    size = SCREENabs(w_current, PIN_WIDTH);
  +
  +    if (size < 0)
  +      size=0;
  +
  +    gdk_gc_set_line_attributes(w_current->xor_gc, size,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +
  +#if 0
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +			x_get_color(w_current->background_color) );
  +#endif
  +
  +  gdk_draw_line(w_current->window, w_current->xor_gc, w_current->start_x, w_current->start_y, w_current->last_x, w_current->last_y);
  +
  +  if (w_current->net_style == THICK ) {
  +    gdk_gc_set_line_attributes(w_current->xor_gc, 0,
  +                               GDK_LINE_SOLID,
  +                               GDK_CAP_NOT_LAST,
  +                               GDK_JOIN_MITER);
  +  }
  +}
  
  
  
  1.4       +409 -283  eda/geda/gaf/gschem/src/o_select.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_select.c
  ===================================================================
  RCS file: o_select.c
  diff -N o_select.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_select.c	14 Jul 2006 02:23:55 -0000	1.4
  @@ -0,0 +1,485 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +/*! The code in this file is sometimes not obvious, especially
  + * o_select_object (which implements the selection of objects either
  + * when doing a single or multi select)
  + *
  + * Also, there are cases where it looks like there is redundant code, which
  + * could be removed/merged, but I purposely didn't do so to keep the code
  + * readable
  + *
  + * the count == 0 stuff really only applies to when you are coming from a
  + * multi select case
  + */
  +#include <config.h>
  +
  +#include <math.h>
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/x_states.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_select_run_hooks(TOPLEVEL *w_current, OBJECT *o_current, int flag)
  +{
  +  /*
  +   * Run the select_component_hook if the hook has been defined and we
  +   * are selecting a component.  This will likely be used for cross probing
  +   * between schematics and PCB layout or schematics and simulation results.
  +   */
  +  if ( (scm_hook_empty_p(deselect_all_hook) == SCM_BOOL_F) 
  +       && flag == 2 )
  +  {
  +    scm_run_hook(deselect_all_hook, 
  +		 scm_cons (g_make_attrib_smob_list(w_current, o_current), 
  +			   SCM_EOL));
  +  }
  +
  +  /*
  +   * Run the select_component_hook if the hook has been defined and we
  +   * are selecting a component.  This will likely be used for cross probing
  +   * between schematics and PCB layout or schematics and simulation results.
  +   */
  +  if ( (scm_hook_empty_p(select_component_hook) == SCM_BOOL_F) 
  +       && o_current
  +       && (o_current->type == OBJ_COMPLEX) 
  +       && flag == 1 )
  +  {
  +    scm_run_hook(select_component_hook, 
  +		 scm_cons (g_make_attrib_smob_list(w_current, o_current), 
  +			   SCM_EOL));
  +  }
  +
  +  /*
  +   * Run the deselect_component_hook if the hook has been defined and we
  +   * are deselecting a component.  This will likely be used for cross probing
  +   * between schematics and PCB layout or schematics and simulation results.
  +   */
  +  if ( (scm_hook_empty_p(deselect_component_hook) == SCM_BOOL_F) 
  +       && o_current
  +       && (o_current->type == OBJ_COMPLEX) 
  +       && flag == 0 )
  +  {
  +    scm_run_hook(deselect_component_hook, 
  +		 scm_cons (g_make_attrib_smob_list(w_current, o_current), 
  +			   SCM_EOL));
  +  }
  +
  +  /*
  +   * Run the select_net_hook if the hook has been defined and we
  +   * are selecting a net.  This will likely be used for cross probing
  +   * between schematics and PCB layout or schematics and simulation results.
  +   */
  +  if ( (scm_hook_empty_p(select_net_hook) == SCM_BOOL_F) 
  +       && o_current
  +       && (o_current->type == OBJ_NET) 
  +       && flag == 1) 
  +  {
  +    scm_run_hook(select_net_hook, 
  +		 scm_cons (g_make_attrib_smob_list(w_current, o_current), 
  +			   SCM_EOL));
  +  }
  +
  +  /*
  +   * Run the deselect_net_hook if the hook has been defined and we
  +   * are deselecting a net.  This will likely be used for cross probing
  +   * between schematics and PCB layout or schematics and simulation results.
  +   */
  +  if ( (scm_hook_empty_p(select_net_hook) == SCM_BOOL_F) 
  +       && o_current
  +       && (o_current->type == OBJ_NET) 
  +       && flag == 0) 
  +  {
  +    scm_run_hook(deselect_net_hook, 
  +		 scm_cons (g_make_attrib_smob_list(w_current, o_current), 
  +			   SCM_EOL));
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  type can be either SINGLE meaning selection is a single mouse click 
  + *      or it can be MULTIPLE meaning selection is a selection box
  + */
  +void o_select_object(TOPLEVEL *w_current, OBJECT *o_current, 
  +		     int type, int count)
  +{
  +  int SHIFTKEY;
  +  int CONTROLKEY;
  +
  +  SHIFTKEY = w_current->SHIFTKEY;
  +  CONTROLKEY = w_current->CONTROLKEY;
  +
  +#if DEBUG 
  +  printf("OBJECT id: %d\n", o_current->sid);
  +#endif
  +
  +  switch(o_current->selected) {
  +
  +    case(FALSE): /* object not selected */
  +
  +      switch(SHIFTKEY) { /* shift key pressed? */
  +
  +        case(TRUE): /* shift key pressed */
  +          /* just fall through */
  +          break;
  +
  +        case(FALSE):
  +
  +          /* condition: first object being added */
  +          /* condition: control key not pressed */
  +          /* condition: for both multiple and single object added */
  +          /* result: remove all objects from selection */
  +          if (count == 0 && !CONTROLKEY) {
  +            o_select_run_hooks(w_current, NULL, 2);
  +            o_selection_remove_most(w_current,
  +                                    w_current->page_current->selection2_head);
  +          }
  +          break;
  +
  +      } /* end shift key switch */
  +
  +      /* object not select, add it to the selection list */
  +      o_select_run_hooks(w_current, o_current, 1);
  +      o_selection_add(w_current->page_current->selection2_head,
  +                      o_current);
  +
  +      break;
  +
  +
  +    case(TRUE): /* object was already selected */
  +
  +      switch(SHIFTKEY) { /* shift key pressed ? */
  +
  +        case(TRUE): /* shift key pressed */
  +
  +          /* condition: not doing multiple */
  +          /* result: remove object from selection */
  +          if (type != MULTIPLE) {
  +            o_select_run_hooks(w_current, o_current, 0);
  +            o_selection_remove(
  +                               w_current->page_current->selection2_head,
  +                               o_current);
  +          }
  +
  +          break;
  +
  +        case(FALSE): /* shift key not pressed */
  +
  +          /* condition: doing multiple */
  +          /* condition: first object being added */
  +          /* condition: control key not pressed */
  +          /* 1st result: remove all objects from selection */
  +          /* 2nd result: add object to selection */
  +          if (type == MULTIPLE && count == 0 && !CONTROLKEY) {
  +            o_select_run_hooks(w_current, NULL, 2);
  +            o_selection_remove_most(w_current,
  +                                    w_current->page_current->selection2_head);
  +	    
  +	    o_select_run_hooks(w_current, o_current, 1);
  +            o_selection_add(
  +                            w_current->page_current->selection2_head,
  +                            o_current);
  +          }	
  +
  +          /* condition: doing single object add */
  +          /* condition: control key not pressed */
  +          /* 1st result: remove all objects from selection */
  +          /* 2nd result: add object to selection list */
  +          if (type == SINGLE && !CONTROLKEY) {
  +            o_select_run_hooks(w_current, NULL, 2);
  +            o_selection_remove_most(w_current,
  +                                    w_current->page_current->selection2_head);
  +
  +            o_select_run_hooks (w_current, o_current, 1);
  +            o_selection_add(
  +                            w_current->page_current->selection2_head,
  +                            o_current);
  +          }
  +
  +          if (CONTROLKEY) {
  +            o_select_run_hooks(w_current, o_current, 0);
  +            o_selection_remove(
  +                               w_current->page_current->selection2_head,
  +                               o_current);
  +          }
  +
  +          break;
  +      } 
  +      break; /* end object selected switch */
  +  }
  +
  +  /* do the attributes */
  +  o_attrib_add_selected(w_current, w_current->page_current->selection2_head,
  +                        o_current);
  +
  +  /* finally redraw object */
  +  o_redraw_single(w_current, o_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_select_box_start(TOPLEVEL *w_current, int x, int y)
  +{
  +  int box_width, box_height;
  +
  +  /* don't set these to the passed in x, y */
  +  w_current->last_x = w_current->start_x; 
  +  w_current->last_y = w_current->start_y; 
  +
  +  box_width = abs(w_current->last_x - w_current->start_x);
  +  box_height = abs(w_current->last_y - w_current->start_y);
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +                        x_get_darkcolor(w_current->select_color));
  +  gdk_draw_rectangle(w_current->window, w_current->xor_gc,
  +                     FALSE,
  +                     w_current->start_x,
  +                     w_current->start_y,
  +                     box_width,
  +                     box_height);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_select_box_end(TOPLEVEL *w_current, int x, int y)
  +{
  +  int box_width, box_height;
  +  int box_left, box_top;
  +
  +#if 0
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +#endif
  +
  +  box_width = abs(w_current->last_x - w_current->start_x);
  +  box_height = abs(w_current->last_y - w_current->start_y);	
  +
  +  if( w_current->last_y < w_current->start_y )
  +  box_top = w_current->last_y;
  +  else
  +  box_top = w_current->start_y;
  +
  +  if( w_current->last_x < w_current->start_x )
  +  box_left = w_current->last_x;
  +  else
  +  box_left = w_current->start_x;
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +                        x_get_darkcolor(w_current->select_color));
  +  gdk_draw_rectangle(w_current->window, w_current->xor_gc,
  +                     FALSE,
  +                     box_left,
  +                     box_top,
  +                     box_width,
  +                     box_height);
  +
  +  o_select_box_search(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_select_box_rubberband(TOPLEVEL *w_current, int x, int y)
  +{
  +  int box_width, box_height;
  +  int box_left, box_top;
  +
  +#if 0
  +  if (w_current->inside_action == 0) {
  +    o_redraw(w_current, w_current->page_current->object_head);
  +    return;
  +  }
  +#endif
  +
  +  box_width = abs(w_current->last_x - w_current->start_x);
  +  box_height = abs(w_current->last_y - w_current->start_y);
  +
  +  if( w_current->last_y < w_current->start_y )
  +  box_top = w_current->last_y;
  +  else
  +  box_top = w_current->start_y;
  +
  +  if( w_current->last_x < w_current->start_x )
  +  box_left = w_current->last_x;
  +  else
  +  box_left = w_current->start_x;
  +
  +
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +                        x_get_darkcolor(w_current->select_color));
  +  gdk_draw_rectangle(w_current->window, w_current->xor_gc,
  +                     FALSE,
  +                     box_left  ,
  +                     box_top   ,
  +                     box_width ,
  +                     box_height);
  +
  +
  +  /* removed fix_x, fix_y to unrestrict sels */
  +  w_current->last_x = (int) x; 
  +  w_current->last_y = (int) y;
  +
  +  box_width = abs(w_current->last_x - w_current->start_x);
  +  box_height = abs(w_current->last_y - w_current->start_y);
  +
  +  if( w_current->last_y < w_current->start_y )
  +  box_top = w_current->last_y;
  +  else
  +  box_top = w_current->start_y;
  +
  +  if( w_current->last_x < w_current->start_x )
  +  box_left = w_current->last_x;
  +  else
  +  box_left = w_current->start_x;
  +
  +  gdk_draw_rectangle(w_current->window, w_current->xor_gc,
  +                     FALSE,
  +                     box_left,
  +                     box_top,
  +                     box_width,
  +                     box_height);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_select_box_search(TOPLEVEL *w_current) 
  +{
  +  OBJECT *o_current=NULL;
  +  int count = 0; /* object count */
  +  int SHIFTKEY = w_current->SHIFTKEY;
  +	
  +  int tmp;
  +	
  +  if( w_current->last_x < w_current->start_x ) {
  +    tmp = w_current->last_x;
  +    w_current->last_x = w_current->start_x;
  +    w_current->start_x = tmp;
  +  }
  +
  +  if( w_current->last_y < w_current->start_y ) {
  +    tmp = w_current->last_y;
  +    w_current->last_y = w_current->start_y;
  +    w_current->start_y = tmp;
  +  }
  +
  +  o_current = w_current->page_current->object_head;
  +
  +  while (o_current != NULL) {
  +    /* only select visible objects */
  +    if (o_current->type != OBJ_HEAD && 
  +        (o_current->visibility == VISIBLE ||
  +        (o_current->visibility == INVISIBLE && w_current->show_hidden_text))) {
  +      if ( (o_current->left >= w_current->start_x && 
  +            o_current->top >= w_current->start_y) &&
  +           (o_current->left >= w_current->start_x && 
  +            o_current->bottom <= w_current->last_y) &&
  +           (o_current->right <= w_current->last_x && 
  +            o_current->top >= w_current->start_y ) &&
  +           (o_current->right <= w_current->last_x && 
  +            o_current->bottom <= w_current->last_y) ) {
  +
  +        o_select_object(w_current, o_current, 	
  +                        MULTIPLE, count);
  +        count++;
  +      }
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +  /* if there were no objects to be found in select box, count will be */
  +  /* zero, and you need to deselect anything remaining (unless the shift */
  +  /* key was pressed */
  +  if (count == 0 && !SHIFTKEY)  {
  +    o_select_run_hooks(w_current, NULL, 2);
  +    o_selection_remove_most(w_current,
  +			    w_current->page_current->selection2_head);
  +  }
  +  i_update_menus(w_current);
  +}
  +
  +/* This is a wrapper for o_selection_return_first_object */
  +/* This function always looks at the current page selection list */ 
  +OBJECT *o_select_return_first_object(TOPLEVEL *w_current) 
  +{
  +  return(o_selection_return_first_object(w_current->page_current->
  +                                         selection2_head));
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + * \return TRUE if the selection list is not empty, otherwise false.
  + * also make sure item is valid
  + */
  +int o_select_selected(TOPLEVEL *w_current)
  +{
  +  SELECTION *head;
  +
  +  head = w_current->page_current->selection2_head;
  +  if (head) {
  +    if (head->next) {
  +      if (head->next->selected_object) {
  +        return(TRUE);
  +      }
  +    }
  +  }
  +  return(FALSE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_select_unselect_all(TOPLEVEL *w_current)
  +{
  +  o_select_run_hooks(w_current, NULL, 2);
  +  o_selection_remove_most(w_current, 
  +                          w_current->page_current->selection2_head);
  +}
  
  
  
  1.18      +193 -170  eda/geda/gaf/gschem/src/o_slot.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_slot.c
  ===================================================================
  RCS file: o_slot.c
  diff -N o_slot.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_slot.c	14 Jul 2006 02:23:55 -0000	1.18
  @@ -0,0 +1,246 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define MAX_SLOT_SIZE 10
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Change slot of selected component
  + *  \par Function Description
  + *
  + */
  +void o_slot_start(TOPLEVEL *w_current, OBJECT *list)
  +{
  +  OBJECT *object;
  +  OBJECT *slot_text_object;
  +  char *default_slot_value;
  +  char *slot_value;
  +
  +  /* shouldn't happen */
  +  if (list == NULL) {
  +    /* this is an error condition hack */
  +    w_current->inside_action = 0;
  +    i_set_state(w_current, SELECT);
  +    return;
  +  }
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  /* single object for now */
  +  if (object->type == OBJ_COMPLEX) {
  +    /* first see if slot attribute already exists outside
  +     * complex */
  +    slot_value = o_attrib_search_slot(object, &slot_text_object);
  +
  +    if (slot_value) {
  +#if DEBUG
  +      printf("slot=%s\n", slot_value);
  +      printf("text string : %s\n",
  +             slot_text_object->text->string);
  +#endif
  +      slot_edit_dialog(w_current,
  +                       slot_text_object->text->string);
  +      free(slot_value);
  +    } else {
  +      /* we didn't find an attached slot=? attribute */
  +
  +      /* See if there is a default value */
  +      default_slot_value =
  +        o_attrib_search_default_slot(object);
  +
  +      if (default_slot_value) {
  +				/* two is for null and equals sign */
  +        slot_value = (char *) malloc(sizeof(char)*(
  +                                                   strlen("slot")+
  +                                                   strlen(default_slot_value)+
  +                                                   2));
  +        sprintf(slot_value, "slot=%s",
  +                default_slot_value);
  +      } else {
  +				/* no default, make something up? */
  +				/* for now.. this is an error
  +                                   condition */
  +        slot_value = g_strdup ("slot=1");
  +      }
  +
  +#if DEBUG
  +      printf("slot value: %s\n", slot_value);
  +#endif
  +
  +      slot_edit_dialog(w_current, slot_value);
  +      free(slot_value);
  +      free(default_slot_value);
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_slot_end(TOPLEVEL *w_current, char *string, int len)
  +{
  +  OBJECT *object;
  +  OBJECT *temp;
  +  char *slot_value;
  +  char *numslots_value;
  +  OBJECT *slot_text_object;
  +  char *name = NULL;
  +  char *value = NULL;
  +  int numslots;
  +  int new_slot_number;
  +  int status;
  +
  +  status = o_attrib_get_name_value(string, &name, &value);
  +  if (!status) {
  +    s_log_message(_("Slot attribute malformed\n"));
  +    return;
  +  }
  +
  +  object = o_select_return_first_object(w_current);
  +
  +  /* now find the slot attribute on the outside first */
  +  if (object != NULL) {
  +    numslots_value = o_attrib_search_numslots(object, NULL);
  +
  +    if (!numslots_value) {
  +      s_log_message(_("numslots attribute missing\n"));
  +      s_log_message(
  +                    _("Slotting not allowed for this component\n"));
  +      if (name) free(name);
  +      if (value) free(value);
  +      return;
  +    }
  +
  +    numslots = atoi(numslots_value);
  +    free(numslots_value);
  +
  +    new_slot_number = atoi(value);
  +
  +#if DEBUG
  +    printf("numslots = %d\n", numslots);
  +#endif
  +
  +    if (new_slot_number > numslots || new_slot_number <=0 ) {
  +      s_log_message(_("New slot number out of range\n"));
  +      if (name) free(name);
  +      if (value) free(value);
  +      return;
  +    }
  +
  +    /* first see if slot attribute already exists outside
  +     * complex */
  +    slot_value = o_attrib_search_slot(object, &slot_text_object);
  +
  +    if (slot_value) {
  +      if (slot_text_object->text->string) {
  +        free(slot_text_object->text->string);
  +      }
  +
  +      slot_text_object->text->string = g_strdup (string);
  +
  +      temp = slot_text_object;
  +
  +      if (temp->visibility == VISIBLE ||
  +          (temp->visibility == INVISIBLE && w_current->show_hidden_text)) {
  +        o_erase_single(w_current,temp);
  +      }
  +
  +      o_text_recreate(w_current, temp);
  +
  +      /* this doesn't deal with the selection list
  +       * item */
  +      if (temp->visibility == VISIBLE ||
  +          (temp->visibility == INVISIBLE && w_current->show_hidden_text)) {
  +        o_redraw_single(w_current,temp);
  +      }
  +
  +      free(slot_value);
  +
  +    } else {
  +      /* here you need to do the add the slot
  +         attribute since it doesn't exist */
  +      w_current->page_current->object_tail =
  +        (OBJECT *) o_text_add(
  +                              w_current,
  +                              w_current->page_current->object_tail,
  +                              OBJ_TEXT, w_current->text_color,
  +                              object->complex->x, object->complex->y,
  +                              LOWER_LEFT,
  +                              0, /* zero is angle */
  +                              string,
  +                              10,
  +                              INVISIBLE, SHOW_NAME_VALUE);
  +
  +      /* manually attach attribute */
  +
  +      /* NEWSEL this is okay too, since tail is single obj */
  +      o_attrib_attach(w_current,
  +                      w_current->page_current->object_head,
  +                      w_current->page_current->object_tail,
  +                      object);
  +
  +      slot_text_object =
  +        w_current->page_current->object_tail;
  +    }
  +
  +    o_erase_single(w_current, object);
  +    o_attrib_slot_update(w_current, object);
  +
  +
  +#if 0 /* NEWSEL */
  +    /* why? */
  +    /* erase the selection list */
  +    o_erase_selected(w_current);
  +
  +    o_attrib_slot_copy(w_current, object,
  +                       w_current->page_current->selection_head->next);
  +    o_redraw_single(w_current,object);
  +#endif
  +
  +    o_redraw_single(w_current,object);
  +
  +    w_current->page_current->CHANGED = 1;
  +    o_undo_savestate(w_current, UNDO_ALL);
  +    if (name) free(name);
  +    if (value) free(value);
  +
  +  } else {
  +    fprintf(stderr,
  +            _("uggg! you tried to slot edit something that doesn't exist!\n"));
  +    if (name) free(name);
  +    if (value) free(value);
  +    exit(-1);
  +  }
  +}
  
  
  
  1.17      +690 -501  eda/geda/gaf/gschem/src/o_text.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_text.c
  ===================================================================
  RCS file: o_text.c
  diff -N o_text.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_text.c	14 Jul 2006 02:23:55 -0000	1.17
  @@ -0,0 +1,758 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/stat.h>
  +#include <math.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define WINONLY	1
  +#define BACKING 2
  +
  +/* font storage and friends are staying global so that all can access */
  +#define NUM_CHARS 255
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_draw_lowlevel(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int left, right, top, bottom;
  +
  +  if (o_current->visibility == INVISIBLE && w_current->show_hidden_text &&
  +      o_current->text->prim_objs == NULL) {
  +    o_text_recreate(w_current, o_current);
  +  }
  +  
  +  o_redraw(w_current, o_current->text->prim_objs);
  +
  +  get_complex_bounds(w_current, o_current->text->prim_objs,
  +                     &left, &top, &right, &bottom);
  +  o_current->left   = left;
  +  o_current->top    = top;
  +  o_current->right  = right;
  +  o_current->bottom = bottom;
  +
  +  WORLDtoSCREEN(w_current,
  +                o_current->text->x,
  +                o_current->text->y,
  +                &o_current->text->screen_x,
  +                &o_current->text->screen_y);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_draw_rectangle(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int left=0, right=0, top=0, bottom=0;
  +  int screen_x1, screen_y1;
  +  int width, height, dx=0, dy=0;
  +  GdkColor *color;
  +
  +  if (o_current->visibility == INVISIBLE && w_current->show_hidden_text &&
  +      o_current->text->prim_objs == NULL) {
  +    o_text_recreate(w_current, o_current);
  +  }
  +  
  +  o_text_recalc(w_current, o_current);
  +
  +  /* text is too small so go through and draw a rectangle in
  +     it's place */
  +	
  +  screen_x1 = o_current->text->screen_x;
  +  screen_y1 = o_current->text->screen_y;
  +
  +  if (w_current->override_color != -1 ) {  /* Override */
  +    color = x_get_color(w_current->override_color);
  +  } else {
  +    color = x_get_color(o_current->color);
  +  }
  +  gdk_gc_set_foreground(w_current->gc, color);
  +
  +
  +  width = SCREENabs(w_current, o_current->text->displayed_width);
  +  height = SCREENabs(w_current, o_current->text->displayed_height);
  +      
  +  switch(o_current->text->angle) {
  +    case(0):
  +      left = screen_x1+dx;
  +      top = screen_y1+dy-height;
  +      right = width;
  +      bottom = height;
  +      break;
  +	
  +    case(90):
  +      left = screen_x1+dx-height;
  +      top = screen_y1+dy-width;
  +      right = height;
  +      bottom = width;
  +      break;
  +	  
  +    case(180):
  +      left = screen_x1+dx-width;
  +      top = screen_y1+dy;
  +      right = width;
  +      bottom = height;
  +      break;
  +	
  +    case(270):
  +      left = screen_x1+dx;
  +      top = screen_y1+dy;
  +      right = height;
  +      bottom = width;
  +      break;
  +
  +    default:
  +      s_log_message(_("Tried to render text with an invalid angle: %d\n"),
  +                    o_current->text->angle); 
  +      return;
  +      break;
  +  }
  +
  +  /* The right, bottom variables are really just the width and height and */
  +  /* not the "right" or "bottom". */
  +  gdk_draw_rectangle(w_current->window,
  +                     w_current->gc,
  +                     FALSE,
  +                     left, 
  +                     top,
  +                     right,
  +                     bottom);
  +  gdk_draw_rectangle(w_current->backingstore,
  +                     w_current->gc,
  +                     FALSE,
  +                     left, 
  +                     top,
  +                     right,
  +                     bottom);
  +
  +#if 0 /* in prep for future performance enhancement */
  +  right = right+left;
  +  bottom = bottom+top;
  +  o_current->left   = min(left, right);
  +  o_current->top    = min(top, bottom);
  +  o_current->right  = max(left, right);
  +  o_current->bottom = max(top, bottom);
  +  
  +  printf("%d %d %d %d\n", left, top, right, bottom);
  +  
  +  WORLDtoSCREEN(w_current,
  +                o_current->text->x,
  +                o_current->text->y,
  +                &o_current->text->screen_x,
  +                &o_current->text->screen_y);
  +#endif
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_draw(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1;
  +  int small_dist, offset;
  +
  +  if (o_current->visibility == INVISIBLE && !w_current->show_hidden_text) {
  +    return;
  +  }
  +
  +  if (!w_current->fast_mousepan || !w_current->doing_pan) {
  +
  +#if 0 /* in prep for future performance enhancement... */
  +    int pixel_height;
  +    pixel_height = SCREENabs(w_current, 26*o_current->text->size/2);
  +    if (pixel_height < 4 /* && w_current->text_rectangle */)
  +    {
  +      o_text_draw_rectangle(w_current, o_current);
  +    } else {
  +      o_text_draw_lowlevel(w_current, o_current);
  +    }
  +#endif
  +    
  +    o_text_draw_lowlevel(w_current, o_current);
  +
  +    /* Indicate on the schematic that the text is invisible by */
  +    /* drawing a little I on the screen at the origin */
  +    if (o_current->visibility == INVISIBLE && w_current->show_hidden_text) {
  +      if (w_current->override_color != -1 ) {
  +        gdk_gc_set_foreground(w_current->gc, 
  +                              x_get_color(w_current->override_color));
  +      } else {
  +
  +        gdk_gc_set_foreground(w_current->gc, 
  +                              x_get_color(w_current->lock_color));
  +      }
  +
  +      offset = SCREENabs(w_current, 10);
  +      small_dist = SCREENabs(w_current, 20);
  +      screen_x1 = o_current->text->screen_x + offset;
  +      screen_y1 = o_current->text->screen_y + offset;
  +      /* Top part of the I */
  +      gdk_draw_line(w_current->window, w_current->gc,
  +		    screen_x1,
  +		    screen_y1,
  +		    screen_x1+small_dist,
  +		    screen_y1);
  +      gdk_draw_line(w_current->backingstore, w_current->gc, 
  +		    screen_x1,
  +		    screen_y1,
  +		    screen_x1+small_dist,
  +		    screen_y1);
  +      /* Middle part of the I */
  +      gdk_draw_line(w_current->window, w_current->gc,
  +		    screen_x1+small_dist/2,
  +		    screen_y1,
  +		    screen_x1+small_dist/2,
  +		    screen_y1+small_dist);
  +      gdk_draw_line(w_current->backingstore, w_current->gc, 
  +		    screen_x1+small_dist/2,
  +		    screen_y1,
  +		    screen_x1+small_dist/2,
  +		    screen_y1+small_dist);
  +      /* Bottom part of the I */
  +      gdk_draw_line(w_current->window, w_current->gc,
  +		    screen_x1,
  +		    screen_y1+small_dist,
  +		    screen_x1+small_dist,
  +		    screen_y1+small_dist);
  +      gdk_draw_line(w_current->backingstore, w_current->gc, 
  +		    screen_x1,
  +		    screen_y1+small_dist,
  +		    screen_x1+small_dist,
  +		    screen_y1+small_dist);
  +      
  +    }
  +    
  +  } else {
  +    if (w_current->doing_pan) {
  +      o_text_draw_rectangle(w_current, o_current);
  +      return;
  +    }
  +  }
  +	
  +  /* return if text origin marker displaying is disabled */ 
  +  if (w_current->text_origin_marker == FALSE) {
  +    return;
  +  }
  +
  +  small_dist = SCREENabs(w_current, 10);
  +
  +  screen_x1 = o_current->text->screen_x;
  +  screen_y1 = o_current->text->screen_y;
  +
  +  /* this is not really a fix, but a lame patch */
  +  /* not having this will cause a bad draw of things when coords */
  +  /* get close to the 2^15 limit of X */
  +  if (screen_x1+small_dist > 32767 || screen_y1+small_dist > 32767) {
  +    return;
  +  }
  +
  +  if (w_current->override_color != -1 ) {
  +    gdk_gc_set_foreground(w_current->gc, 
  +                          x_get_color(w_current->override_color));
  +  } else {
  +
  +    gdk_gc_set_foreground(w_current->gc, 
  +                          x_get_color(w_current->lock_color));
  +  }
  +
  +  gdk_draw_line(w_current->window, w_current->gc, 
  +                screen_x1-small_dist, 
  +                screen_y1+small_dist, 
  +                screen_x1+small_dist, 
  +                screen_y1-small_dist);
  +  gdk_draw_line(w_current->backingstore, w_current->gc, 
  +                screen_x1-small_dist, 
  +                screen_y1+small_dist, 
  +                screen_x1+small_dist, 
  +                screen_y1-small_dist);
  +
  +  gdk_draw_line(w_current->window, w_current->gc, 
  +                screen_x1+small_dist, 
  +                screen_y1+small_dist, 
  +                screen_x1-small_dist, 
  +                screen_y1-small_dist);
  +  gdk_draw_line(w_current->backingstore, w_current->gc, 
  +                screen_x1+small_dist, 
  +                screen_y1+small_dist, 
  +                screen_x1-small_dist, 
  +                screen_y1-small_dist);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_erase(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  w_current->override_color = w_current->background_color;
  +  o_text_draw(w_current, o_current);
  +  w_current->override_color = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_draw_xor(TOPLEVEL *w_current, int dx, int dy, OBJECT *o_current)
  +{
  +  int screen_x1, screen_y1;
  +  int width, height;
  +  int color, factor;
  +
  +  if (o_current->visibility == INVISIBLE && !w_current->show_hidden_text) {
  +    return;
  +  }
  +
  +  /* always display text which is 12 or larger */
  +  factor = (int) w_current->page_current->to_world_x_constant;
  +  if ((factor < w_current->text_display_zoomfactor) ||
  +      o_current->text->size >= 12 ||
  +      w_current->text_feedback == ALWAYS) {
  +    o_complex_draw_xor(w_current, dx, dy, o_current->text->prim_objs);
  +  } else {
  +    /* text is too small so go through and draw a line in
  +       it's place */
  +
  +    screen_x1 = o_current->text->screen_x;
  +    screen_y1 = o_current->text->screen_y;
  +
  +    if (o_current->saved_color != -1) {
  +      color = o_current->saved_color;
  +    } else {
  +      color = o_current->color;
  +    }
  +
  +    gdk_gc_set_foreground(w_current->outline_xor_gc,
  +                          x_get_darkcolor(color));
  +
  +#if 0
  +    width = SCREENabs(w_current, o_text_width(w_current, 
  +                                               o_current->text->string,
  +                                               o_current->text->size/2)); 
  +    height = SCREENabs(w_current, o_text_height(o_current->text->string,
  +						o_current->text->size));
  +#endif
  +
  +    width = SCREENabs(w_current, o_current->text->displayed_width);
  +    height = SCREENabs(w_current, o_current->text->displayed_height);
  +
  +    switch(o_current->text->angle) {
  +      case(0):
  +	gdk_draw_rectangle(w_current->window,
  +			   w_current->outline_xor_gc,
  +			   FALSE,
  +			   screen_x1+dx,
  +			   screen_y1+dy-height,
  +			   width,
  +			   height);
  +        break;
  +
  +      case(90):
  +	gdk_draw_rectangle(w_current->window,
  +			   w_current->outline_xor_gc,
  +			   FALSE,
  +			   screen_x1+dx-height,
  +			   screen_y1+dy-width,
  +			   height,
  +			   width);
  +        break;
  +
  +      case(180):
  +	gdk_draw_rectangle(w_current->window,
  +			   w_current->outline_xor_gc,
  +			   FALSE,
  +			   screen_x1+dx-width,
  +			   screen_y1+dy,
  +			   width,
  +			   height);
  +
  +        break;
  +
  +      case(270):
  +	gdk_draw_rectangle(w_current->window,
  +			   w_current->outline_xor_gc,
  +			   FALSE,
  +			   screen_x1+dx,
  +			   screen_y1+dy,
  +			   height,
  +			   width);
  +        break;
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_input(TOPLEVEL *w_current)
  +{
  +  text_input_dialog(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_start(TOPLEVEL *w_current, int screen_x, int screen_y)
  +{
  +  int x, y;
  +  int temp, i;
  +  char *value;
  +
  +  w_current->last_x = w_current->start_x = fix_x(w_current, screen_x);
  +  w_current->last_y = w_current->start_y = fix_y(w_current, screen_y);
  +
  +  w_current->last_drawb_mode = -1;
  +
  +  /* make sure list is null first, so that you don't have a mem leak */
  +  SCREENtoWORLD(w_current,
  +                w_current->start_x,
  +                w_current->start_y,
  +                &x,
  +                &y);
  +
  +  /* remove the old attrib list if it exists without killing the
  +     head structure */
  +  o_list_delete_rest(w_current,
  +                     w_current->page_current->attrib_place_head);
  +
  +  value = w_current->current_attribute;
  +
  +  switch(w_current->text_caps) {
  +    case(LOWER):
  +      string_tolower(value, value);
  +      break;
  +
  +    case(UPPER):
  +      string_toupper(value, value);
  +      break;
  +
  +    case(BOTH):
  +    default:
  +      /* do nothing */
  +      break;
  +  }
  +
  +  /* here you need to add OBJ_TEXT when it's done */
  +  w_current->page_current->attrib_place_tail =
  +  (OBJECT *) o_text_add(
  +			w_current,
  +			w_current->page_current->attrib_place_head,
  +				/* type changed from TEXT to TEXT */
  +			OBJ_TEXT, w_current->text_color,
  +			x, y, LOWER_LEFT, 0, /* zero is angle */
  +			w_current->current_attribute,
  +			w_current->text_size,
  +			/* has to be visible so you can place it */
  +			/* visibility is set when you create the object */
  +			VISIBLE, SHOW_NAME_VALUE);
  +
  +  if (w_current->complex_rotate) {
  +    temp = w_current->complex_rotate / 90;
  +    for (i = 0; i < temp; i++) {
  +      o_text_place_rotate(w_current);
  +    }
  +  }
  +
  +  o_drawbounding(w_current,
  +                 w_current->page_current->attrib_place_head->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), TRUE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_end(TOPLEVEL *w_current)
  +{
  +  /*! \todo get consistant names */
  +  int world_x, world_y;
  +
  +  SCREENtoWORLD(w_current,
  +                w_current->last_x,
  +                w_current->last_y,
  +                &world_x,
  +                &world_y);
  +
  +  world_x = snap_grid(w_current, world_x);
  +  world_y = snap_grid(w_current, world_y);
  +
  +  /* here you need to add OBJ_TEXT when it's done */
  +  /*! \todo make this VIS and SHOW default configurable */
  +  w_current->page_current->object_tail =
  +  o_text_add(w_current, w_current->page_current->object_tail,
  +				/* type changed from TEXT to TEXT */
  +             OBJ_TEXT,
  +             w_current->text_color,
  +             world_x, world_y, LOWER_LEFT, 
  +             w_current->complex_rotate,
  +             w_current->current_attribute,
  +             w_current->text_size,
  +             VISIBLE, SHOW_NAME_VALUE);
  +
  +  /* if the text is invisible then you need to erase the outline
  +     left by the place */
  +  if (w_current->current_visible == INVISIBLE) {
  +    o_drawbounding(
  +                   w_current,
  +                   w_current->page_current->attrib_place_head->next,
  +                   NULL,
  +                   x_get_darkcolor(w_current->bb_color), FALSE);
  +  }
  +  /*! \todo you need to erase the bounding box if have that mode
  +     set!!! */
  +
  +  /* erase the old bounding box / outline */
  +  if (w_current->actionfeedback_mode == OUTLINE) {
  +    o_drawbounding(
  +                   w_current,
  +                   w_current->page_current->attrib_place_head->next,
  +                   NULL,
  +                   x_get_color(w_current->text_color), FALSE);
  +  } else {
  +    o_drawbounding(
  +                   w_current,
  +                   w_current->page_current->attrib_place_head->next,
  +                   NULL,
  +                   x_get_darkcolor(w_current->select_color), FALSE);
  +  }
  +
  +  w_current->override_color = -1;
  +
  +  w_current->page_current->CHANGED=1;
  +  o_select_run_hooks(w_current, NULL, 2); 
  +  o_selection_remove_most(w_current,
  +                          w_current->page_current->selection2_head);
  +  o_selection_add(w_current->page_current->selection2_head, 
  +                  w_current->page_current->object_tail);
  +	
  +
  +  /* object_tail is the object that was just added */
  +  if (w_current->page_current->object_tail->draw_func != NULL &&
  +      w_current->page_current->object_tail->type != OBJ_HEAD) {
  +    (*w_current->page_current->object_tail->draw_func)(
  +                                                       w_current,
  +                                                       w_current->page_current->object_tail);
  +  }
  +
  +  w_current->override_color = -1;
  +  o_undo_savestate(w_current, UNDO_ALL);
  +  i_update_menus(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_rubberattrib(TOPLEVEL *w_current)
  +{
  +  o_drawbounding(w_current,
  +                 w_current->page_current->attrib_place_head->next,
  +                 NULL,
  +                 x_get_darkcolor(w_current->bb_color), FALSE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_edit(TOPLEVEL *w_current, OBJECT *o_current)
  +{
  +  /* you need to check to make sure only one object is selected */
  +  /* no actually this is okay... not here in o_edit */
  +  text_edit_dialog(w_current,
  +                   o_current->text->string, o_current->text->size,
  +                   o_current->text->alignment);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_edit_end(TOPLEVEL *w_current, char *string, int len, int text_size,
  +		     int text_alignment)
  +{
  +  OBJECT *object;
  +  SELECTION *s_current;
  +  int numselect;
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +  numselect = o_selection_return_num(w_current->page_current->selection2_head);
  +  
  +  while(s_current != NULL) {
  +    object = s_current->selected_object;
  +
  +    if (object) {
  +      if (object->type == OBJ_TEXT) {
  +
  +        /* only change text string if there is only ONE text object selected */
  +        if (numselect == 1 && string) {
  +          if (object->text->string) {
  +            free(object->text->string);
  +          }
  +          /* Kazu <kazu@xxxxxxxx> on August 5, 1999 - I am not
  +             sure if strlen(string) == len. If so, activate the
  +             second part of this "if".*/
  +#if 1
  +          object->text->string = malloc(sizeof(char) * len + 1);
  +          strcpy(object->text->string, string);
  +#else
  +          object->text->string = g_strdup (string);
  +#endif
  +        }
  +
  +        object->text->size = text_size;
  +        object->text->alignment = text_alignment;
  +		
  +        /* probably the text object should be extended to carry a color */
  +        /* and we should pass it here with a function parameter (?) */
  +        object->saved_color = w_current->edit_color;
  +
  +        o_text_erase(w_current, object);
  +        o_text_recreate(w_current, object);
  +        o_text_draw(w_current, object);
  +
  +      } 
  +    }
  +    
  +    s_current = s_current->next;
  +  }
  +  
  +  w_current->page_current->CHANGED = 1;
  +  o_undo_savestate(w_current, UNDO_ALL);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  The object passed in should be the REAL object, NOT any copy in any
  + *  selection list
  + */
  +void o_text_change(TOPLEVEL *w_current, OBJECT *object, char *string, 
  +		   int visibility, int show)
  +{
  +  if (object == NULL) {
  +    return;
  +  }
  +
  +  if (object->type != OBJ_TEXT) {
  +    return;
  +  }
  +
  +  /* erase old object */
  +  o_text_erase(w_current, object);
  +
  +  /* second change the real object */
  +  if (object->text->string) {
  +    free(object->text->string);
  +  }
  +
  +  object->text->string = g_strdup (string);
  +  object->visibility = visibility;
  +  object->show_name_value = show;
  +  o_text_recreate(w_current, object);
  +  o_text_draw(w_current, object);
  +
  +  /* handle slot= attribute, it's a special case */
  +  if (g_ascii_strncasecmp (string, "slot=", 5) == 0) {
  +    o_slot_end (w_current, string, strlen (string));
  +  }
  +
  +  w_current->page_current->CHANGED = 1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_text_place_rotate(TOPLEVEL *w_current)
  +{
  +  OBJECT *o_current;
  +  int screen_x_local = -1;
  +  int screen_y_local = -1;
  +  int new_angle;
  +
  +  o_current = w_current->page_current->attrib_place_head->next;
  +  while(o_current) {
  +    switch(o_current->type) {	
  +      case(OBJ_TEXT):
  +        screen_x_local = o_current->text->screen_x; 
  +        screen_y_local = o_current->text->screen_y;
  +        break;
  +    }
  +    o_current = o_current->next;
  +  }
  +
  +  if (screen_x_local == -1) {
  +    printf("Could not find text obj in new text placement!\n");
  +    return;
  +  }
  +
  +  o_current = w_current->page_current->attrib_place_head->next;
  +  while(o_current) {
  +    switch(o_current->type) {	
  +
  +      case(OBJ_TEXT):
  +        new_angle = (o_current->text->angle + 90) % 360;
  +        o_text_rotate(w_current, screen_x_local, screen_y_local,
  +                      new_angle, 90, o_current);
  +        break;
  +    }
  +    o_current = o_current->next;
  +  }
  +}
  
  
  
  1.6       +428 -313  eda/geda/gaf/gschem/src/o_undo.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: o_undo.c
  ===================================================================
  RCS file: o_undo.c
  diff -N o_undo.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ o_undo.c	14 Jul 2006 02:23:55 -0000	1.6
  @@ -0,0 +1,540 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define GET_PAGE_WIDTH(w)                                       \
  +        ((w)->page_current->right  - (w)->page_current->left)
  +
  +static int undo_file_index=0;
  +static int prog_pid=0;
  +
  +/* TMP environment variable */
  +static char* TMP = NULL;
  +static int freeTMP = FALSE;
  +
  +/* this is additional number of levels (or history) at which point the */
  +/* undo stack will be trimmed, it's used a safety to prevent running out */ 
  +/* of entries to free */
  +#define UNDO_PADDING  5
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_undo_init(void)
  +{
  +  prog_pid = getpid();	
  +
  +  TMP = getenv("TMP");
  +  if (!TMP) {
  +     TMP = g_strdup ("/tmp");
  +     freeTMP = TRUE;
  +  } 
  +#if DEBUG
  +  printf("%s\n", TMP);
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  
  + *  <B>flag</B> can be one of the following values:
  + *  <DL>
  + *    <DT>*</DT><DD>UNDO_ALL
  + *    <DT>*</DT><DD>UNDO_VIEWPORT_ONLY
  + *  </DL>
  + */
  +void o_undo_savestate(TOPLEVEL *w_current, int flag)
  +{
  +  char *filename = NULL;
  +  OBJECT *object_head = NULL;
  +  int levels;
  +  UNDO *u_current;
  +  UNDO *u_current_next;
  +
  +  /* save autosave backups if necessary */
  +  o_autosave_backups(w_current);
  +
  +  if (w_current->undo_control == FALSE) {
  +    return;	
  +  }
  +
  +  if (w_current->undo_type == UNDO_DISK && flag == UNDO_ALL) {
  +
  +    /* Increment the number of operations since last backup if 
  +       auto-save is enabled */
  +    if (w_current->auto_save_interval != 0) {
  +      w_current->page_current->ops_since_last_backup++;
  +    }
  +
  +    /* 32 is? for max length of pid and index */
  + 
  +
  +    filename = malloc(sizeof(char)*(strlen("/gschem.save_.sch")+
  +	              strlen(TMP)+32));
  +
  +    sprintf(filename, "%s%cgschem.save%d_%d.sch", TMP, G_DIR_SEPARATOR,
  +            prog_pid, 
  +            undo_file_index++);
  +
  +    /* Changed from f_save to o_save when adding backup copy creation. */
  +    /* f_save manages the creaton of backup copies. 
  +       This way, f_save is called only when saving a file, and not when
  +       saving an undo backup copy */
  +    o_save(w_current, filename);
  +
  +		
  +  } else if (w_current->undo_type == UNDO_MEMORY && flag == UNDO_ALL) {
  +
  +    /* Increment the number of operations since last backup if 
  +       auto-save is enabled */
  +    if (w_current->auto_save_interval != 0) {
  +      w_current->page_current->ops_since_last_backup++;
  +    }
  +
  +    object_head = s_basic_init_object("undo_head");	
  +		
  +    o_list_copy_all(w_current, 
  +                    w_current->page_current->object_head->next,
  +                    object_head, NORMAL_FLAG);
  +  }
  +
  +  /* Clear Anything above current */
  +  if (w_current->page_current->undo_current) {
  +    s_undo_remove_rest(w_current, 
  +                       w_current->page_current->undo_current->next);
  +    w_current->page_current->undo_current->next = NULL;
  +  } else { /* undo current is NULL */
  +    s_undo_remove_rest(w_current, 
  +                       w_current->page_current->undo_bottom);
  +    w_current->page_current->undo_bottom = NULL;
  +  }
  +	
  +  w_current->page_current->undo_tos = w_current->page_current->undo_current;
  +
  +  w_current->page_current->undo_tos =
  +  s_undo_add(w_current->page_current->undo_tos, 
  +             flag, filename, object_head,
  +             w_current->page_current->left, 
  +             w_current->page_current->top,
  +             w_current->page_current->right,
  +             w_current->page_current->bottom,
  +             w_current->page_current->page_control,
  +             w_current->page_current->up);
  +
  +  w_current->page_current->undo_current = 
  +  w_current->page_current->undo_tos;
  +
  +  if (w_current->page_current->undo_bottom == NULL) {
  +    w_current->page_current->undo_bottom = 
  +      w_current->page_current->undo_tos;	
  +  }
  +
  +#if DEBUG
  +  printf("\n\n---Undo----\n");
  +  s_undo_print_all(w_current->page_current->undo_bottom);
  +  printf("BOTTOM: %s\n", w_current->page_current->undo_bottom->filename);
  +  printf("TOS: %s\n", w_current->page_current->undo_tos->filename);
  +  printf("CURRENT: %s\n", w_current->page_current->undo_current->filename);
  +  printf("----\n");
  +#endif
  +
  +  if (filename) {	
  +    free(filename);
  +  }
  +	
  +  /* Now go through and see if we need to free/remove some undo levels */ 
  +  /* so we stay within the limits */
  +
  +  /* only check history every 10 undo savestates */
  +  if (undo_file_index % 10) {
  +    return;
  +  }
  +
  +  levels = s_undo_levels(w_current->page_current->undo_bottom);
  +	
  +#if DEBUG
  +  printf("levels: %d\n", levels);
  +#endif
  +	
  +  if (levels >= w_current->undo_levels + UNDO_PADDING) {
  +    levels = levels - w_current->undo_levels;
  +
  +#if DEBUG
  +    printf("Trimming: %d levels\n", levels);
  +#endif
  +
  +    u_current = w_current->page_current->undo_bottom;
  +    while(u_current && levels > 0) {
  +      u_current_next = u_current->next;
  +		
  +      if (u_current->filename) {
  +#if DEBUG
  +        printf("Freeing: %s\n", u_current->filename);
  +#endif
  +        unlink(u_current->filename);
  +        free(u_current->filename);	
  +      }	
  +			
  +      if (u_current->object_head) {
  +        w_current->REMOVING_SEL = 1;
  +        s_delete_list_fromstart(w_current, 
  +                                u_current->object_head);
  +        w_current->REMOVING_SEL = 0; 
  +        u_current->object_head = NULL; 
  +      }
  +
  +      u_current->next = NULL;
  +      u_current->prev = NULL;
  +      free(u_current);
  +			
  +      u_current = u_current_next;
  +      levels--;
  +    }
  +
  +    /* Because we use a pad you are always garanteed to never */	
  +    /* exhaust the list */
  +    u_current->prev = NULL;
  +    w_current->page_current->undo_bottom = u_current;
  +
  +#if DEBUG		
  +    printf("New current is: %s\n", u_current->filename);
  +#endif
  +  }
  +	
  +#if DEBUG
  +  printf("\n\n---Undo----\n");
  +  s_undo_print_all(w_current->page_current->undo_bottom);
  +  printf("BOTTOM: %s\n", w_current->page_current->undo_bottom->filename);
  +  printf("TOS: %s\n", w_current->page_current->undo_tos->filename);
  +  printf("CURRENT: %s\n", w_current->page_current->undo_current->filename);
  +  printf("----\n");
  +#endif
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +char *o_undo_find_prev_filename(UNDO *start)
  +{
  +  UNDO *u_current;
  +	
  +  u_current = start->prev;
  +	
  +  while(u_current) {
  +    if (u_current->filename) {
  +      return(u_current->filename);	
  +    }	
  +    u_current = u_current->prev;
  +  }
  +	
  +  return(NULL); 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +OBJECT *o_undo_find_prev_object_head(UNDO *start)
  +{
  +  UNDO *u_current;
  +	
  +  u_current = start->prev;
  +	
  +  while(u_current) {
  +    if (u_current->object_head) {
  +      return(u_current->object_head);	
  +    }	
  +    u_current = u_current->prev;
  +  }
  +	
  +  return(NULL); 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  <B>type</B> can be one of the following values:
  + *  <DL>
  + *    <DT>*</DT><DD>UNDO_ACTION
  + *    <DT>*</DT><DD>REDO_ACTION
  + *  </DL>
  + */
  +void o_undo_callback(TOPLEVEL *w_current, int type)
  +{
  +  UNDO *u_current;
  +  UNDO *u_next;
  +  UNDO *save_bottom;
  +  UNDO *save_tos;
  +  UNDO *save_current;
  +  int save_logging;
  +  int diff_x;
  +  int find_prev_data=FALSE;
  +  int prev_status;
  +
  +  char *save_filename;
  +	
  +  if (w_current->undo_control == FALSE) {
  +    s_log_message(_("Undo/Redo disabled in rc file\n"));
  +    return;	
  +  }
  +
  +  if (w_current->page_current->undo_current == NULL) {
  +    return;	
  +  }
  +
  +  if (type == UNDO_ACTION) {
  +    u_current = w_current->page_current->undo_current->prev;
  +  } else {
  +    u_current = w_current->page_current->undo_current->next;
  +  }
  +
  +  u_next = w_current->page_current->undo_current;
  +
  +  if (u_current == NULL) {
  +    return;	
  +  }
  +
  +  if (u_next->type == UNDO_ALL && u_current->type == UNDO_VIEWPORT_ONLY) {
  +#if DEBUG
  +    printf("Type: %d\n", u_current->type);
  +    printf("Current is an undo all, next is viewport only!\n");	
  +#endif
  +    find_prev_data = TRUE;
  +	
  +    if (w_current->undo_type == UNDO_DISK) {	
  +      u_current->filename = 
  +        o_undo_find_prev_filename(u_current);	
  +    } else {
  +      u_current->object_head = 
  +      o_undo_find_prev_object_head(u_current);	
  +    }
  +  }
  +
  +  /* save filename */
  +  save_filename = g_strdup (w_current->page_current->page_filename);
  +
  +  /* save structure so it's not nuked */	
  +  save_bottom = w_current->page_current->undo_bottom;
  +  save_tos = w_current->page_current->undo_tos;
  +  save_current = w_current->page_current->undo_current;
  +  w_current->page_current->undo_bottom = NULL; 
  +  w_current->page_current->undo_tos =  NULL;
  +  w_current->page_current->undo_current =  NULL;
  +
  +  if (w_current->undo_type == UNDO_DISK && u_current->filename) {
  +    PAGE *p_new;
  +    s_page_delete (w_current, w_current->page_current);
  +    p_new = s_page_new(w_current, u_current->filename);
  +    s_page_goto (w_current, p_new);
  +  } else if (w_current->undo_type == UNDO_MEMORY && 
  +             u_current->object_head) {
  +               PAGE *p_new;
  +               s_page_delete (w_current, w_current->page_current);
  +               p_new = s_page_new (w_current, save_filename);
  +               s_page_goto (w_current, p_new);
  +             }
  +
  +  /* temporarily disable logging */
  +  save_logging = do_logging;
  +  prev_status = w_current->DONT_REDRAW;
  +  w_current->DONT_REDRAW = 1;
  +  do_logging = FALSE;
  +
  +  if (w_current->undo_type == UNDO_DISK && u_current->filename) {
  +
  +    f_open(w_current, u_current->filename);
  +
  +    x_manual_resize(w_current);
  +    w_current->page_current->page_control = u_current->page_control;
  +    w_current->page_current->up = u_current->up;
  +    w_current->page_current->CHANGED=1;
  +
  +  } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_head) { 
  +
  +    s_delete_list_fromstart(w_current, 
  +                            w_current->page_current->object_head);
  +		
  +    w_current->page_current->object_head = 
  +    s_basic_init_object("object_head");
  +    w_current->page_current->object_head->type = OBJ_HEAD;
  +		
  +    o_list_copy_all(w_current, u_current->object_head->next, 
  +                    w_current->page_current->object_head, 
  +                    NORMAL_FLAG);
  +		
  +    w_current->page_current->object_tail = return_tail(
  +                                                       w_current->page_current->object_head);
  +    x_manual_resize(w_current);
  +    w_current->page_current->page_control = u_current->page_control;
  +    w_current->page_current->up = u_current->up;
  +    w_current->page_current->CHANGED=1;
  +  }
  +
  +  /* do misc setups */
  +  set_window(w_current, w_current->page_current,
  +             u_current->left, u_current->right, 
  +             u_current->top, u_current->bottom);
  +  x_hscrollbar_update(w_current);
  +  x_vscrollbar_update(w_current);
  +
  +  /* restore logging */
  +  do_logging = save_logging;
  +
  +  /* set filename right */
  +  free(w_current->page_current->page_filename);
  +  w_current->page_current->page_filename = save_filename;
  +
  +  /* final redraw */
  +  x_pagesel_update (w_current);
  +
  +  /* Let the caller to decide if redraw or not */
  +  /* w_current->DONT_REDRAW = 0; */
  +  w_current->DONT_REDRAW = prev_status;
  +
  +  diff_x = GET_PAGE_WIDTH (w_current);
  +
  +#if 0 /* zoom factor is no longer used */
  +#ifdef HAS_RINT
  +  w_current->page_current->ZOOM_FACTOR= (int) rint(w_current->init_right /
  +                                                   diff_x);
  +#else
  +  w_current->page_current->ZOOM_FACTOR = (int) (w_current->init_right /
  +                                                diff_x);
  +#endif
  +#endif
  +
  +  if (!w_current->DONT_REDRAW) {
  +    o_redraw_all(w_current);
  +  }
  +  i_update_menus(w_current);
  +
  +  /* restore saved undo structures */
  +  w_current->page_current->undo_bottom = save_bottom;
  +  w_current->page_current->undo_tos = save_tos;
  +  w_current->page_current->undo_current = save_current;
  +
  +  if (type == UNDO_ACTION) { 
  +    if (w_current->page_current->undo_current) {
  +      w_current->page_current->undo_current = 
  +        w_current->page_current->undo_current->prev;
  +      if (w_current->page_current->undo_current == NULL) {
  +        w_current->page_current->undo_current = 
  +          w_current->page_current->undo_bottom;
  +      }
  +    }
  +  } else { /* type is REDO_ACTION */
  +    if (w_current->page_current->undo_current) {
  +      w_current->page_current->undo_current = 
  +      w_current->page_current->undo_current->next;
  +      if (w_current->page_current->undo_current == NULL) {
  +        w_current->page_current->undo_current = 
  +          w_current->page_current->undo_tos;
  +      }
  +    }
  +  }
  +
  +  /* don't have to free data here since filename, object_head are */
  +  /* just pointers to the real data (lower in the stack) */
  +  if (find_prev_data) {
  +    u_current->filename = NULL;	
  +    u_current->object_head = NULL;	
  +  }
  +
  +#if DEBUG
  +  printf("\n\n---Undo----\n");
  +  s_undo_print_all(w_current->page_current->undo_bottom);
  +  printf("TOS: %s\n", w_current->page_current->undo_tos->filename);
  +  printf("CURRENT: %s\n", w_current->page_current->undo_current->filename);
  +  printf("----\n");
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_undo_cleanup(void)
  +{
  +  int i;
  +  char *filename;
  +
  +  for (i = 0 ; i < undo_file_index; i++) {
  +    filename = g_strdup_printf("%s%cgschem.save%d_%d.sch", TMP, G_DIR_SEPARATOR,
  +			       prog_pid, i);
  +    unlink(filename);
  +    free(filename);
  +  }
  +
  +  if (freeTMP) {
  +    free(TMP);
  +    TMP = NULL;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void o_undo_remove_last_undo(TOPLEVEL *w_current)
  +{
  +  if (w_current->page_current->undo_current == NULL) {
  +    return;	
  +  }
  +
  +  if (w_current->page_current->undo_current) {
  +    w_current->page_current->undo_current = 
  +      w_current->page_current->undo_current->prev;
  +    if (w_current->page_current->undo_current == NULL) {
  +      w_current->page_current->undo_current = 
  +        w_current->page_current->undo_bottom;
  +    }
  +  }
  +
  +
  +
  +}
  
  
  
  1.11      +75 -58    eda/geda/gaf/gschem/src/parsecmd.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: parsecmd.c
  ===================================================================
  RCS file: parsecmd.c
  diff -N parsecmd.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ parsecmd.c	14 Jul 2006 02:23:55 -0000	1.11
  @@ -0,0 +1,117 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define OPTIONS "hqvr:s:o:pt"
  +
  +#ifndef OPTARG_IN_UNISTD
  +extern char *optarg;
  +extern int optind;
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void usage(char *cmd)
  +{
  +  printf(_("Usage: %s [OPTIONS] schematic_filename1 ... schematic_filenameN\n"
  +         "  -q            Quiet mode\n"
  +         "  -v            Verbose mode on\n"
  +         "  -r filename   Rc filename\n"
  +         "  -s filename   Script (guile) filename\n"
  +         "  -o filename   Output filename (for printing)\n"
  +         "  -p            Automatically place the window\n"
  +         "  -t            Print stroke information\n"
  +         "  -h            Help; this message\n"
  +         "\n"), cmd);
  +  exit(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +int parse_commandline(int argc, char *argv[])
  +{
  +  int ch;
  +
  +  while ((ch = getopt (argc, argv, OPTIONS)) != -1) {
  +    switch (ch) {
  +      case 'v':
  +        verbose_mode = TRUE;
  +        break;
  +
  +      case 't':
  +        stroke_info_mode = TRUE;
  +        break;
  +
  +      case 'q':
  +        quiet_mode = TRUE;
  +        break;
  +
  +      case 'r':
  +        rc_filename = g_strdup (optarg);
  +        break;
  +
  +      case 's':
  +        script_filename = g_strdup (optarg);
  +        break;
  +
  +      case 'o':
  +        output_filename = g_strdup (optarg);
  +        break;
  +
  +      case 'p':
  +        auto_place_mode = TRUE;
  +        break;
  +
  +      case 'h':
  +        usage(argv[0]);
  +        break;
  +
  +      case '?':
  +      default:
  +        usage(argv[0]);
  +        break;
  +    }
  +  }
  +
  +  if (quiet_mode) {
  +    verbose_mode = FALSE;
  +  }
  +
  +  return(optind);
  +}
  
  
  
  1.1                  eda/geda/gaf/gschem/src/x_attribedit.c
  
  Index: x_attribedit.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * gschem - gEDA Schematic Capture
   * Copyright (C) 1998-2000 Ales V. Hvezda
   *
   * 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 USA
   */
  /*! \todo STILL NEED to clean up line lengths in aa and tr
   */
  #include <config.h>
  
  #include <stdio.h>
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  
  #include <libgeda/libgeda.h>
  
  #include "../include/i_vars.h"
  #include "../include/globals.h"
  #include "../include/prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  
  /***************** Start of Attrib Edit dialog box ********************/
  /*! \section attrib-edit-dialog-box Atrib Edit Dialog Box */
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Documentation
   *
   */
  gint option_menu_get_history (GtkOptionMenu *option_menu) 
  { 
    GtkWidget *active_widget; 
           
    g_return_val_if_fail (GTK_IS_OPTION_MENU (option_menu), -1); 
           
    active_widget = gtk_menu_get_active (GTK_MENU (option_menu->menu)); 
  
    if (active_widget) 
    return g_list_index (GTK_MENU_SHELL (option_menu->menu)->children, 
                         active_widget); 
    else 
    return -1; 
  } 
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Documentation
   *
   */
  int attrib_edit_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  				TOPLEVEL * w_current)
  {
    if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
      attrib_edit_dialog_cancel(NULL, w_current);	
      return TRUE;
    }
    
    return FALSE;
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Documentation
   *
   */
  void attrib_edit_dialog_ok(GtkWidget * w, TOPLEVEL * w_current)
  {
    const char *value, *label;
    char *newtext;
    GtkEntry *value_entry, *name_entry;
    GtkWidget *visbutton, *show_options;
    GtkWidget *addtocompsbutton, *addtonetsbutton, *addtoallbutton;
    GtkWidget *overwritebutton;
    OBJECT *attribptr;
    OBJECT *object;
    SELECTION *s_current = NULL;
    ATTRIB *a_current = NULL, *a_sav;
    int vis, show;
    int invocation_flag;
    int nsel=0, addto=0, replace=0, addmask=0;
    int option_index;
  
    i_set_state(w_current, SELECT);
  
    value_entry =
    gtk_object_get_data(GTK_OBJECT(w_current->aewindow), "value_entry");
    name_entry =
    gtk_object_get_data(GTK_OBJECT(w_current->aewindow), "attrib_combo_entry");
    visbutton =
    gtk_object_get_data(GTK_OBJECT(w_current->aewindow), "visbutton");
    show_options =
    gtk_object_get_data(GTK_OBJECT(w_current->aewindow), "show_options");
  
    value = gtk_entry_get_text(value_entry);
    label = gtk_entry_get_text(name_entry);
    newtext = g_strconcat (label, "=", value, NULL);
  
    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(visbutton)))
    vis = VISIBLE;
    else
    vis = INVISIBLE;
  
    option_index = option_menu_get_history(GTK_OPTION_MENU (show_options));
    switch(option_index) {
      case(0):
        show = SHOW_VALUE;
        break;
  
      case(1):
        show = SHOW_NAME;
        break;
  
      case(2):
        show = SHOW_NAME_VALUE;
        break;
  
      default:
        fprintf(stderr, _("Got invalid show option; defaulting to show both\n"));
        show = SHOW_NAME_VALUE;
        break;
    }
  
    attribptr =
    gtk_object_get_data(GTK_OBJECT(w_current->aewindow), "attrib");
    if (!attribptr) {
      int world_x, world_y;
      OBJECT *new = NULL;
  
      s_current = w_current->page_current->selection2_head->next;
      while (s_current != NULL) {
        object = s_current->selected_object;
        if (object == NULL) {
  	fprintf(stderr, _("ERROR: NULL object!\n"));
  	exit(-1);
        }
        if (!s_current->selected_object->attached_to) {
  	nsel++;
        }
        s_current = s_current->next;
      }
      s_current = w_current->page_current->selection2_head->next;
      if (nsel > 1) {
  
        addtoallbutton =
          gtk_object_get_data(GTK_OBJECT(w_current->aewindow),
                              "addtoallbutton");
  
        addtocompsbutton =
          gtk_object_get_data(GTK_OBJECT(w_current->aewindow),
                              "addtocompsbutton");
  
        addtonetsbutton =
          gtk_object_get_data(GTK_OBJECT(w_current->aewindow),
                              "addtonetsbutton");
  
        overwritebutton =
          gtk_object_get_data(GTK_OBJECT(w_current->aewindow),
                              "overwritebutton");
  
        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overwritebutton))) {
  	replace = 1;
        } else {
  	replace = 0;
        }
  
        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(addtoallbutton))) {
  	addto = 7;
        }
        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(addtocompsbutton))) {
  	addto = 2;
        }
        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(addtonetsbutton))) {
  	addto = 1;
        }
  
        while (s_current != NULL) {
  	gboolean replaced;
  
  	object = s_current->selected_object;
  	if (object && !object->attached_to && object->type != OBJ_TEXT ) {
  	  addmask = 4;
  	  if (object->type == OBJ_COMPLEX || object->type == OBJ_PLACEHOLDER) {
  	    addmask = 2;
  	  }
  	  if (object->type == OBJ_NET) {
  	    addmask = 1;
  	  }
  	  replaced = FALSE;
  	  if (addmask & addto) {
  	    a_current = object->attribs;
  	    if (replace) {
  	      while (a_current != NULL) {
  		a_sav = a_current;
  		a_current = a_current->next;
  
  		if (a_sav->object->text != NULL) {
  		  if (!strncmp
  		      (a_sav->object->text->string, newtext,
  		       strchr(newtext, '=') - newtext)) {
  		    o_text_change(w_current, a_sav->object, 
  				  newtext, vis, show);
  		    replaced = TRUE;
  		    w_current->page_current->CHANGED = 1;
  		  }
  		}
  	      }
  	    }
  	    if (!replaced) {
  	      new = o_attrib_add_attrib(w_current, newtext, vis, show, object);
  	    }
  	  }
  	}
  	s_current = s_current->next;
        }
        o_undo_savestate(w_current, UNDO_ALL);
      } else {
        object = o_select_return_first_object(w_current);
        new = o_attrib_add_attrib(w_current, newtext, vis, show, object);
  
        invocation_flag =
  	(int) gtk_object_get_data(GTK_OBJECT(w_current->aewindow),
  				  "invocation_flag");
        
  #if DEBUG
        printf("invocation flag: %d\n", invocation_flag);
  #endif
        if (invocation_flag == FROM_HOTKEY) {
  	SCREENtoWORLD(w_current, mouse_x, mouse_y, &world_x, &world_y);
  	new->text->x = world_x;
  	new->text->y = world_y;
  	o_text_erase(w_current, new);
  	o_text_recreate(w_current, new);
  	o_text_draw(w_current, new);
  	w_current->page_current->CHANGED = 1;
  	o_undo_savestate(w_current, UNDO_ALL);
        }
      }
    } else {
      o_text_change(w_current, attribptr, newtext, vis, show);
      w_current->page_current->CHANGED = 1;
      o_undo_savestate(w_current, UNDO_ALL);
    }
    gtk_grab_remove(w_current->aewindow);
    gtk_widget_destroy(w_current->aewindow);
    w_current->aewindow = NULL;
    free(newtext);
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Documentation
   *
   */
  void attrib_edit_dialog_cancel(GtkWidget *w, TOPLEVEL *w_current)
  {
    i_set_state(w_current, SELECT);
    gtk_grab_remove(w_current->aewindow);
    gtk_widget_destroy(w_current->aewindow);
    w_current->aewindow = NULL;
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Documentation
   *
   */
  void attrib_edit_dialog_delete(GtkWidget *w, TOPLEVEL *w_current)
  {
    OBJECT *object;
  
    /* for now unselect everything, but in the future you really ought 
     * to just unselect a single object */
    o_unselect_all(w_current);
  
    object = gtk_object_get_data(GTK_OBJECT(w_current->aewindow),"attrib");
    o_delete_text(w_current, object);
    w_current->page_current->CHANGED=1;
    o_undo_savestate(w_current, UNDO_ALL);
  
    i_set_state(w_current, SELECT);
    i_update_menus(w_current);
    gtk_grab_remove(w_current->aewindow);
    gtk_widget_destroy(w_current->aewindow);
    w_current->aewindow = NULL;
  }
  
  /*! \todo Finish function documentation!!!
   *  \brief
   *  \par Function Documentation
   *
   */
  void attrib_edit_dialog(TOPLEVEL * w_current, OBJECT * list, int flag)
  {
    GtkWidget *aewindow;
    GtkWidget *table1;
    GtkWidget *hbox1;
    GtkWidget *hbuttonbox1;
    GtkWidget *okbutton;
    GtkWidget *deletebutton=NULL;
    GtkWidget *cancelbutton;
    GtkWidget *frame1;
    GtkWidget *table3;
    GtkWidget *show_options;
    GtkWidget *show_options_menu;
    GtkWidget *glade_menuitem;
    GtkWidget *attrib_combo;
    GtkWidget *attrib_combo_entry;
    GtkWidget *value_entry;
    GtkWidget *visbutton;
    GtkWidget *label2;
    GtkWidget *label1;
    GtkWidget *frame2;
    GtkWidget *hbox2;
    GSList *hbox2_group = NULL;
    GtkWidget *addtoallbutton;
    GtkWidget *addtocompsbutton;
    GtkWidget *addtonetsbutton;
    GtkWidget *overwritebutton;
  
    /* gschem specific */
    SELECTION *s_current = NULL;
    GList *combo_items = NULL;
    char* string = NULL;
    int nsel=0, i, len;
    char *name = NULL;
    char *val = NULL;
    OBJECT *attrib = NULL;
    
    /* gschem specific */
    if (w_current->aewindow)
    return;
  
    /* gschem specific */
    s_current = w_current->page_current->selection2_head->next;
    while (s_current != NULL) {
      if (!s_current->selected_object->attached_to) {
        nsel++;
      }
      s_current = s_current->next;
    }
  #ifdef HAS_GTK22
    aewindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  #else
    aewindow = gtk_window_new (GTK_WINDOW_DIALOG);
  #endif
    gtk_object_set_data (GTK_OBJECT (aewindow), "aewindow", aewindow);
    gtk_window_set_title (GTK_WINDOW (aewindow), _("Single Attribute Editor"));
    gtk_window_set_position (GTK_WINDOW (aewindow), GTK_WIN_POS_MOUSE);
    gtk_window_set_modal (GTK_WINDOW (aewindow), TRUE);
  
    table1 = gtk_table_new (3, 1, FALSE);
    gtk_widget_ref (table1);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "table1", table1,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (table1);
    gtk_container_add (GTK_CONTAINER (aewindow), table1);
    gtk_container_set_border_width (GTK_CONTAINER (aewindow), 5);
  
    hbox1 = gtk_hbox_new (FALSE, 0);
    gtk_widget_ref (hbox1);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "hbox1", hbox1,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (hbox1);
    gtk_table_attach (GTK_TABLE (table1), hbox1, 0, 1, 2, 3,
                      (GtkAttachOptions) (GTK_FILL),
                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0);
  
    hbuttonbox1 = gtk_hbutton_box_new ();
    gtk_widget_ref (hbuttonbox1);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "hbuttonbox1", hbuttonbox1,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (hbuttonbox1);
    gtk_box_pack_start (GTK_BOX (hbox1), hbuttonbox1, TRUE, TRUE, 0);
    gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 1);
  
  #ifdef HAS_GTK12
    okbutton = gtk_button_new_with_label ("OK");
  #else
    okbutton = gtk_button_new_from_stock (GTK_STOCK_OK);
  #endif
    gtk_widget_ref (okbutton);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "okbutton", okbutton,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (okbutton);
    gtk_container_add (GTK_CONTAINER (hbuttonbox1), okbutton);
    gtk_container_set_border_width (GTK_CONTAINER (okbutton), 3);
    GTK_WIDGET_SET_FLAGS (okbutton, GTK_CAN_DEFAULT);
    gtk_button_set_relief (GTK_BUTTON (okbutton), GTK_RELIEF_HALF);
  
    if (list) { /* gschem specific */
  #ifdef HAS_GTK12
      deletebutton = gtk_button_new_with_label (_("Delete"));
  #else
      deletebutton = gtk_button_new_from_stock (GTK_STOCK_DELETE);
  #endif
      gtk_widget_ref (deletebutton);
      gtk_object_set_data_full (GTK_OBJECT (aewindow), "deletebutton", deletebutton,
                                (GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_show (deletebutton);
      gtk_container_add (GTK_CONTAINER (hbuttonbox1), deletebutton);
      gtk_container_set_border_width (GTK_CONTAINER (deletebutton), 3);
      GTK_WIDGET_SET_FLAGS (deletebutton, GTK_CAN_DEFAULT);
    }
  
  #ifdef HAS_GTK12
    cancelbutton = gtk_button_new_with_label (_("Cancel"));
  #else
    cancelbutton = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  #endif
    gtk_widget_ref (cancelbutton);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "cancelbutton", cancelbutton,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (cancelbutton);
    gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancelbutton);
    gtk_container_set_border_width (GTK_CONTAINER (cancelbutton), 3);
    GTK_WIDGET_SET_FLAGS (cancelbutton, GTK_CAN_DEFAULT);
  
    frame1 = gtk_frame_new (_("Add/Edit Attribute"));
    gtk_widget_ref (frame1);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "frame1", frame1,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (frame1);
    gtk_table_attach (GTK_TABLE (table1), frame1, 0, 1, 0, 1,
                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
                      (GtkAttachOptions) (GTK_FILL), 0, 0);
    gtk_container_set_border_width (GTK_CONTAINER (frame1), 6);
  
    table3 = gtk_table_new (3, 2, FALSE);
    gtk_widget_ref (table3);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "table3", table3,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (table3);
    gtk_container_add (GTK_CONTAINER (frame1), table3);
    gtk_container_set_border_width (GTK_CONTAINER (table3), 6);
  
    attrib_combo = gtk_combo_new ();
    gtk_widget_ref (attrib_combo);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "attrib_combo", attrib_combo,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (attrib_combo);
    gtk_table_attach (GTK_TABLE (table3), attrib_combo, 1, 2, 0, 1,
                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
                      (GtkAttachOptions) (0), 0, 0);
  
    attrib_combo_entry = GTK_COMBO (attrib_combo)->entry;
    gtk_widget_ref (attrib_combo_entry);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "attrib_combo_entry", attrib_combo_entry,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (attrib_combo_entry);
  
    value_entry = gtk_entry_new ();
    gtk_widget_ref (value_entry);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "value_entry", value_entry,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (value_entry);
    gtk_table_attach (GTK_TABLE (table3), value_entry, 1, 2, 1, 2,
                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
                      (GtkAttachOptions) (0), 0, 8);
  
    visbutton = gtk_check_button_new_with_label (_("Visible"));
    gtk_widget_ref (visbutton);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "visbutton", visbutton,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (visbutton);
    gtk_table_attach (GTK_TABLE (table3), visbutton, 0, 1, 2, 3,
                      (GtkAttachOptions) (GTK_FILL),
                      (GtkAttachOptions) (0), 3, 0);
    gtk_container_set_border_width (GTK_CONTAINER (visbutton), 3);
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (visbutton), TRUE);
  
    label2 = gtk_label_new (_("Value:"));
    gtk_widget_ref (label2);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "label2", label2,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (label2);
    gtk_table_attach (GTK_TABLE (table3), label2, 0, 1, 1, 2,
                      (GtkAttachOptions) (0),
                      (GtkAttachOptions) (0), 0, 3);
    gtk_misc_set_alignment (GTK_MISC (label2), 0, 0.5);
  
    label1 = gtk_label_new (_("Name:"));
    gtk_widget_ref (label1);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "label1", label1,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (label1);
    gtk_table_attach (GTK_TABLE (table3), label1, 0, 1, 0, 1,
                      (GtkAttachOptions) (0),
                      (GtkAttachOptions) (0), 0, 3);
    gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_RIGHT);
    gtk_misc_set_alignment (GTK_MISC (label1), 0, 0.5);
    gtk_misc_set_padding (GTK_MISC (label1), 4, 0);
  
    show_options = gtk_option_menu_new ();
    gtk_widget_ref (show_options);
    gtk_object_set_data_full (GTK_OBJECT (aewindow), "show_options",
                              show_options,
                              (GtkDestroyNotify) gtk_widget_unref);
    gtk_widget_show (show_options);
    gtk_table_attach (GTK_TABLE (table3), show_options, 1, 2, 2, 3,
                      (GtkAttachOptions) (GTK_FILL),
                      (GtkAttachOptions) (0), 0, 0);
    show_options_menu = gtk_menu_new ();
    glade_menuitem = gtk_menu_item_new_with_label (_("Show Value Only"));
    gtk_widget_show (glade_menuitem);
    gtk_menu_append (GTK_MENU (show_options_menu), glade_menuitem);
    glade_menuitem = gtk_menu_item_new_with_label (_("Show Name Only"));
    gtk_widget_show (glade_menuitem);
    gtk_menu_append (GTK_MENU (show_options_menu), glade_menuitem);
    glade_menuitem = gtk_menu_item_new_with_label (_("Show Name & Value"));
    gtk_widget_show (glade_menuitem);
    gtk_menu_append (GTK_MENU (show_options_menu), glade_menuitem);
    gtk_option_menu_set_menu (GTK_OPTION_MENU (show_options), show_options_menu);
    gtk_option_menu_set_history (GTK_OPTION_MENU (show_options), 0);
    
    if (nsel > 1) { /* gschem specific */
      frame2 = gtk_frame_new (_("Multiple Attach"));
      gtk_widget_ref (frame2);
      gtk_object_set_data_full (GTK_OBJECT (aewindow), "frame2", frame2,
                                (GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_show (frame2);
      gtk_table_attach (GTK_TABLE (table1), frame2, 0, 1, 1, 2,
                        (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
                        (GtkAttachOptions) (GTK_FILL), 0, 0);
      gtk_container_set_border_width (GTK_CONTAINER (frame2), 6);
  
      hbox2 = gtk_hbox_new (FALSE, 0);
      gtk_widget_ref (hbox2);
      gtk_object_set_data_full (GTK_OBJECT (aewindow), "hbox2", hbox2,
                                (GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_show (hbox2);
      gtk_container_add (GTK_CONTAINER (frame2), hbox2);
  
      addtoallbutton = gtk_radio_button_new_with_label (hbox2_group, _("All"));
      hbox2_group = gtk_radio_button_group (GTK_RADIO_BUTTON (addtoallbutton));
      gtk_widget_ref (addtoallbutton);
      gtk_object_set_data_full (GTK_OBJECT (aewindow), "addtoallbutton", addtoallbutton,
                                (GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_show (addtoallbutton);
      gtk_box_pack_start (GTK_BOX (hbox2), addtoallbutton, FALSE, FALSE, 0);
      gtk_container_set_border_width (GTK_CONTAINER (addtoallbutton), 3);
  
      addtocompsbutton = gtk_radio_button_new_with_label (hbox2_group, _("Components"));
      hbox2_group = gtk_radio_button_group (GTK_RADIO_BUTTON (addtocompsbutton));
      gtk_widget_ref (addtocompsbutton);
      gtk_object_set_data_full (GTK_OBJECT (aewindow), "addtocompsbutton", addtocompsbutton,
                                (GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_show (addtocompsbutton);
      gtk_box_pack_start (GTK_BOX (hbox2), addtocompsbutton, FALSE, FALSE, 0);
      gtk_container_set_border_width (GTK_CONTAINER (addtocompsbutton), 3);
  
      addtonetsbutton = gtk_radio_button_new_with_label (hbox2_group, _("Nets"));
      hbox2_group = gtk_radio_button_group (GTK_RADIO_BUTTON (addtonetsbutton));
      gtk_widget_ref (addtonetsbutton);
      gtk_object_set_data_full (GTK_OBJECT (aewindow), "addtonetsbutton", addtonetsbutton,
                                (GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_show (addtonetsbutton);
      gtk_box_pack_start (GTK_BOX (hbox2), addtonetsbutton, FALSE, FALSE, 0);
  
      overwritebutton = gtk_check_button_new_with_label (_("Replace"));
      gtk_widget_ref (overwritebutton);
      gtk_object_set_data_full (GTK_OBJECT (aewindow), "overwritebutton", overwritebutton,
                                (GtkDestroyNotify) gtk_widget_unref);
      gtk_widget_show (overwritebutton);
      gtk_box_pack_start (GTK_BOX (hbox2), overwritebutton, FALSE, FALSE, 0);
    }
  
    /* gschem specific */
    if (list) {
      o_attrib_get_name_value(list->text->string, &name, &val);
      attrib = list;
      if (attrib->visibility == VISIBLE) {
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(visbutton), TRUE);
      } else {
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(visbutton), FALSE);
      }
  
      if (attrib->show_name_value == SHOW_VALUE) {
        gtk_option_menu_set_history (GTK_OPTION_MENU (show_options), 0);
      } else if (attrib->show_name_value == SHOW_NAME) {
        gtk_option_menu_set_history (GTK_OPTION_MENU (show_options), 1);
      } else {
        gtk_option_menu_set_history (GTK_OPTION_MENU (show_options), 2);
      }
    } else {
      OBJECT *object;
  
      attrib = NULL;
  
      if ((object = o_select_return_first_object(w_current))) {
        if (object->type == OBJ_NET)
  	name = g_strdup("netname");
      }
  
      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(visbutton), TRUE);
      /* show value only */
      gtk_option_menu_set_history (GTK_OPTION_MENU (show_options), 0);
    }
    gtk_object_set_data(GTK_OBJECT(aewindow), "attrib", attrib);
    if (name) {
      gtk_entry_set_text(GTK_ENTRY(attrib_combo_entry), name);
    }
    if (val) {
      gtk_entry_set_text(GTK_ENTRY(value_entry), val);
      len = strlen(val);
      gtk_entry_select_region(GTK_ENTRY(value_entry), 0, len);
    }
    gtk_object_set_data(GTK_OBJECT(aewindow), "invocation_flag",
                        (gpointer) flag);
    
    /* gschem specific */
    i = 0;
    string = (char *) s_attrib_get(i);
    while (string != NULL) {
      combo_items = g_list_append(combo_items, string);
      i++;
      string = (char *) s_attrib_get(i);
    }
    combo_items = g_list_prepend(combo_items, name);
    gtk_combo_set_popdown_strings(GTK_COMBO(attrib_combo), combo_items);
    g_list_free(combo_items);
    
    /* gschem specific */
    gtk_widget_show(aewindow);
    w_current->aewindow = aewindow;
  
    /* gschem specific */
    gtk_signal_connect(GTK_OBJECT(aewindow), "destroy",
  		     GTK_SIGNAL_FUNC(destroy_window),
  		     &w_current->aewindow);
    gtk_signal_connect(GTK_OBJECT(okbutton), "clicked",
  		     GTK_SIGNAL_FUNC(attrib_edit_dialog_ok), w_current);
    gtk_signal_connect(GTK_OBJECT(cancelbutton), "clicked",
  		     GTK_SIGNAL_FUNC(attrib_edit_dialog_cancel),
  		     w_current);
    gtk_signal_connect(GTK_OBJECT(value_entry), "activate",
  		     GTK_SIGNAL_FUNC(attrib_edit_dialog_ok), w_current);
  
    gtk_signal_connect(GTK_OBJECT(aewindow), "key_press_event",
                       (GtkSignalFunc) attrib_edit_dialog_keypress, w_current);
  
    if (list) {
      gtk_signal_connect(GTK_OBJECT(deletebutton), "clicked",
  		       GTK_SIGNAL_FUNC(attrib_edit_dialog_delete),
  		       w_current);
    }
  
    gtk_grab_add(w_current->aewindow);
  
    if (attrib || (name && strcmp(name, "netname") == 0)) { 
      gtk_widget_grab_focus(value_entry);
    } else {  
      gtk_widget_grab_focus(attrib_combo_entry);
    }
  
    if (name) free(name);
    if (val) free(val);
  
  }
  /***************** End of Attrib Edit dialog box **********************/
  
  
  
  1.14      +227 -166  eda/geda/gaf/gschem/src/x_basic.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_basic.c
  ===================================================================
  RCS file: x_basic.c
  diff -N x_basic.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_basic.c	14 Jul 2006 02:23:55 -0000	1.14
  @@ -0,0 +1,342 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/x_event.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#ifndef __MINGW32__
  +#include <gdk/gdkx.h>
  +#endif
  +
  +#if 0 /* once you are sure your new color system works... delete code */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +GdkColor *x_get_color(int color)
  +{
  +  switch(color) {
  +    case(RED):    return(&red   ); break;
  +    case(BLUE):   return(&blue  ); break;
  +    case(GREEN):  return(&green ); break;
  +    case(YELLOW): return(&yellow); break;
  +    case(CYAN):   return(&cyan  ); break;
  +    case(GREY):   return(&grey  ); break;
  +    case(GREY90): return(&grey90); break;
  +    case(BLACK):  return(&black ); break;
  +    case(WHITE):  return(&white ); break;
  +    default:      return(&white ); break;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +GdkColor *x_get_darkcolor(int color)
  +{
  +  switch(color) {
  +    case(RED):    return(&darkred   ); break;
  +    case(BLUE):   return(&darkblue  ); break;
  +    case(GREEN):  return(&darkgreen ); break;
  +    case(YELLOW): return(&darkyellow); break;
  +    case(CYAN):   return(&darkcyan  ); break;
  +    case(GREY):   return(&darkgrey  ); break;
  +    case(BLACK):  return(&black     ); break;
  +    case(WHITE):  return(&grey      ); break;
  +    default:      return(&white     ); break;
  +  }
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_repaint_background(TOPLEVEL *w_current)
  +{
  +  if (!w_current->inside_redraw) {
  +    gdk_gc_set_foreground(
  +                          w_current->gc,
  +                          x_get_color(w_current->background_color));
  +
  +    gdk_draw_rectangle(w_current->window,
  +                       w_current->gc, TRUE, 0, 0,
  +                       w_current->win_width,
  +                       w_current->win_height);
  +
  +    gdk_draw_rectangle(w_current->backingstore,
  +                       w_current->gc, TRUE, 0, 0,
  +                       w_current->win_width,
  +                       w_current->win_height);
  +
  +    x_grid_draw(w_current);
  +
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_hscrollbar_set_ranges(TOPLEVEL *w_current)
  +{
  +        GtkAdjustment        *hadjustment;
  +
  +	if (w_current->scrollbars_flag == FALSE) {
  +		return;
  +	}
  +
  +	hadjustment =
  +		gtk_range_get_adjustment(GTK_RANGE(w_current->h_scrollbar));
  +
  +	hadjustment->lower = w_current->init_left;
  +	hadjustment->upper = w_current->init_right;
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_hscrollbar_update(TOPLEVEL *w_current)
  +{
  +  GtkAdjustment *hadjustment;
  +
  +  if (w_current->scrollbars_flag == FALSE) {
  +    return;
  +  }
  +
  +  if (w_current->h_scrollbar == NULL) {
  +    return;
  +  }
  +
  +  hadjustment = gtk_range_get_adjustment (GTK_RANGE (
  +                                                     w_current->h_scrollbar));
  +
  +  hadjustment->value = w_current->page_current->left;
  +
  +  hadjustment->page_size = fabs(w_current->page_current->right -
  +                                w_current->page_current->left);
  +
  +  hadjustment->page_increment = hadjustment->page_size - 100.0;
  +
  +#if DEBUG
  +  printf("H %f %f\n", hadjustment->lower, hadjustment->upper);
  +  printf("Hp %f\n", hadjustment->page_size);
  +#endif
  +
  +  gtk_signal_emit_by_name(GTK_OBJECT(hadjustment), "changed");
  +  gtk_signal_emit_by_name(GTK_OBJECT(hadjustment), "value_changed");
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_vscrollbar_set_ranges(TOPLEVEL *w_current)
  +{
  +  GtkAdjustment *vadjustment;
  +
  +  if (w_current->scrollbars_flag == FALSE) {
  +    return;
  +  }
  +
  +  vadjustment =
  +  gtk_range_get_adjustment(GTK_RANGE(w_current->v_scrollbar));
  +
  +  vadjustment->lower = w_current->init_top;
  +  vadjustment->upper = w_current->init_bottom;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_vscrollbar_update(TOPLEVEL *w_current)
  +{
  +  GtkAdjustment *vadjustment;
  +
  +  if (w_current->scrollbars_flag == FALSE) {
  +    return;
  +  }
  +
  +  if (w_current->v_scrollbar == NULL) {
  +    return;
  +  }
  +
  +  vadjustment =
  +  gtk_range_get_adjustment(GTK_RANGE(w_current->v_scrollbar));
  +
  +  vadjustment->page_size = fabs(w_current->page_current->bottom -
  +                                w_current->page_current->top);
  +
  +  vadjustment->page_increment = vadjustment->page_size - 100.0;
  +
  +  vadjustment->value =
  +  w_current->init_bottom - w_current->page_current->bottom;
  +
  +#if DEBUG
  +  printf("V %f %f\n", vadjustment->lower, vadjustment->upper);
  +  printf("Vp %f\n", vadjustment->page_size);
  +#endif
  +
  +  gtk_signal_emit_by_name(GTK_OBJECT(vadjustment), "changed");
  +  gtk_signal_emit_by_name(GTK_OBJECT(vadjustment), "value_changed");
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_scrollbars_update(TOPLEVEL *w_current)
  +{
  +  if (w_current->scrollbars_flag == FALSE) {
  +    return;
  +  }
  +
  +  w_current->DONT_RECALC = 1;
  +  w_current->DONT_RESIZE = 1;
  +  w_current->DONT_REDRAW = 1;
  +  x_hscrollbar_update(w_current);
  +  x_vscrollbar_update(w_current);
  +  w_current->DONT_REDRAW = 0;
  +  w_current->DONT_RECALC = 0;
  +  w_current->DONT_RESIZE = 0;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +GtkWidget *x_create_dialog_box(GtkWidget **out_vbox,
  +			       GtkWidget **out_action_area)
  +{
  +  GtkWidget *separator;
  +  GtkWidget *vbox;
  +  GtkWidget *action_area;
  +  GtkWidget *dialog;
  +
  +  if (!out_vbox)
  +  return(NULL);
  +
  +  if (!out_action_area)
  +  return(NULL);
  +
  +  dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  +
  +  vbox = gtk_vbox_new (FALSE, 0);
  +  gtk_container_add (GTK_CONTAINER (dialog), vbox);
  +  gtk_widget_show (vbox);
  +
  +  action_area = gtk_hbox_new (TRUE, 5);
  +  gtk_container_set_border_width (GTK_CONTAINER (action_area), 10);
  +  gtk_box_pack_end (GTK_BOX (vbox), action_area, FALSE, TRUE, 0);
  +  gtk_widget_show (action_area);
  +
  +  separator = gtk_hseparator_new ();
  +  gtk_box_pack_end (GTK_BOX (vbox), separator, FALSE, TRUE, 0);
  +  gtk_widget_show (separator);
  +
  +  *out_vbox = vbox;
  +  *out_action_area = action_area;
  +
  +  return(dialog);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  not used
  + */
  +GtkWidget *x_create_dialog_box_horiz(GtkWidget **out_hbox,
  +				     GtkWidget **out_action_area)
  +{
  +  GtkWidget *separator;
  +  GtkWidget *vbox;
  +  GtkWidget *hbox;
  +  GtkWidget *action_area;
  +  GtkWidget *dialog;
  +
  +  if (!out_hbox)
  +  return(NULL);
  +
  +  if (!out_action_area)
  +  return(NULL);
  +
  +  dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  +
  +  vbox = gtk_vbox_new (FALSE, 0);
  +  gtk_container_add (GTK_CONTAINER (dialog), vbox);
  +  gtk_widget_show (vbox);
  +
  +  hbox = gtk_hbox_new (FALSE, 5);
  +  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
  +  gtk_widget_show (hbox);
  +
  +  separator = gtk_hseparator_new ();
  +  gtk_box_pack_end (GTK_BOX (vbox), separator, FALSE, TRUE, 0);
  +  gtk_widget_show (separator);
  +
  +  action_area = gtk_hbox_new (FALSE, 5);
  +  gtk_container_set_border_width (GTK_CONTAINER (action_area), 10);
  +  gtk_box_pack_end (GTK_BOX (vbox), action_area, FALSE, FALSE, 0);
  +  gtk_widget_show (action_area);
  +
  +  *out_hbox = hbox;
  +  *out_action_area = action_area;
  +
  +  return(dialog);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_basic_warp_cursor(GtkWidget* widget, gint x, gint y, gboolean relative)
  +{
  +#ifndef __MINGW32__
  +   XWarpPointer(GDK_WINDOW_XDISPLAY(widget->window), None, 
  +                GDK_WINDOW_XWINDOW(widget->window),0,0,0,0,x,y);
  +#endif
  +}
  
  
  
  1.8       +142 -116  eda/geda/gaf/gschem/src/x_color.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_color.c
  ===================================================================
  RCS file: x_color.c
  diff -N x_color.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_color.c	14 Jul 2006 02:23:55 -0000	1.8
  @@ -0,0 +1,187 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/x_event.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +COLOR colors[MAX_COLORS];
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Documentation
  + *
  + */
  +void x_color_allocate_all(void)
  +{
  +  int error;
  +  int i;		
  +
  +  for (i = 0; i < MAX_COLORS; i++) {
  +    if (colors[i].color_name) {
  +      colors[i].gtk_color = (GdkColor *) 
  +        malloc(sizeof(GdkColor));
  +
  +      error = gdk_color_parse(colors[i].color_name, 
  +                              colors[i].gtk_color);
  +
  +      if (error == FALSE) {
  +        fprintf(stderr, 
  +                _("Could not find the color %s!\n"), 
  +                colors[i].color_name);
  +        fprintf(stderr, 
  +                _("Defaulting color to white\n"));
  +
  +        error = gdk_color_parse("white", 
  +                                colors[i].gtk_color);
  +
  +        if (error == FALSE) {
  +          fprintf(stderr, 
  +                  _("Ack! Cannot allocate white!\n"));
  +          exit(-1);
  +        }
  +
  +      }
  +
  +
  +      error = gdk_color_alloc(colormap, colors[i].gtk_color);
  +
  +      if (error == FALSE) {
  +        fprintf(stderr, 
  +                _("Could not allocate the color %s!\n"), 
  +                colors[i].color_name);
  +        exit(-1);
  +      }
  +
  +    }
  +
  +    if (colors[i].outline_color_name) {
  +      colors[i].gtk_outline_color = (GdkColor *) 
  +        malloc(sizeof(GdkColor));
  +
  +      error = gdk_color_parse(colors[i].outline_color_name, 
  +                              colors[i].gtk_outline_color);
  +
  +      if (error == FALSE) {
  +        fprintf(stderr, 
  +                _("Could not find the color %s!\n"), 
  +                colors[i].outline_color_name);
  +        fprintf(stderr, 
  +                _("Defaulting color to white\n"));
  +
  +        error = gdk_color_parse("white", 
  +                                colors[i].gtk_outline_color);
  +
  +        if (error == FALSE) {
  +          fprintf(stderr, 
  +                  _("Ack! Cannot allocate white!\n"));
  +          exit(-1);
  +        }
  +
  +      }
  +
  +      /* Make sure the outline color is correct for non-black backgrounds */
  +      if (i > 0) {
  +	colors[i].gtk_outline_color->red = 
  +		colors[i].gtk_outline_color->red ^ colors[0].gtk_color->red;
  +	colors[i].gtk_outline_color->green =	
  +		 colors[i].gtk_outline_color->green ^ 
  +		 	colors[0].gtk_color->green;
  +	colors[i].gtk_outline_color->blue =	
  +		 colors[i].gtk_outline_color->blue ^ colors[0].gtk_color->blue;
  +      }
  +
  +      error = gdk_color_alloc(colormap, 
  +                              colors[i].gtk_outline_color);
  +
  +      if (error == FALSE) {
  +        fprintf(stderr, 
  +                _("Could not allocate the color %s!\n"), 
  +                colors[i].outline_color_name);
  +        exit(-1);
  +      }
  +
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Documentation
  + *
  + */
  +GdkColor *x_get_color(int color)
  +{
  +  if (colors[color].color_name) {
  +    return(colors[color].gtk_color);
  +  } else {
  +    fprintf(stderr, _("Tried to get an invalid color: %d\n"), color);
  +    return(&white);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Documentation
  + *
  + *  \todo this has to change... to the right code
  + */
  +GdkColor *x_get_darkcolor(int color)
  +{
  +  if (colors[color].outline_color_name) {
  +    return(colors[color].gtk_outline_color);
  +  } else {
  +    fprintf(stderr, _("Tried to get an invalid color: %d\n"), color);
  +    return(&white);
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Documentation
  + *
  + */
  +gchar *x_color_get_name(int index)
  +{
  +  if ((index >= MAX_COLORS) || (index < 0)) {
  +    return(NULL);
  +  }
  +
  +  /* only if these two variables are not null is the color settable */
  +  if (colors[index].color_name && colors[index].outline_color_name) {
  +    return (g_strdup(colors[index].color_name));
  +  }
  +
  +  /* didn't find a color, but there still might be more */
  +  return(NULL);
  +}
  
  
  
  1.56      +4351 -3276eda/geda/gaf/gschem/src/x_dialog.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_dialog.c
  ===================================================================
  RCS file: x_dialog.c
  diff -N x_dialog.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_dialog.c	14 Jul 2006 02:23:55 -0000	1.56
  @@ -0,0 +1,4594 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +/*! \todo STILL NEED to clean up line lengths in aa and tr */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/i_vars.h"
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +#include "../include/x_dialog.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define GLADE_HOOKUP_OBJECT(component,widget,name) \
  +  g_object_set_data_full (G_OBJECT (component), name, \
  +    gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
  +
  +static GtkWidget* create_menu_linetype (TOPLEVEL *w_current);
  +static gint line_type_dialog_linetype_change (GtkWidget *w, gpointer data);
  +static int line_type_dialog_keypress (GtkWidget * widget, GdkEventKey * event, gpointer data);
  +static void line_type_dialog_ok (GtkWidget *w, gpointer data);
  +static void line_type_dialog_cancel (GtkWidget *w, gpointer data);
  +
  +static GtkWidget* create_menu_filltype (TOPLEVEL *w_current);
  +static gint fill_type_dialog_filltype_change(GtkWidget *w, gpointer data);
  +static int fill_type_dialog_keypress(GtkWidget * widget, GdkEventKey * event, gpointer data);
  +static void fill_type_dialog_ok(GtkWidget *w, gpointer data);
  +static void fill_type_dialog_cancel(GtkWidget *w, gpointer data);
  +
  +struct line_type_data {
  +  GtkWidget *dialog;
  +  GtkWidget *width_entry;
  +  GtkWidget *line_type;
  +  GtkWidget *length_entry;
  +  GtkWidget *space_entry;
  +
  +  TOPLEVEL *toplevel;
  +  GList *objects;
  +};
  +
  +struct fill_type_data {
  +  GtkWidget *dialog;
  +  GtkWidget *fill_type;
  +  GtkWidget *width_entry;
  +  GtkWidget *angle1_entry;
  +  GtkWidget *pitch1_entry;
  +  GtkWidget *angle2_entry;
  +  GtkWidget *pitch2_entry;
  +
  +  TOPLEVEL *toplevel;
  +  GList *objects;
  +};
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void destroy_window(GtkWidget *widget, GtkWidget **window)
  +{
  +  *window = NULL;
  +}
  +
  +/***************** Start of Text Input dialog box *********************/
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int text_input_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			       TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	text_input_dialog_close(NULL, w_current);	
  + 	return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_input_dialog_apply(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  int len;
  +  char *string = NULL;
  +  GtkWidget *tientry;
  +#ifdef HAS_GTK22
  +  GtkTextBuffer *textbuffer;
  +  GtkTextIter start, end;
  +#endif
  +
  +  tientry = gtk_object_get_data(GTK_OBJECT(w_current->tiwindow),"tientry");
  +
  +#ifdef HAS_GTK22
  +  textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tientry));
  +  gtk_text_buffer_get_bounds (textbuffer, &start, &end);
  +  string =  gtk_text_iter_get_text (&start, &end);
  +#else
  +  string = gtk_entry_get_text(GTK_ENTRY(tientry));
  +#endif
  +
  +  if (string[0] != '\0' ) {
  +    len = strlen(string);
  +#if DEBUG
  +    printf("text was: _%s_ %d\n", string, len);
  +#endif
  +    switch(w_current->text_caps) {
  +      case(LOWER):
  +        string_tolower(string, string);
  +        break;
  +
  +      case(UPPER):
  +        string_toupper(string, string);
  +        break;
  +
  +      case(BOTH):
  +      default:
  +				/* do nothing */
  +        break;
  +    }
  +
  +    o_attrib_set_string(w_current, string);
  +    w_current->page_current->CHANGED=1;
  +#ifdef HAS_GTK22
  +    gtk_text_buffer_set_text(textbuffer, w_current->current_attribute, -1);
  +    select_all_text_in_textview(GTK_TEXT_VIEW(tientry));
  +#else
  +    gtk_entry_set_text(GTK_ENTRY(tientry),
  +                       w_current->current_attribute);
  +    gtk_entry_select_region(GTK_ENTRY(tientry),
  +                            0, len);
  +#endif
  +    gtk_widget_grab_focus(tientry);
  +
  +    w_current->event_state = DRAWTEXT;
  +    w_current->inside_action = 1;
  +  }
  +
  +#if 0
  +  gtk_grab_remove(w_current->tiwindow);
  +  gtk_widget_destroy(w_current->tiwindow);
  +  w_current->tiwindow = NULL;
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_input_dialog_close(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +#if 0
  +  gtk_grab_remove(w_current->tiwindow);
  +#endif
  +  gtk_widget_destroy(w_current->tiwindow);
  +  w_current->tiwindow=NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_input_dialog (TOPLEVEL *w_current)
  +{
  +  GtkWidget *label = NULL;
  +  GtkWidget *tientry = NULL;
  +  GtkWidget *buttonok     = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +#ifdef HAS_GTK22
  +  GtkWidget *viewport1 = NULL;
  +  GtkWidget *scrolled_window = NULL;
  +  PangoTabArray *tab_array;
  +  int real_tab_width;
  +#endif
  +
  +  if (!w_current->tiwindow) {
  +    w_current->tiwindow = x_create_dialog_box(&vbox, &action_area);
  +
  +#if 0
  +    gtk_window_position(GTK_WINDOW (w_current->tiwindow),
  +                        GTK_WIN_POS_MOUSE);
  +#endif
  +
  +    /*gtk_widget_set_usize(w_current->tiwindow, 400,130); no longer fixed size*/
  +
  +    gtk_window_position(GTK_WINDOW (w_current->tiwindow),
  +                        GTK_WIN_POS_NONE);
  +
  +    gtk_signal_connect(GTK_OBJECT (w_current->tiwindow),
  +                       "destroy", GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->tiwindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tiwindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) text_input_dialog_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT (w_current->tiwindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->tiwindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW (w_current->tiwindow),
  +                         _("Text Entry..."));
  +    gtk_container_border_width(
  +                               GTK_CONTAINER (w_current->tiwindow), 5);
  +
  +    label = gtk_label_new (_("Enter text, click apply,\nmove cursor into window, click to place text.\nMiddle button to rotate while placing."));
  +    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 5);
  +    gtk_widget_show (label);
  +
  +#ifdef HAS_GTK22
  +    viewport1 = gtk_viewport_new (NULL, NULL);
  +    gtk_widget_show (viewport1);
  +    
  +    scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  +    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
  +				   GTK_POLICY_AUTOMATIC, 
  +				   GTK_POLICY_AUTOMATIC);
  +    gtk_container_add (GTK_CONTAINER (viewport1), scrolled_window);
  +    gtk_box_pack_start( GTK_BOX(vbox), viewport1, TRUE, TRUE, 10);
  +    gtk_widget_show(scrolled_window);
  +
  +    tientry = gtk_text_view_new();
  +    gtk_text_view_set_editable(GTK_TEXT_VIEW(tientry), TRUE);
  +    select_all_text_in_textview(GTK_TEXT_VIEW(tientry));
  +
  +    /* Set the tab width, using pango tab array */
  +    /*! \bug FIXME: This doesn't work. Why? */
  +    tab_array = pango_tab_array_new (1, TRUE);
  +    real_tab_width = text_view_calculate_real_tab_width(GTK_TEXT_VIEW(tientry),
  +							tab_in_chars);
  +    if (real_tab_width >= 0) {
  +      pango_tab_array_set_tab (tab_array, 0, PANGO_TAB_LEFT, real_tab_width);
  +      /* printf("Real tab width: %i\n", real_tab_width);*/
  +      gtk_text_view_set_tabs (GTK_TEXT_VIEW (tientry), 
  +			      tab_array);
  +    }
  +    else {
  +      g_warning ("text_input_dialog: Impossible to set tab width.\n");
  +    }
  +    pango_tab_array_free (tab_array);
  +    gtk_container_add(GTK_CONTAINER(scrolled_window), tientry);
  +#else
  +    tientry = gtk_entry_new_with_max_length (79);
  +    gtk_editable_select_region(GTK_EDITABLE(tientry),
  +			       0, -1);
  +    gtk_signal_connect(GTK_OBJECT(tientry), "activate",
  +                       GTK_SIGNAL_FUNC(text_input_dialog_apply),
  +                       w_current);
  +    gtk_box_pack_start(GTK_BOX(vbox), tientry, TRUE, TRUE, 10);
  +#endif
  +
  +    gtk_widget_show(tientry);
  +    gtk_widget_grab_focus(tientry);
  +    gtk_object_set_data(GTK_OBJECT(w_current->tiwindow),
  +                        "tientry",tientry);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label(_("Apply"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_APPLY);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonok), "clicked",
  +                       GTK_SIGNAL_FUNC(text_input_dialog_apply),
  +                       w_current);
  +    gtk_widget_show (buttonok);
  +    gtk_widget_grab_default (buttonok);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Close"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttoncancel, TRUE, TRUE, 0);
  +    gtk_signal_connect (GTK_OBJECT (buttoncancel), "clicked",
  +                        GTK_SIGNAL_FUNC(text_input_dialog_close),
  +                        w_current);
  +    gtk_widget_show (buttoncancel);
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->tiwindow)) {
  +    gtk_widget_show (w_current->tiwindow);
  +#if 0
  +    gtk_grab_add (w_current->tiwindow);
  +#endif
  +  } else {
  +    gdk_window_raise(w_current->tiwindow->window);
  +  }
  +}
  +
  +/***************** End of Text Input dialog box ***********************/
  +
  +/***************** Start of Text Edit dialog box **********************/
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint change_alignment(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  char *alignment;
  +  alignment = gtk_object_get_data(GTK_OBJECT(w),"alignment");
  +  w_current->text_alignment = atoi(alignment);
  +
  +  /*w_current->page_current->CHANGED=1; I don't think this belongs */
  +  /* o_undo_savestate(w_current, UNDO_ALL); I don't think this belongs */
  +	
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static GtkWidget *create_menu_alignment (TOPLEVEL *w_current)
  +{
  +  GtkWidget *menu;
  +  GtkWidget *menuitem;
  +  GSList *group;
  +  char *buf;
  +
  +  menu = gtk_menu_new ();
  +  group = NULL;
  +
  +  buf = g_strdup_printf( _("Lower Left"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "0");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf( _("Middle Left"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "1");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf( _("Upper Left"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "2");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf( _("Lower Middle"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "3");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf( _("Middle Middle"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "4");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf( _("Upper Middle"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "5");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf( _("Lower Right"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "6");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf( _("Middle Right"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "7");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf( _("Upper Right"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_object_set_data (GTK_OBJECT(menuitem), "alignment", "8");
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) change_alignment,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  return(menu);
  +}
  +
  +/* we reuse the color menu so we need to declare it */
  +static GtkWidget *create_color_menu(TOPLEVEL * w_current, int * select_index);
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int text_edit_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			      TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	text_edit_dialog_cancel(NULL, w_current);	
  + 	return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_edit_dialog_ok(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  int len=0;
  +  int text_size=8;
  +  char *text_string = NULL;
  +  char *text_size_string = NULL;
  +  int new_text_alignment;
  +  int num_selected;
  +#ifdef HAS_GTK22
  +  GtkTextBuffer *textbuffer;
  +  GtkTextIter start, end;
  +#endif
  +
  +  num_selected = o_selection_return_num(w_current->page_current->selection2_head);
  +
  +  /* text string entry will only show up if one object is selected */
  +  if (num_selected == 1) {
  +#ifdef HAS_GTK22
  +    textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w_current->teentry));
  +    gtk_text_buffer_get_bounds (textbuffer, &start, &end);
  +    text_string =  gtk_text_iter_get_text (&start, &end);
  +#else
  +    text_string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->teentry));
  +#endif
  +  } /* else the string will be null which is okay */
  +  
  +  text_size_string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->tsentry));
  +
  +  if (text_string) {
  +    len = strlen(text_string);
  +  }
  +
  +  if (text_size_string) {
  +    text_size = atoi(text_size_string);
  +  }
  +  
  +  if (text_size == 0) {
  +    text_size = default_text_size;
  +  }
  +
  +  new_text_alignment = w_current->text_alignment;
  +
  +  o_text_edit_end(w_current, text_string, len, text_size, new_text_alignment);
  +
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +
  +  gtk_grab_remove(w_current->tewindow);
  +  gtk_widget_destroy(w_current->tewindow);
  +  w_current->tewindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_edit_dialog_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +  gtk_grab_remove(w_current->tewindow);
  +  gtk_widget_destroy(w_current->tewindow);
  +  w_current->tewindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_edit_dialog (TOPLEVEL *w_current, char *string, int text_size,
  +		       int text_alignment)
  +{
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok     = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +  GtkWidget *optionmenu = NULL;
  +  GtkWidget *align_menu = NULL;
  +#ifdef HAS_GTK22
  +  GtkWidget *viewport1 = NULL;
  +  GtkWidget *scrolled_window = NULL;
  +  GtkTextBuffer *textbuffer;
  +#endif
  +  char *text_size_string;
  +  int len;
  +  int num_selected;
  +  int select_index=0;
  +
  +  num_selected = o_selection_return_num(w_current->page_current->selection2_head);
  +  
  +  if (!w_current->tewindow) {
  +    w_current->tewindow = x_create_dialog_box(&vbox, &action_area);
  +    
  +    gtk_window_set_default_size (GTK_WINDOW (w_current->tewindow), 250, 300);
  +
  +    gtk_window_position(GTK_WINDOW (w_current->tewindow),
  +                        GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT (w_current->tewindow),
  +                       "destroy",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->tewindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tewindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) text_edit_dialog_keypress, w_current);
  +
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT (w_current->tewindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(gtk_widget_destroyed),
  +                       &w_current->tewindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW (w_current->tewindow),
  +                         _("Edit Text"));
  +    gtk_container_border_width(
  +                               GTK_CONTAINER(w_current->tewindow), 10);
  +
  +    if (num_selected == 1) {
  +      label = gtk_label_new (_("Edit Text"));
  +      gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
  +      gtk_widget_show (label);
  +
  +#ifdef HAS_GTK22
  +      viewport1 = gtk_viewport_new (NULL, NULL);
  +      gtk_widget_show (viewport1);
  +
  +      scrolled_window = gtk_scrolled_window_new(NULL, NULL);
  +      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
  +				     GTK_POLICY_AUTOMATIC, 
  +				     GTK_POLICY_AUTOMATIC);
  +      gtk_container_add (GTK_CONTAINER (viewport1), scrolled_window);
  +      gtk_box_pack_start( GTK_BOX(vbox), viewport1, TRUE, TRUE, 10);
  +      gtk_widget_show(scrolled_window);
  +      
  +      w_current->teentry = gtk_text_view_new();
  +      gtk_text_view_set_editable(GTK_TEXT_VIEW(w_current->teentry), TRUE);
  +      select_all_text_in_textview(GTK_TEXT_VIEW(w_current->teentry));
  +
  +      /*! \bug FIXME: Set tab's width in the textview widget. */
  +      /* See first the code in text_input_dialog and get it working before adding it here. */
  +
  +      gtk_container_add(GTK_CONTAINER(scrolled_window), w_current->teentry);
  +#else
  +      w_current->teentry = gtk_entry_new();
  +      gtk_editable_select_region(GTK_EDITABLE(w_current->teentry), 0, -1);
  +      gtk_signal_connect(GTK_OBJECT(w_current->teentry), "activate",
  +                         GTK_SIGNAL_FUNC(text_edit_dialog_ok),
  +                         w_current);
  +      gtk_box_pack_start(GTK_BOX(vbox), w_current->teentry, TRUE, TRUE, 10);
  +#endif
  +
  +      gtk_widget_show (w_current->teentry);
  +      gtk_widget_grab_focus(w_current->teentry);
  +    }
  +
  +    label = gtk_label_new(_("Edit Text Color"));
  +    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
  +    gtk_widget_show(label);
  +    
  +    optionmenu = gtk_option_menu_new();
  +    
  +    gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu), create_color_menu(w_current, &select_index));
  +    gtk_option_menu_set_history(GTK_OPTION_MENU(optionmenu), select_index);
  +	
  +    gtk_box_pack_start(GTK_BOX(vbox), optionmenu, FALSE, TRUE, 5);
  +    gtk_widget_show(optionmenu);
  +
  +    label = gtk_label_new (_("Edit Text Size"));
  +    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
  +    gtk_widget_show (label);
  +
  +    w_current->tsentry = gtk_entry_new_with_max_length (10);
  +    gtk_editable_select_region(
  +                               GTK_EDITABLE (w_current->tsentry), 0, -1);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       w_current->tsentry, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->tsentry), "activate",
  +                       GTK_SIGNAL_FUNC(text_edit_dialog_ok),
  +                       w_current);
  +    gtk_widget_show (w_current->tsentry);
  +
  +		
  +    label = gtk_label_new (_("Edit Text Alignment"));
  +    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 5);
  +    gtk_widget_show (label);
  +
  +    optionmenu = gtk_option_menu_new ();
  +    align_menu = create_menu_alignment (w_current);
  +    gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),
  +                             align_menu);
  +    gtk_option_menu_set_history(GTK_OPTION_MENU (optionmenu), 
  +                                text_alignment);
  +    w_current->text_alignment = text_alignment;
  +    gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gtk_menu_get_active(GTK_MENU(align_menu))),
  +				   TRUE);
  +
  +    gtk_box_pack_start(GTK_BOX(vbox), optionmenu, FALSE, TRUE, 0);
  +    gtk_widget_show(optionmenu);
  +
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label (_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonok, TRUE, TRUE, 5);
  +    gtk_signal_connect(GTK_OBJECT (buttonok), "clicked",
  +                       GTK_SIGNAL_FUNC(text_edit_dialog_ok),
  +                       w_current);
  +    gtk_widget_show(buttonok);
  +    gtk_widget_grab_default(buttonok);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +    GTK_WIDGET_SET_FLAGS(buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttoncancel, TRUE, TRUE, 5);
  +    gtk_signal_connect(GTK_OBJECT (buttoncancel), "clicked",
  +                       GTK_SIGNAL_FUNC(text_edit_dialog_cancel),
  +                       w_current);
  +    gtk_widget_show(buttoncancel);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->tewindow)) {
  +    gtk_widget_show (w_current->tewindow);
  +    if (string != NULL) {
  +      len = strlen(string);
  +      if (num_selected == 1) { /* only if one thing is selected */
  +#ifdef HAS_GTK22
  +	textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w_current->teentry));
  +	gtk_text_buffer_set_text(GTK_TEXT_BUFFER(textbuffer), string, -1);
  +	select_all_text_in_textview(GTK_TEXT_VIEW(w_current->teentry));
  +#else
  +        gtk_entry_set_text(GTK_ENTRY(w_current->teentry),
  +			   string);
  +	gtk_entry_select_region(GTK_ENTRY(w_current->teentry),
  +				0, len);
  +#endif
  +      }
  +    }
  +
  +    text_size_string = g_strdup_printf("%d", text_size);
  +    gtk_entry_set_text(GTK_ENTRY(w_current->tsentry),
  +                       text_size_string);
  +    free(text_size_string);
  +
  +    gtk_grab_add (w_current->tewindow);
  +  }
  +}
  +
  +/***************** End of Text Edit dialog box ************************/
  +
  +/***************** Start of Line Type/width dialog box ****************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static GtkWidget *create_menu_linetype (TOPLEVEL *w_current)
  +{
  +  GtkWidget *menu;
  +  GSList *group;
  +  struct line_type {
  +    gchar *str;
  +    OBJECT_TYPE type;
  +  } types[] = { { N_("Solid"),   TYPE_SOLID },
  +                { N_("Dotted"),  TYPE_DOTTED },
  +                { N_("Dashed"),  TYPE_DASHED },
  +                { N_("Center"),  TYPE_CENTER },
  +                { N_("Phantom"), TYPE_PHANTOM } };
  +  gint i;
  +
  +  menu  = gtk_menu_new ();
  +  group = NULL;
  +  
  +  for (i = 0; i < sizeof (types) / sizeof (struct line_type); i++) {
  +    GtkWidget *menuitem;
  +      
  +    menuitem = gtk_radio_menu_item_new_with_label (group, _(types[i].str));
  +    group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +    gtk_menu_append (GTK_MENU (menu), menuitem);
  +    gtk_object_set_data (GTK_OBJECT(menuitem), "linetype",
  +                         GINT_TO_POINTER (types[i].type));
  +    gtk_widget_show (menuitem);
  +  }
  +
  +  return(menu);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static gint line_type_dialog_linetype_change(GtkWidget *w, gpointer data)
  +{
  +  struct line_type_data *line_type_data = (struct line_type_data*) data;
  +  GtkWidget *menuitem;
  +  gboolean activate_length_entry, activate_space_entry;
  +  gint type;
  +
  +  menuitem = gtk_menu_get_active (
  +    GTK_MENU (gtk_option_menu_get_menu (
  +                GTK_OPTION_MENU (line_type_data->line_type))));
  +
  +  type = GPOINTER_TO_INT(
  +    gtk_object_get_data (GTK_OBJECT (menuitem), "linetype"));
  +  switch(type) {
  +      case(TYPE_SOLID):
  +        activate_length_entry = FALSE;
  +        activate_space_entry  = FALSE;
  +        break;
  +      case(TYPE_DOTTED):
  +        activate_length_entry = FALSE;
  +        activate_space_entry  = TRUE;
  +        break;
  +      case(TYPE_DASHED):
  +      case(TYPE_CENTER):
  +      case(TYPE_PHANTOM):
  +        activate_length_entry = TRUE;
  +        activate_space_entry  = TRUE;
  +        break;
  +      default:
  +        activate_length_entry = TRUE;
  +        activate_space_entry  = TRUE;
  +  }
  +
  +  gtk_widget_set_sensitive (line_type_data->space_entry,
  +                            activate_space_entry);
  +  gtk_widget_set_sensitive (line_type_data->length_entry,
  +                            activate_length_entry);
  +    
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static int line_type_dialog_keypress(GtkWidget *widget, GdkEventKey *event, 
  +				     gpointer data)
  +{
  +  struct line_type_data *line_type_data = (struct line_type_data*)data;
  +    
  +  if (strcmp (gdk_keyval_name (event->keyval), "Escape") == 0) {
  +    line_type_dialog_cancel (NULL, (gpointer) line_type_data);
  +    return TRUE;
  +  }
  +
  +  return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void line_type_dialog_ok(GtkWidget *w, gpointer data)
  +{
  +  struct line_type_data *line_type_data = (struct line_type_data*)data;
  +  TOPLEVEL *toplevel;
  +  GList *objects;
  +  const gchar *width_str, *length_str, *space_str;
  +  OBJECT_TYPE type;
  +    
  +  /* retrieve the list of objects and the toplevel */
  +  objects  = line_type_data->objects;
  +  toplevel = line_type_data->toplevel;
  +    
  +  /* get the new values from the text entries of the dialog */
  +  width_str   = gtk_entry_get_text (GTK_ENTRY (
  +                                      line_type_data->width_entry));
  +  length_str  = gtk_entry_get_text (GTK_ENTRY (
  +                                      line_type_data->length_entry));
  +  space_str   = gtk_entry_get_text (GTK_ENTRY (
  +                                      line_type_data->space_entry));
  +  type = GPOINTER_TO_INT(
  +    gtk_object_get_data (
  +      GTK_OBJECT (
  +        gtk_menu_get_active (
  +          GTK_MENU (gtk_option_menu_get_menu (
  +                      GTK_OPTION_MENU (
  +                        line_type_data->line_type))))), "linetype"));
  +    
  +  /* are there several objects concerned? */
  +  if (g_list_next (objects) == NULL) {
  +    /* no, there is only one object */
  +    OBJECT *o_current = (OBJECT*) objects->data;
  +    gint width, length, space;
  +        
  +    width  = atoi (width_str);
  +    length = atoi (length_str);
  +    space  = atoi (space_str);
  +
  +    /* apply the new line options to object */
  +    o_erase_single (toplevel, o_current);
  +    o_set_line_options (toplevel, o_current,
  +                        o_current->line_end, 
  +                        type,
  +                        width,
  +                        length,
  +                        space);
  +    o_object_recalc (toplevel, o_current);
  +    o_redraw_single (toplevel, o_current);
  +      
  +  } else {
  +    /* more than one object in the list */
  +    GList *object;
  +    gint width, length, space;
  +
  +    /* get the new line options */
  +    width  = g_strcasecmp (width_str,
  +                           _("*unchanged*")) ? atoi (width_str)  : -1;
  +    length = g_strcasecmp (length_str,
  +                           _("*unchanged*")) ? atoi (length_str) : -1;
  +    space  = g_strcasecmp (space_str,
  +                           _("*unchanged*")) ? atoi (space_str)  : -1;
  +
  +    /* apply changes to each object */
  +    object = objects;
  +    while (object != NULL) {
  +      OBJECT *o_current = (OBJECT*)object->data;
  +
  +      o_erase_single (toplevel, o_current);
  +      o_set_line_options (toplevel, o_current,
  +                          o_current->line_end, 
  +                          type   == -1 ? o_current->line_type : type,
  +                          width  == -1 ? o_current->line_width  : width,
  +                          length == -1 ? o_current->line_length : length,
  +                          space  == -1 ? o_current->line_space  : space);
  +      o_object_recalc (toplevel, o_current);
  +      o_redraw_single (toplevel, o_current);
  +          
  +      object = object->next;
  +    }
  +  }
  +
  +  /* get ride of the list of objects but not the objects */
  +  g_list_free (objects);
  +  line_type_data->objects = NULL;
  +    
  +  toplevel->page_current->CHANGED = 1;
  +  i_set_state (toplevel, SELECT);
  +  i_update_toolbar (toplevel);
  +    
  +  gtk_grab_remove (line_type_data->dialog);
  +  gtk_widget_destroy (line_type_data->dialog);
  +    
  +  g_free (line_type_data);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void line_type_dialog_cancel(GtkWidget *w, gpointer data)
  +{
  +  struct line_type_data *line_type_data = (struct line_type_data*)data;
  +  TOPLEVEL *toplevel = line_type_data->toplevel;
  +    
  +  /* free the list of selected objects */
  +  g_list_free (line_type_data->objects);
  +    
  +  i_set_state (toplevel, SELECT);
  +  i_update_toolbar (toplevel);
  +    
  +  gtk_grab_remove (line_type_data->dialog);
  +  gtk_widget_destroy (line_type_data->dialog);
  +
  +  g_free (line_type_data);
  +    
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void line_type_dialog (TOPLEVEL *w_current, GList *objects)
  +{
  +  GtkWidget *dialog;
  +  GtkWidget *buttonok     = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +  GtkWidget *optionmenu   = NULL;
  +  GtkWidget *length_entry = NULL;
  +  GtkWidget *space_entry  = NULL;
  +  GtkWidget *width_entry  = NULL;
  +  struct line_type_data *line_type_data;
  +  gchar *width_str, *space_str, *length_str;
  +  gint type;
  +
  +  line_type_data = (struct line_type_data*) malloc (
  +    sizeof (struct line_type_data));
  +
  +  dialog = x_create_dialog_box(&vbox, &action_area);
  +
  +  gtk_window_position(GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
  +  
  +  gtk_signal_connect(GTK_OBJECT (dialog),
  +                     "destroy",
  +                     GTK_SIGNAL_FUNC(destroy_window),
  +                     &dialog);
  +  gtk_signal_connect (GTK_OBJECT (dialog),
  +                      "key_press_event",
  +                      (GtkSignalFunc) line_type_dialog_keypress,
  +                      line_type_data);
  +
  +  gtk_window_set_title(GTK_WINDOW (dialog), _("Edit Line Width & Type"));
  +  gtk_container_border_width(GTK_CONTAINER(dialog), 10);
  +
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      gtk_label_new (_("Line Width")),
  +                      TRUE, TRUE, 0);
  +
  +  width_entry = gtk_entry_new();
  +  /*    gtk_editable_select_region(
  +        GTK_EDITABLE(width_entry), 0, -1); */
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      width_entry,
  +                      TRUE, TRUE, 10);
  +  gtk_signal_connect(GTK_OBJECT(width_entry), "activate",
  +                     GTK_SIGNAL_FUNC(line_type_dialog_ok),
  +                     line_type_data);
  +  
  +  gtk_box_pack_start(GTK_BOX(vbox),
  +                     gtk_label_new (_("Line Type")),
  +                     TRUE, TRUE, 5);
  +
  +  optionmenu = gtk_option_menu_new ();
  +  gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),
  +                           create_menu_linetype (w_current));
  +  gtk_box_pack_start(GTK_BOX(vbox),
  +                     optionmenu,
  +                     TRUE, TRUE, 0);
  +  gtk_signal_connect(GTK_OBJECT (optionmenu), "changed",
  +                     (GtkSignalFunc) line_type_dialog_linetype_change,
  +                     line_type_data);
  +  
  +  gtk_box_pack_start(GTK_BOX(vbox),
  +                     gtk_label_new (_("Line Dash Length")),
  +                     TRUE, TRUE, 5);
  +  
  +  length_entry = gtk_entry_new();
  +  gtk_editable_select_region(GTK_EDITABLE(length_entry), 0, -1);
  +  gtk_box_pack_start(GTK_BOX(vbox),
  +                     length_entry,
  +                     TRUE, TRUE, 10);
  +
  +  gtk_box_pack_start(GTK_BOX(vbox),
  +                     gtk_label_new (_("Line Dash Space")),
  +                     TRUE, TRUE, 5);
  +  
  +  space_entry = gtk_entry_new();
  +  gtk_editable_select_region(GTK_EDITABLE(space_entry), 0, -1);
  +  gtk_box_pack_start(GTK_BOX(vbox),
  +                     space_entry,
  +                     TRUE, TRUE, 10);
  +
  +#ifdef HAS_GTK12
  +  buttonok = gtk_button_new_with_label (_("OK"));
  +#else
  +  buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +  GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +  gtk_box_pack_start(GTK_BOX(action_area),
  +                     buttonok,
  +                     TRUE, TRUE, 0);
  +  gtk_signal_connect(GTK_OBJECT (buttonok), "clicked",
  +                     GTK_SIGNAL_FUNC(line_type_dialog_ok),
  +                     line_type_data);
  +  gtk_widget_grab_default(buttonok);
  +
  +#ifdef HAS_GTK12
  +  buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +  buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +  GTK_WIDGET_SET_FLAGS(buttoncancel, GTK_CAN_DEFAULT);
  +  gtk_box_pack_start(GTK_BOX(action_area),
  +                     buttoncancel,
  +                     TRUE, TRUE, 0);
  +  gtk_signal_connect(GTK_OBJECT (buttoncancel), "clicked",
  +                     GTK_SIGNAL_FUNC(line_type_dialog_cancel),
  +                     line_type_data);
  +
  +  /* populate the data structure */
  +  line_type_data->dialog = dialog;
  +  line_type_data->width_entry  = width_entry;
  +  line_type_data->line_type    = optionmenu;
  +  line_type_data->length_entry = length_entry;
  +  line_type_data->space_entry  = space_entry;
  +  
  +  line_type_data->toplevel = w_current;
  +  line_type_data->objects  = objects;
  +
  +  /* fill in the fields of the dialog */
  +  if (g_list_next (objects) == NULL) {
  +    /* only one object in object list */
  +    OBJECT *o_current = (OBJECT*) objects->data;
  +      
  +    width_str  = g_strdup_printf ("%d", o_current->line_width);
  +    space_str  = g_strdup_printf ("%d", o_current->line_space);
  +    length_str = g_strdup_printf ("%d", o_current->line_length);
  +    type = o_current->line_type;
  +  } else {
  +    GtkWidget *menuitem;
  +    GtkWidget *menu;
  +      
  +    width_str   = g_strdup_printf (_("*unchanged*"));
  +    space_str   = g_strdup_printf (_("*unchanged*"));
  +    length_str  = g_strdup_printf (_("*unchanged*"));
  +    type = TYPE_PHANTOM + 1;
  +      
  +    /* add a new menuitem to option menu for line type */
  +    menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (optionmenu));
  +    menuitem = gtk_radio_menu_item_new_with_label (
  +      gtk_radio_menu_item_get_group (
  +        GTK_RADIO_MENU_ITEM (gtk_menu_get_active (GTK_MENU (menu)))),
  +      _("*unchanged*"));
  +    gtk_menu_append (menu, menuitem);
  +    gtk_object_set_data (GTK_OBJECT (menuitem),
  +                         "linetype",
  +                         GINT_TO_POINTER (-1));
  +    gtk_widget_show (menuitem);
  +  }
  +  
  +  gtk_entry_set_text (GTK_ENTRY (width_entry), width_str);
  +  gtk_entry_select_region (GTK_ENTRY (width_entry), 0, strlen (width_str));
  +  gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), type);
  +  gtk_entry_set_text (GTK_ENTRY (space_entry), space_str);
  +  gtk_entry_set_text (GTK_ENTRY (length_entry), length_str);
  +  
  +  gtk_widget_grab_focus(width_entry);
  +  gtk_grab_add (dialog);
  +  
  +  g_free (width_str);
  +  g_free (space_str);
  +  g_free (length_str);
  +  
  +  gtk_widget_show_all (dialog);
  +  
  +}
  +
  +/***************** End of Line Type / Width dialog box ****************/
  +
  +/***************** Start of Fill Type dialog box **********************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static GtkWidget *create_menu_filltype (TOPLEVEL *w_current)
  +{
  +  GtkWidget *menu;
  +  GSList *group;
  +  struct fill_type {
  +    gchar *str;
  +    OBJECT_FILLING type;
  +  } types[] = { { N_("Hollow"), FILLING_HOLLOW },
  +                { N_("Filled"), FILLING_FILL },
  +                { N_("Mesh"),   FILLING_MESH },
  +                { N_("Hatch"),  FILLING_HATCH } };
  +  gint i;
  +
  +  menu  = gtk_menu_new ();
  +  group = NULL;
  +
  +  for (i = 0; i < sizeof (types) / sizeof (struct fill_type); i++) {
  +    GtkWidget *menuitem;
  +      
  +    menuitem = gtk_radio_menu_item_new_with_label (group, _(types[i].str));
  +    group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +    gtk_menu_append (GTK_MENU (menu), menuitem);
  +    gtk_object_set_data (GTK_OBJECT(menuitem), "filltype",
  +                         GINT_TO_POINTER (types[i].type));
  +    gtk_widget_show (menuitem);
  +  }
  +
  +  return menu;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static gint fill_type_dialog_filltype_change(GtkWidget *w, gpointer data)
  +{
  +  struct fill_type_data *fill_type_data = (struct fill_type_data*) data;
  +  GtkWidget *menuitem;
  +  gboolean activate_width_entry;
  +  gboolean activate_anglepitch1_entries;
  +  gboolean activate_anglepitch2_entries;
  +  gint type;
  +
  +  menuitem = gtk_menu_get_active (
  +    GTK_MENU (gtk_option_menu_get_menu (
  +                GTK_OPTION_MENU (fill_type_data->fill_type))));
  +
  +  type = GPOINTER_TO_INT(
  +    gtk_object_get_data (GTK_OBJECT (menuitem), "filltype"));
  +  switch(type) {
  +      case(FILLING_HOLLOW):
  +      case(FILLING_FILL):
  +        activate_width_entry = FALSE;
  +        activate_anglepitch1_entries = FALSE;
  +        activate_anglepitch2_entries = FALSE;
  +        break;
  +      case(FILLING_HATCH):
  +        activate_width_entry = TRUE;
  +        activate_anglepitch1_entries = TRUE;
  +        activate_anglepitch2_entries = FALSE;
  +        break;
  +      case(FILLING_MESH):
  +        activate_width_entry = TRUE;
  +        activate_anglepitch1_entries = TRUE;
  +        activate_anglepitch2_entries = TRUE;
  +        break;
  +      default:
  +        activate_width_entry = TRUE;
  +        activate_anglepitch1_entries = TRUE;
  +        activate_anglepitch2_entries = TRUE;
  +  }
  +
  +  gtk_widget_set_sensitive (fill_type_data->width_entry,
  +                            activate_width_entry);
  +  gtk_widget_set_sensitive (fill_type_data->angle1_entry,
  +                            activate_anglepitch1_entries);
  +  gtk_widget_set_sensitive (fill_type_data->pitch1_entry,
  +                            activate_anglepitch1_entries);
  +  gtk_widget_set_sensitive (fill_type_data->angle2_entry,
  +                            activate_anglepitch2_entries);
  +  gtk_widget_set_sensitive (fill_type_data->pitch2_entry,
  +                            activate_anglepitch2_entries);
  +    
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static int fill_type_dialog_keypress(GtkWidget * widget, GdkEventKey * event,
  +				     gpointer data)
  +{
  +  struct fill_type_data *fill_type_data = (struct fill_type_data*)data;
  +
  +  if (strcmp (gdk_keyval_name (event->keyval), "Escape") == 0) {
  +    fill_type_dialog_cancel (NULL, (gpointer) fill_type_data);
  +    return TRUE;
  +  }
  +
  +  return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void fill_type_dialog_ok(GtkWidget *w, gpointer data)
  +{
  +  struct fill_type_data *fill_type_data = (struct fill_type_data*)data;
  +  TOPLEVEL *toplevel;
  +  GList *objects;
  +  const gchar *width_str, *angle1_str, *pitch1_str, *angle2_str, *pitch2_str;
  +  OBJECT_FILLING type;
  +  
  +  /* retrieve the list of objects and the toplevel */
  +  objects  = fill_type_data->objects;
  +  toplevel = fill_type_data->toplevel;
  +
  +  /* get the new values from the text entries of the dialog */
  +  width_str  = gtk_entry_get_text (GTK_ENTRY (
  +                                     fill_type_data->width_entry));
  +  angle1_str = gtk_entry_get_text (GTK_ENTRY (
  +                                     fill_type_data->angle1_entry));
  +  pitch1_str = gtk_entry_get_text (GTK_ENTRY (
  +                                     fill_type_data->pitch1_entry));
  +  angle2_str = gtk_entry_get_text (GTK_ENTRY (
  +                                     fill_type_data->angle2_entry));
  +  pitch2_str = gtk_entry_get_text (GTK_ENTRY (
  +                                     fill_type_data->pitch2_entry));
  +  type = GPOINTER_TO_INT(
  +    gtk_object_get_data (
  +      GTK_OBJECT (
  +        gtk_menu_get_active (
  +          GTK_MENU (gtk_option_menu_get_menu (
  +                      GTK_OPTION_MENU (
  +                        fill_type_data->fill_type))))), "filltype"));
  +
  +  /* are there several objects concerned? */
  +  if (g_list_next (objects) == NULL) {
  +    /* no, there is only one object */
  +    OBJECT *o_current = (OBJECT*) objects->data;
  +    gint width, angle1, pitch1, angle2, pitch2;
  +        
  +    width  = atoi (width_str);
  +    angle1 = atoi (angle1_str);
  +    pitch1 = atoi (pitch1_str);
  +    angle2 = atoi (angle2_str);
  +    pitch2 = atoi (pitch2_str);
  +
  +    /* apply the new line options to object */
  +    o_erase_single (toplevel, o_current);
  +    o_set_fill_options(toplevel, o_current,
  +                       type, width,
  +                       pitch1, angle1,
  +                       pitch2, angle2);
  +    o_object_recalc (toplevel, o_current);
  +    o_redraw_single (toplevel, o_current);
  +      
  +  } else {
  +    /* more than one object in the list */
  +    GList *object;
  +    gint width, angle1, pitch1, angle2, pitch2;
  +
  +    /* get the new line options */
  +    width  = g_strcasecmp (width_str,
  +                           _("*unchanged*")) ? atoi (width_str)  : -1;
  +    angle1 = g_strcasecmp (angle1_str,
  +                           _("*unchanged*")) ? atoi (angle1_str) : -1;
  +    pitch1 = g_strcasecmp (pitch1_str,
  +                           _("*unchanged*")) ? atoi (pitch1_str) : -1;
  +    angle2 = g_strcasecmp (angle2_str,
  +                           _("*unchanged*")) ? atoi (angle2_str) : -1;
  +    pitch2 = g_strcasecmp (pitch2_str,
  +                           _("*unchanged*")) ? atoi (pitch2_str) : -1;
  +
  +    /* apply changes to each object */
  +    object = objects;
  +    while (object != NULL) {
  +      OBJECT *o_current = (OBJECT*)object->data;
  +
  +      o_erase_single (toplevel, o_current);
  +      o_set_fill_options (toplevel, o_current,
  +                          type   == -1 ? o_current->fill_type   : type,
  +                          width  == -1 ? o_current->fill_width  : width,
  +                          pitch1 == -1 ? o_current->fill_pitch1 : pitch1,
  +                          angle1 == -1 ? o_current->fill_angle1 : angle1,
  +                          pitch2 == -1 ? o_current->fill_pitch2 : pitch2,
  +                          angle2 == -1 ? o_current->fill_angle2 : angle2);
  +      o_object_recalc (toplevel, o_current);
  +      o_redraw_single (toplevel, o_current);
  +          
  +      object = object->next;
  +    }
  +  }
  +
  +  /* get ride of the list of objects but not the objects */
  +  g_list_free (objects);
  +  fill_type_data->objects = NULL;
  +    
  +  toplevel->page_current->CHANGED = 1;
  +  i_set_state (toplevel, SELECT);
  +  i_update_toolbar (toplevel);
  +    
  +  gtk_grab_remove (fill_type_data->dialog);
  +  gtk_widget_destroy (fill_type_data->dialog);
  +    
  +  g_free (fill_type_data);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void fill_type_dialog_cancel(GtkWidget *w, gpointer data)
  +{
  +  struct fill_type_data *fill_type_data = (struct fill_type_data*)data;
  +  TOPLEVEL *toplevel = fill_type_data->toplevel;
  +
  +  /* free the list of selected objects */
  +  g_list_free (fill_type_data->objects);
  +  
  +  i_set_state (toplevel, SELECT);
  +  i_update_toolbar (toplevel);
  +  
  +  gtk_grab_remove (fill_type_data->dialog);
  +  gtk_widget_destroy (fill_type_data->dialog);
  +
  +  g_free (fill_type_data);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void fill_type_dialog(TOPLEVEL *w_current, GList *objects)
  +{
  +  GtkWidget *dialog;
  +  GtkWidget *buttonok     = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +  GtkWidget *optionmenu = NULL;
  +  GtkWidget *width_entry = NULL;
  +  GtkWidget *angle1_entry = NULL;
  +  GtkWidget *pitch1_entry = NULL;
  +  GtkWidget *angle2_entry = NULL;
  +  GtkWidget *pitch2_entry = NULL;
  +  struct fill_type_data *fill_type_data;
  +  gchar *width_str, *angle1_str, *pitch1_str, *angle2_str, *pitch2_str;
  +  gint type;
  +
  +  fill_type_data = (struct fill_type_data*) malloc (
  +    sizeof (struct fill_type_data));
  +
  +  dialog = x_create_dialog_box (&vbox, &action_area);
  +
  +  gtk_window_position(GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
  +  
  +  gtk_signal_connect(GTK_OBJECT (dialog),
  +                     "destroy",
  +                     GTK_SIGNAL_FUNC(destroy_window),
  +                     &dialog);
  +  gtk_signal_connect (GTK_OBJECT (dialog),
  +                      "key_press_event",
  +                      (GtkSignalFunc) fill_type_dialog_keypress,
  +                      fill_type_data);
  +
  +  gtk_window_set_title(GTK_WINDOW (dialog), _("Edit Fill Type"));
  +  gtk_container_border_width(GTK_CONTAINER(dialog), 10);
  +  
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      gtk_label_new (_("Fill Type")),
  +                      TRUE, TRUE, 0);
  +
  +  optionmenu = gtk_option_menu_new ();
  +  gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),
  +                           create_menu_filltype (w_current));
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      optionmenu,
  +                      TRUE, TRUE, 0);
  +  gtk_signal_connect(GTK_OBJECT (optionmenu), "changed",
  +                     (GtkSignalFunc) fill_type_dialog_filltype_change,
  +                     fill_type_data);
  +
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      gtk_label_new (_("Line Width")),
  +                      TRUE, TRUE, 0);
  +
  +  width_entry = gtk_entry_new();
  +  gtk_editable_select_region (GTK_EDITABLE (width_entry), 0, -1);
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      width_entry,
  +                      TRUE, TRUE, 10);
  +  gtk_signal_connect (GTK_OBJECT (width_entry), "activate",
  +                      GTK_SIGNAL_FUNC (fill_type_dialog_ok),
  +                      fill_type_data);
  +
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      gtk_label_new (_("Angle1")),
  +                      TRUE, TRUE, 0);
  +
  +  angle1_entry = gtk_entry_new ();
  +  gtk_editable_select_region (GTK_EDITABLE (angle1_entry), 0, -1);
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      angle1_entry,
  +                      TRUE, TRUE, 10);
  +  gtk_signal_connect (GTK_OBJECT (angle1_entry), "activate",
  +                      GTK_SIGNAL_FUNC (fill_type_dialog_ok),
  +                      fill_type_data);
  +		
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      gtk_label_new (_("Pitch1")),
  +                      TRUE, TRUE, 0);
  +
  +  pitch1_entry = gtk_entry_new ();
  +  gtk_editable_select_region (GTK_EDITABLE (pitch1_entry), 0, -1);
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      pitch1_entry,
  +                      TRUE, TRUE, 10);
  +  gtk_signal_connect (GTK_OBJECT (pitch1_entry), "activate",
  +                      GTK_SIGNAL_FUNC (fill_type_dialog_ok),
  +                      fill_type_data);
  +		
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      gtk_label_new (_("Angle2")),
  +                      TRUE, TRUE, 0);
  +
  +  angle2_entry = gtk_entry_new ();
  +  gtk_editable_select_region (GTK_EDITABLE (angle2_entry), 0, -1);
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      angle2_entry,
  +                      TRUE, TRUE, 10);
  +  gtk_signal_connect (GTK_OBJECT (angle2_entry), "activate",
  +                      GTK_SIGNAL_FUNC (fill_type_dialog_ok),
  +                      fill_type_data);
  +
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      gtk_label_new (_("Pitch2")),
  +                      TRUE, TRUE, 0);
  +
  +  pitch2_entry = gtk_entry_new ();
  +  gtk_editable_select_region (GTK_EDITABLE (pitch2_entry), 0, -1);
  +  gtk_box_pack_start (GTK_BOX (vbox),
  +                      pitch2_entry,
  +                      TRUE, TRUE, 10);
  +  gtk_signal_connect (GTK_OBJECT (pitch2_entry), "activate",
  +                      GTK_SIGNAL_FUNC (fill_type_dialog_ok),
  +                      fill_type_data);
  +
  +		
  +#ifdef HAS_GTK12
  +  buttonok = gtk_button_new_with_label (_("OK"));
  +#else
  +  buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +  GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +  gtk_box_pack_start (GTK_BOX (action_area),
  +                      buttonok,
  +                      TRUE, TRUE, 0);
  +  gtk_signal_connect (GTK_OBJECT (buttonok), "clicked",
  +                      GTK_SIGNAL_FUNC (fill_type_dialog_ok),
  +                      fill_type_data);
  +  gtk_widget_grab_default (buttonok);
  +
  +#ifdef HAS_GTK12
  +  buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +  buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +  GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +  gtk_box_pack_start (GTK_BOX (action_area),
  +                      buttoncancel,
  +                      TRUE, TRUE, 0);
  +  gtk_signal_connect (GTK_OBJECT (buttoncancel), "clicked",
  +                      GTK_SIGNAL_FUNC (fill_type_dialog_cancel),
  +                      fill_type_data);
  +
  +  /* populate the data structure */
  +  fill_type_data->dialog = dialog;
  +  fill_type_data->fill_type    = optionmenu;
  +  fill_type_data->width_entry  = width_entry;
  +  fill_type_data->angle1_entry = angle1_entry;
  +  fill_type_data->pitch1_entry = pitch1_entry;
  +  fill_type_data->angle2_entry = angle2_entry;
  +  fill_type_data->pitch2_entry = pitch2_entry;
  +  
  +  fill_type_data->toplevel = w_current;
  +  fill_type_data->objects  = objects;
  +
  +  /* fill in the fields of the dialog */
  +  if (g_list_next (objects) == NULL) {
  +    /* only one object in object list */
  +    OBJECT *o_current = (OBJECT*) objects->data;
  +      
  +    type = o_current->fill_type;
  +    width_str  = g_strdup_printf ("%d", o_current->fill_width);
  +    angle1_str = g_strdup_printf ("%d", o_current->fill_angle1);
  +    pitch1_str = g_strdup_printf ("%d", o_current->fill_pitch1);
  +    angle2_str = g_strdup_printf ("%d", o_current->fill_angle2);
  +    pitch2_str = g_strdup_printf ("%d", o_current->fill_pitch2);
  +  } else {
  +    GtkWidget *menuitem;
  +    GtkWidget *menu;
  +      
  +    width_str  = g_strdup_printf (_("*unchanged*"));
  +    angle1_str = g_strdup_printf (_("*unchanged*"));
  +    pitch1_str = g_strdup_printf (_("*unchanged*"));
  +    angle2_str = g_strdup_printf (_("*unchanged*"));
  +    pitch2_str = g_strdup_printf (_("*unchanged*"));
  +    type = FILLING_HATCH + 1;
  +      
  +    /* add a new menuitem to option menu for line type */
  +    menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (optionmenu));
  +    menuitem = gtk_radio_menu_item_new_with_label (
  +      gtk_radio_menu_item_get_group (
  +        GTK_RADIO_MENU_ITEM (gtk_menu_get_active (GTK_MENU (menu)))),
  +      _("*unchanged*"));
  +    gtk_menu_append (menu, menuitem);
  +    gtk_object_set_data (GTK_OBJECT (menuitem),
  +                         "filltype",
  +                         GINT_TO_POINTER (-1));
  +    gtk_widget_show (menuitem);
  +  }
  +
  +  gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), type);
  +  gtk_entry_set_text (GTK_ENTRY (width_entry), width_str);
  +  gtk_entry_select_region (GTK_ENTRY (width_entry), 0, strlen (width_str));
  +  gtk_entry_set_text (GTK_ENTRY (angle1_entry), angle1_str);
  +  gtk_entry_select_region (GTK_ENTRY (angle1_entry), 0, strlen (angle1_str));
  +  gtk_entry_set_text (GTK_ENTRY (pitch1_entry), pitch1_str);
  +  gtk_entry_select_region (GTK_ENTRY (pitch1_entry), 0, strlen (pitch1_str));
  +  gtk_entry_set_text (GTK_ENTRY (angle2_entry), angle2_str);
  +  gtk_entry_select_region (GTK_ENTRY (angle2_entry), 0, strlen (angle2_str));
  +  gtk_entry_set_text (GTK_ENTRY (pitch2_entry), pitch2_str);
  +  gtk_entry_select_region (GTK_ENTRY (pitch2_entry), 0, strlen (pitch2_str));
  +  
  +  gtk_widget_grab_focus(width_entry);
  +  gtk_grab_add (dialog);
  +  
  +  g_free (width_str);
  +  g_free (angle1_str);
  +  g_free (pitch1_str);
  +  g_free (angle2_str);
  +  g_free (pitch2_str);
  +  
  +  gtk_widget_show_all (dialog);
  +  
  +}
  +
  +/***************** End of Fill Type dialog box ***********************/
  +
  +/***************** Start of Exit dialog box **************************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int exit_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			 TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	exit_dialog_cancel(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void exit_dialog_ok(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  gtk_grab_remove(w_current->exwindow);
  +  gtk_widget_destroy(w_current->exwindow);
  +  w_current->exwindow = NULL;
  +
  +  /* go through and change ALL changed flags to 0 */
  +#if 0
  +  w_current->page_current->CHANGED = 0;
  +#endif
  +  s_page_clear_changed(w_current->page_head);
  +  i_callback_file_close(w_current, 0, NULL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void exit_dialog_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  gtk_grab_remove(w_current->exwindow);
  +  gtk_widget_destroy(w_current->exwindow);
  +  w_current->exwindow = NULL;
  +
  +  /* leave this one */
  +  w_current->event_state = SELECT;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void exit_dialog (TOPLEVEL *w_current)
  +{
  +  GtkWidget *exit_dialog;
  +  GtkWidget *vbox1;
  +  GtkWidget *label1;
  +  GtkWidget *hseparator1;
  +  GtkWidget *hbuttonbox1;
  +  GtkWidget *button1;
  +  GtkWidget *button2;
  +
  +  if (!w_current->exwindow)
  +  {
  +
  +    exit_dialog = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  +    w_current->exwindow = exit_dialog;
  +    gtk_window_set_title (GTK_WINDOW (exit_dialog), "Discard Changes?");
  +    gtk_window_set_position (GTK_WINDOW (exit_dialog), GTK_WIN_POS_MOUSE);
  +    gtk_window_set_modal (GTK_WINDOW (exit_dialog), TRUE);
  +    gtk_window_set_default_size (GTK_WINDOW (exit_dialog), 240, 160);
  +    gtk_widget_show (exit_dialog);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->exwindow),
  +                       "destroy",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->exwindow);
  +    
  +    gtk_signal_connect(GTK_OBJECT(w_current->exwindow),
  +                       "key_press_event",
  +                       (GtkSignalFunc) exit_dialog_keypress, w_current);
  +
  +    vbox1 = gtk_vbox_new (FALSE, 0);
  +    gtk_widget_show (vbox1);
  +    gtk_container_add (GTK_CONTAINER (exit_dialog), vbox1);
  +
  +    label1 = gtk_label_new(
  +                           _("There are unsaved schematics!\n"
  +                             "\n"
  +                             "Are you sure?\n"
  +                             "OK will discard ALL changes!"));
  +    gtk_label_set_justify (GTK_LABEL (label1), GTK_JUSTIFY_CENTER);
  +    gtk_widget_show (label1);
  +    gtk_box_pack_start (GTK_BOX (vbox1), label1, TRUE, TRUE, 0);
  +    hseparator1 = gtk_hseparator_new ();
  +    gtk_widget_show (hseparator1);
  +    gtk_box_pack_start (GTK_BOX (vbox1), hseparator1, FALSE, FALSE, 0);
  +
  +    hbuttonbox1 = gtk_hbutton_box_new ();
  +    gtk_widget_show (hbuttonbox1);
  +    gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, FALSE, FALSE, 0);
  +    gtk_container_set_border_width (GTK_CONTAINER (hbuttonbox1), 10);
  +
  +#ifdef HAS_GTK12
  +    button1 = gtk_button_new_with_label (_("OK"));
  +#else
  +    button1 = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    gtk_widget_show (button1);
  +    gtk_container_add (GTK_CONTAINER (hbuttonbox1), button1);
  +    GTK_WIDGET_SET_FLAGS (button1, GTK_CAN_DEFAULT);
  +    gtk_signal_connect(GTK_OBJECT (button1), "clicked",
  +                       GTK_SIGNAL_FUNC(exit_dialog_ok), w_current);
  +
  +#ifdef HAS_GTK12
  +    button2 = gtk_button_new_with_label (_("Cancel"));
  +#else
  +    button2 = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +    gtk_widget_show (button2);
  +    gtk_container_add (GTK_CONTAINER (hbuttonbox1), button2);
  +    GTK_WIDGET_SET_FLAGS (button2, GTK_CAN_DEFAULT);
  +    gtk_signal_connect(GTK_OBJECT (button2), "clicked",
  +                       GTK_SIGNAL_FUNC(exit_dialog_cancel),
  +                       w_current);
  +
  +    gtk_widget_grab_focus (button2);
  +    gtk_widget_grab_default (button2);
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->exwindow)) {
  +    gtk_widget_show(w_current->exwindow);
  +    gtk_grab_add(w_current->exwindow);
  +  }
  +}
  +
  +/***************** End of Exit dialog box ****************************/
  +
  +/***************** Start of Arc dialog box ***************************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int arc_angles_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +	              TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	arc_angles_dialog_cancel(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void arc_angles_dialog_ok(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  char *string_start = NULL;
  +  char *string_sweep = NULL;
  +
  +  string_start = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->aaentry_start));
  +  string_sweep = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->aaentry_sweep));
  +
  +  if ( (string_start[0] != '\0') && (string_sweep[0] != '\0') ) {
  +    /*! \todo put error detection */
  +    /* pb20011125 - o_arc_end4 accepts the final angles as param */
  +    o_arc_end4(w_current, atoi(string_start), atoi(string_sweep));
  +  }
  +
  +  gtk_grab_remove(w_current->aawindow);
  +  gtk_widget_destroy(w_current->aawindow);
  +  w_current->aawindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void arc_angles_dialog_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  gtk_grab_remove(w_current->aawindow);
  +  gtk_widget_destroy(w_current->aawindow);
  +  w_current->aawindow = NULL;
  +
  +  w_current->event_state = DRAWARC;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void arc_angle_dialog (TOPLEVEL *w_current)
  +{
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok     = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +
  +  if (!w_current->aawindow) {
  +    w_current->aawindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW(w_current->aawindow),
  +                        GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->aawindow),
  +                       "destroy",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->aawindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->aawindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) arc_angles_dialog_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT(w_current->aawindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->aawindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW(w_current->aawindow),
  +                         _("Arc Params"));
  +    gtk_container_border_width(GTK_CONTAINER(w_current->aawindow),
  +                               10);
  +
  +    label = gtk_label_new (_("Start Angle"));
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       label, TRUE, TRUE, 0);
  +    gtk_widget_show (label);
  +
  +    w_current->aaentry_start = gtk_entry_new_with_max_length (4);
  +    gtk_editable_select_region(
  +                               GTK_EDITABLE(w_current->aaentry_start), 0, -1);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       w_current->aaentry_start, FALSE, FALSE, 5);
  +    gtk_widget_show(w_current->aaentry_start);
  +    gtk_widget_grab_focus(w_current->aaentry_start);
  +
  +    label = gtk_label_new(_("Degrees of Sweep"));
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       label, TRUE, TRUE, 0);
  +    gtk_widget_show(label);
  +
  +    w_current->aaentry_sweep = gtk_entry_new_with_max_length (4);
  +    gtk_editable_select_region(
  +                               GTK_EDITABLE(w_current->aaentry_sweep), 0, -1);
  +    gtk_box_pack_start(GTK_BOX(vbox),
  +                       w_current->aaentry_sweep, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->aaentry_sweep),
  +                       "activate",
  +                       GTK_SIGNAL_FUNC(arc_angles_dialog_ok),
  +                       w_current);
  +    gtk_widget_show(w_current->aaentry_sweep);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label (_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start (
  +			GTK_BOX(action_area),
  +			buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonok), "clicked",
  +                       GTK_SIGNAL_FUNC(arc_angles_dialog_ok),
  +                       w_current);
  +    gtk_widget_show (buttonok);
  +    gtk_widget_grab_default (buttonok);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start (GTK_BOX (action_area),
  +                        buttoncancel, TRUE, TRUE, 0);
  +    gtk_signal_connect (GTK_OBJECT (buttoncancel), "clicked",
  +                        GTK_SIGNAL_FUNC(arc_angles_dialog_cancel),
  +                        w_current);
  +    gtk_widget_show (buttoncancel);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->aawindow)) {
  +    gtk_widget_show (w_current->aawindow);
  +    gtk_grab_add (w_current->aawindow);
  +  }
  +}
  +
  +/***************** End of Arc dialog box *****************************/
  +
  +/***************** Start of Translate dialog box *********************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int translate_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			      TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	translate_dialog_cancel(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void translate_dialog_ok(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  char *string=NULL;
  +
  +  string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->trentry));
  +
  +  if ((string[0] != '\0')) {
  +    /*! \todo put error detection */
  +    /* zero offset has a special meaning... */
  +    o_complex_translate_all(w_current, atoi(string));
  +  }
  +
  +#if 0
  +  gtk_grab_remove(w_current->trwindow);
  +#endif
  +  gtk_widget_destroy(w_current->trwindow);
  +  w_current->trwindow=NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void translate_dialog_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +#if 0
  +	gtk_grab_remove(w_current->trwindow);
  +#endif
  +  gtk_widget_destroy(w_current->trwindow);
  +  w_current->trwindow=NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void translate_dialog (TOPLEVEL *w_current)
  +{
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +
  +  if (!w_current->trwindow) {
  +    w_current->trwindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW (w_current->trwindow),
  +                        GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT (w_current->trwindow),
  +                       "destroy",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->trwindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->trwindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) translate_dialog_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT (w_current->trwindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->trwindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW (w_current->trwindow),
  +                         _("Translate"));
  +    gtk_container_border_width (GTK_CONTAINER (
  +                                               w_current->trwindow), 10);
  +
  +    label = gtk_label_new(_("Offset to translate?\n(0 for origin)"));
  +    gtk_misc_set_padding(GTK_MISC (label), 10, 10);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       label, TRUE, TRUE, 0);
  +    gtk_widget_show (label);
  +
  +    w_current->trentry = gtk_entry_new_with_max_length (10);
  +    gtk_editable_select_region(GTK_EDITABLE(w_current->trentry),
  +                               0, -1);
  +    gtk_box_pack_start(GTK_BOX(vbox),
  +                       w_current->trentry, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->trentry), "activate",
  +                       GTK_SIGNAL_FUNC(translate_dialog_ok),
  +                       w_current);
  +    gtk_widget_show (w_current->trentry);
  +    gtk_widget_grab_focus(w_current->trentry);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label (_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start (GTK_BOX (action_area),
  +                        buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonok), "clicked",
  +                       GTK_SIGNAL_FUNC(translate_dialog_ok),
  +                       w_current);
  +    gtk_widget_show (buttonok);
  +    gtk_widget_grab_default (buttonok);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttoncancel, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttoncancel), "clicked",
  +                       GTK_SIGNAL_FUNC(translate_dialog_cancel),
  +                       w_current);
  +    gtk_widget_show (buttoncancel);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->trwindow)) {
  +    gtk_widget_show (w_current->trwindow);
  +#if 0
  +    gtk_grab_add (w_current->trwindow);
  +#endif
  +  }
  +}
  +
  +/***************** End of Translate dialog box ***********************/
  +
  +/***************** Start of Text size dialog box *********************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int text_size_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			      TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	text_size_dialog_cancel(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_size_dialog_ok(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  char *string = NULL;
  +  int size;
  +
  +  string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->tsentry));
  +
  +  if ((string[0] != '\0')) {
  +    size = atoi(string);
  +    if (size) {
  +      w_current->text_size = size;
  +      w_current->page_current->CHANGED=1;
  +      o_undo_savestate(w_current, UNDO_ALL);
  +    }
  +  }
  +
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_size_dialog_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void text_size_dialog (TOPLEVEL *w_current)
  +{
  +  char *string;
  +  int len;
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +
  +  if (!w_current->tswindow) {
  +    w_current->tswindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW(w_current->tswindow),
  +                        GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +                       "destroy",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->tswindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) text_size_dialog_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT (w_current->tswindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->tswindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW (w_current->tswindow),
  +                         _("Text Size"));
  +    gtk_container_border_width(GTK_CONTAINER(w_current->tswindow),
  +                               10);
  +
  +    label = gtk_label_new (_("Enter new text size"));
  +    gtk_misc_set_padding (GTK_MISC (label), 10, 10);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       label, TRUE, TRUE, 0);
  +    gtk_widget_show (label);
  +
  +    w_current->tsentry = gtk_entry_new_with_max_length (10);
  +    gtk_editable_select_region(
  +                               GTK_EDITABLE(w_current->tsentry), 0, -1);
  +    gtk_box_pack_start(GTK_BOX(vbox),
  +                       w_current->tsentry, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->tsentry), "activate",
  +                       GTK_SIGNAL_FUNC(text_size_dialog_ok),
  +                       w_current);
  +    gtk_widget_show (w_current->tsentry);
  +    gtk_widget_grab_focus(w_current->tsentry);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label (_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonok), "clicked",
  +                       GTK_SIGNAL_FUNC(text_size_dialog_ok),
  +                       w_current);
  +    gtk_widget_show (buttonok);
  +    gtk_widget_grab_default (buttonok);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttoncancel, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttoncancel), "clicked",
  +                       GTK_SIGNAL_FUNC(text_size_dialog_cancel),
  +                       w_current);
  +    gtk_widget_show (buttoncancel);
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->tswindow)) {
  +    string = g_strdup_printf("%d", w_current->text_size);
  +    len = strlen(string);
  +    gtk_entry_set_text(GTK_ENTRY(w_current->tsentry), string);
  +    gtk_entry_select_region(GTK_ENTRY(w_current->tsentry), 0, len);
  +    gtk_widget_show (w_current->tswindow);
  +    gtk_grab_add(w_current->tswindow);
  +    free(string);
  +  }
  +}
  +
  +/***************** End of Text size dialog box ***********************/
  +
  +/***************** Start of Snap size dialog box *********************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int snap_size_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			      TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	snap_size_dialog_cancel(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void snap_size_dialog_ok(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  char *string = NULL;
  +  int size;
  +
  +  string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->tsentry));
  +
  +  if ((string[0] != '\0')) {
  +    size = atoi(string);
  +    if (size) {
  +      w_current->snap_size = size;
  +    }
  +  }
  +
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void snap_size_dialog_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void snap_size_dialog (TOPLEVEL *w_current)
  +{
  +  char *string;
  +  int len;
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok     = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +
  +  if (!w_current->tswindow) {
  +    w_current->tswindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW (w_current->tswindow),
  +                        GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow), "destroy",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->tswindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) snap_size_dialog_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->tswindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW (w_current->tswindow),
  +                         _("Snap Grid"));
  +    gtk_container_border_width(GTK_CONTAINER(w_current->tswindow),
  +                               10);
  +
  +    label = gtk_label_new(_("Enter new snap grid spacing"));
  +    gtk_misc_set_padding(GTK_MISC (label), 10, 10);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       label, TRUE, TRUE, 0);
  +    gtk_widget_show(label);
  +
  +    w_current->tsentry = gtk_entry_new_with_max_length (10);
  +    gtk_editable_select_region(GTK_EDITABLE(w_current->tsentry),
  +                               0, -1);
  +    gtk_box_pack_start(GTK_BOX(vbox),
  +                       w_current->tsentry, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->tsentry), "activate",
  +                       GTK_SIGNAL_FUNC(snap_size_dialog_ok),
  +                       w_current);
  +    gtk_widget_show(w_current->tsentry);
  +    gtk_widget_grab_focus(w_current->tsentry);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label (_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonok), "clicked",
  +                       GTK_SIGNAL_FUNC(snap_size_dialog_ok),
  +                       w_current);
  +    gtk_widget_show (buttonok);
  +    gtk_widget_grab_default (buttonok);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttoncancel, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttoncancel), "clicked",
  +                       GTK_SIGNAL_FUNC(snap_size_dialog_cancel),
  +                       w_current);
  +    gtk_widget_show(buttoncancel);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->tswindow)) {
  +    string = g_strdup_printf("%d", w_current->snap_size);
  +    len = strlen(string);
  +    gtk_entry_set_text(GTK_ENTRY(w_current->tsentry), string);
  +    gtk_entry_select_region(GTK_ENTRY(w_current->tsentry), 0, len);
  +    gtk_widget_show (w_current->tswindow);
  +    gtk_grab_add (w_current->tswindow);
  +    free(string);
  +  }
  +}
  +
  +/***************** End of Snap size dialog box ***********************/
  +
  +/***************** Start of slot edit dialog box *********************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int slot_edit_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			      TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	slot_edit_dialog_cancel(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void slot_edit_dialog_ok(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  int len;
  +  char *string = NULL;
  +
  +  string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->seentry));
  +
  +  if (string[0] != '\0') {
  +    len = strlen(string);
  +
  +#if DEBUG
  +    printf("text was: _%s_ %d\n", string, len);
  +#endif
  +
  +    if (len < 80) {
  +      o_slot_end(w_current, string, len);
  +    } else {
  +      /*! \todo you should NOT have limits */
  +      fprintf(stderr, _("String too long... hack!\n"));
  +    }
  +  }
  +
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +
  +  gtk_grab_remove(w_current->sewindow);
  +  gtk_widget_destroy(w_current->sewindow);
  +  w_current->sewindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void slot_edit_dialog_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +  gtk_grab_remove(w_current->sewindow);
  +  gtk_widget_destroy(w_current->sewindow);
  +  w_current->sewindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void slot_edit_dialog (TOPLEVEL *w_current, char *string)
  +{
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +  GtkWidget *vbox, *action_area;
  +  int len;
  +
  +  if (!w_current->sewindow) {
  +    w_current->sewindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW(w_current->sewindow),
  +                        GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT (w_current->sewindow),
  +                       "destroy", GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->sewindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->sewindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) slot_edit_dialog_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT (w_current->sewindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->sewindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW (w_current->sewindow),
  +                         _("Edit slot number"));
  +    gtk_container_border_width(
  +                               GTK_CONTAINER(w_current->sewindow), 10);
  +
  +    label = gtk_label_new (_("Edit slot number"));
  +    gtk_box_pack_start(
  +                       GTK_BOX (vbox),
  +                       label, TRUE, TRUE, 0);
  +    gtk_widget_show (label);
  +
  +    w_current->seentry = gtk_entry_new();
  +    gtk_editable_select_region(
  +                               GTK_EDITABLE (w_current->seentry), 0, -1);
  +    gtk_box_pack_start( GTK_BOX(vbox),
  +                       w_current->seentry, TRUE, TRUE, 10);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->seentry), "activate",
  +                       GTK_SIGNAL_FUNC(slot_edit_dialog_ok),
  +                       w_current);
  +    gtk_widget_show (w_current->seentry);
  +    gtk_widget_grab_focus(w_current->seentry);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label (_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect (GTK_OBJECT (buttonok), "clicked",
  +                        GTK_SIGNAL_FUNC(slot_edit_dialog_ok),
  +                        w_current);
  +    gtk_widget_show (buttonok);
  +    gtk_widget_grab_default (buttonok);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start (GTK_BOX (action_area), buttoncancel, 
  +                        TRUE, TRUE, 0);
  +    gtk_signal_connect (GTK_OBJECT (buttoncancel), "clicked",
  +                        GTK_SIGNAL_FUNC(slot_edit_dialog_cancel),
  +                        w_current);
  +    gtk_widget_show (buttoncancel);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->sewindow)) {
  +    gtk_widget_show (w_current->sewindow);
  +
  +    if (string != NULL) {
  +      len = strlen(string);
  +      gtk_entry_set_text(GTK_ENTRY(w_current->seentry),
  +                         string);
  +      gtk_entry_select_region(GTK_ENTRY(w_current->seentry),
  +                              strlen("slot="), len);
  +    }
  +    gtk_grab_add (w_current->sewindow);
  +  }
  +}
  +
  +/***************** End of Slot Edit dialog box ***********************/
  +
  +/***************** Start of help/about dialog box ********************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int about_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			  TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	about_dialog_close(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void about_dialog_close(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  gtk_widget_destroy(w_current->abwindow);
  +  w_current->abwindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void about_dialog (TOPLEVEL *w_current)
  +{
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonclose = NULL;
  +  GtkWidget *vbox, *action_area;
  +  char *string;
  +
  +  if (!w_current->abwindow) {
  +    w_current->abwindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position (GTK_WINDOW (w_current->abwindow),
  +                         GTK_WIN_POS_MOUSE);
  +
  +    gtk_window_set_title (GTK_WINDOW (w_current->abwindow),
  +                          _("About..."));
  +    gtk_container_border_width (GTK_CONTAINER (
  +                                               w_current->abwindow), 5);
  +
  +    gtk_signal_connect (GTK_OBJECT (w_current->abwindow),
  +                        "destroy", GTK_SIGNAL_FUNC(destroy_window),
  +                        &w_current->abwindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->abwindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) about_dialog_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect (GTK_OBJECT (w_current->abwindow),
  +                        "delete_event",
  +                        GTK_SIGNAL_FUNC(destroy_window),
  +                        &w_current->abwindow);
  +#endif
  +
  +    string = g_strdup_printf( _("gEDA : GPL Electronic Design Automation"));
  +    label = gtk_label_new (string);
  +    free(string);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       label, TRUE, TRUE, 5);
  +    gtk_widget_show (label);
  +
  +    string = g_strdup_printf(_("gschem version %s"), VERSION);
  +    label = gtk_label_new (string);
  +    free(string);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       label, TRUE, TRUE, 5);
  +    gtk_widget_show (label);
  +
  +    string = g_strdup_printf( _("Written by:\nAles V. Hvezda\nahvezda@xxxxxxxxxxxxx\nAnd many others (See AUTHORS file)"));
  +    label = gtk_label_new (string);
  +    free(string);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       label, TRUE, TRUE, 5);
  +    gtk_widget_show (label);
  +
  +#ifdef HAS_GTK12
  +    buttonclose = gtk_button_new_with_label (_("Close"));
  +#else
  +    buttonclose = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonclose, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonclose, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonclose), "clicked",
  +                       GTK_SIGNAL_FUNC(about_dialog_close),
  +                       w_current);
  +    gtk_widget_show(buttonclose);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(w_current->abwindow)) {
  +    gtk_widget_show(w_current->abwindow);
  +  }
  +}
  +
  +/***************** End of help/about dialog box *********************/
  +
  +/***************** Start of coord dialog box ************************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int coord_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			  TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	coord_dialog_close(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void coord_dialog_close(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  gtk_widget_destroy(w_current->cowindow);
  +  w_current->cowindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void coord_display_update(TOPLEVEL *w_current, int x, int y)
  +{
  +  char *string;
  +  int world_x, world_y;
  +
  +  string = g_strdup_printf("(%d, %d)", x, y);
  +  gtk_label_set_text(GTK_LABEL(w_current->coord_screen), string );
  +  free(string);
  +
  +  SCREENtoWORLD(w_current, x, y, &world_x, &world_y);
  +
  +  string = g_strdup_printf("(%d, %d)", world_x, world_y);
  +  gtk_label_set_text(GTK_LABEL(w_current->coord_world), string );
  +  free(string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void coord_dialog (TOPLEVEL *w_current, int x, int y)
  +{
  +  GtkWidget *buttonclose = NULL;
  +  GtkWidget *frame;
  +  GtkWidget *vbox2;
  +
  +  if (!w_current->cowindow) {
  +    w_current->cowindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  +    gtk_window_position (GTK_WINDOW (w_current->cowindow),
  +                         GTK_WIN_POS_MOUSE);
  +
  +    gtk_window_set_title (GTK_WINDOW (w_current->cowindow),
  +                          _("Coords"));
  +    gtk_container_border_width (GTK_CONTAINER (
  +                                               w_current->cowindow), 5);
  +
  +    gtk_signal_connect (GTK_OBJECT (w_current->cowindow),
  +                        "destroy", GTK_SIGNAL_FUNC(destroy_window),
  +                        &w_current->cowindow);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect (GTK_OBJECT (w_current->cowindow),
  +                        "delete_event",
  +                        GTK_SIGNAL_FUNC(destroy_window),
  +                        &w_current->cowindow);
  +#endif
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->cowindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) coord_dialog_keypress, w_current);
  +
  +
  +    vbox2 = gtk_vbox_new (FALSE, 5);
  +    gtk_container_add (GTK_CONTAINER (w_current->cowindow), vbox2);
  +    gtk_widget_show(vbox2);
  +
  +    frame = gtk_frame_new (_("Screen"));
  +    w_current->coord_screen =
  +      gtk_label_new("(########, ########)");
  +    gtk_label_set_justify(
  +                          GTK_LABEL(w_current->coord_screen), GTK_JUSTIFY_LEFT);
  +    gtk_misc_set_padding(GTK_MISC(w_current->coord_screen),
  +                         10, 10);
  +    gtk_container_add(GTK_CONTAINER (frame),
  +                      w_current->coord_screen);
  +    gtk_box_pack_start(GTK_BOX (vbox2), frame, FALSE, FALSE, 0);
  +    gtk_widget_show(w_current->coord_screen);
  +    gtk_widget_show(frame);
  +
  +    frame = gtk_frame_new (_("World"));
  +    w_current->coord_world =
  +      gtk_label_new ("(########, ########)");
  +    gtk_misc_set_padding(GTK_MISC(w_current->coord_world), 10, 10);
  +    gtk_label_set_justify(GTK_LABEL(w_current->coord_world),
  +                          GTK_JUSTIFY_LEFT);
  +    gtk_container_add(GTK_CONTAINER (frame),
  +                      w_current->coord_world);
  +    gtk_box_pack_start(GTK_BOX (vbox2), frame, FALSE, FALSE, 0);
  +    gtk_widget_show(w_current->coord_world);
  +    gtk_widget_show(frame);
  +
  +#ifdef HAS_GTK12
  +    buttonclose = gtk_button_new_with_label (_("Close"));
  +#else
  +    buttonclose = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonclose, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX ( vbox2 ),
  +                       buttonclose, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonclose), "clicked",
  +                       GTK_SIGNAL_FUNC(coord_dialog_close),
  +                       w_current);
  +    gtk_widget_show(buttonclose);
  +    gtk_widget_grab_default (buttonclose);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->cowindow)) {
  +    gtk_widget_show (w_current->cowindow);
  +    coord_display_update(w_current, x, y);
  +  } else {
  +    gdk_window_raise(w_current->cowindow->window);
  +  }
  +}
  +
  +/***************** End of coord dialog box **************************/
  +
  +/***************** Start of color edit dialog box *******************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint color_set(GtkWidget *w, gpointer data)
  +{
  +  int index;
  +
  +  /* 
  +   * here we really are passing an int sized piece of data, the index rather
  +   * than a pointer and we shouldn't have issues as long as
  +   * sizeof(void *) >= sizeof(int)
  +   */
  +  index = GPOINTER_TO_INT( data );
  +
  +  /* hate to use this here... but I have to... */
  +  global_window_current->edit_color = index;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \warning
  + *  Caller must free returned character string.
  + *
  + */
  +char *index2functionstring(int index)
  +{
  +  char *string;
  +
  +  switch(index) {
  +    case(BACKGROUND_COLOR):
  +      string = g_strdup ("background");
  +      break;
  +    case(PIN_COLOR):
  +      string = g_strdup ("pin");
  +      break;
  +    case(NET_ENDPOINT_COLOR):
  +      string = g_strdup ("net endpoint");
  +      break;
  +    case(GRAPHIC_COLOR):
  +      string = g_strdup ("graphic");
  +      break;
  +    case(NET_COLOR):
  +      string = g_strdup ("net");
  +      break;
  +    case(ATTRIBUTE_COLOR):
  +      string = g_strdup ("attribute");
  +      break;
  +    case(LOGIC_BUBBLE_COLOR):
  +      string = g_strdup ("logic bubble");
  +      break;
  +    case(GRID_COLOR):
  +      string = g_strdup ("grid point");
  +      break;
  +    case(DETACHED_ATTRIBUTE_COLOR):
  +      string = g_strdup ("detached attribute");
  +      break;
  +    case(TEXT_COLOR):
  +      string = g_strdup ("text");
  +      break;
  +    case(BUS_COLOR):
  +      string = g_strdup ("bus");
  +      break;
  +    case(SELECT_COLOR):
  +      string = g_strdup ("select");
  +      break;
  +    case(BOUNDINGBOX_COLOR):
  +      string = g_strdup ("bounding box");
  +      break;
  +    case(ZOOM_BOX_COLOR):
  +      string = g_strdup ("zoom box");
  +      break;
  +    case(STROKE_COLOR):
  +      string = g_strdup ("stroke");
  +      break;
  +    case(LOCK_COLOR):
  +      string = g_strdup ("lock");
  +      break;
  +    case(OUTPUT_BACKGROUND_COLOR):
  +      string = g_strdup ("output background");
  +      break;
  +    default:
  +      string = g_strdup ("unknown");
  +      break;
  +  }
  +  return(string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  This is from gtktest.c
  + */
  +static GtkWidget *create_color_menu (TOPLEVEL * w_current, int * select_index)
  +{
  +  GtkWidget *menu;
  +  GtkWidget *menuitem;
  +  GSList *group;
  +  int index=0;
  +  char *buf; 
  +  char *menu_string;
  +  char *temp=NULL;
  +
  +  /* first lets see if we have a selected object, if so select its color */
  +  int select_col = -1;
  +  int item_index = 0;
  +  SELECTION *s_current = NULL;
  +  OBJECT *object = NULL;
  +
  +  menu = gtk_menu_new ();
  +  group = NULL;
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +
  +  if (s_current != NULL) {
  +
  +    object = s_current->selected_object;
  +    if (object == NULL) {
  +      fprintf(stderr, "no object selected - WHEE!\n");
  +    }else{
  +      select_col = object->saved_color;
  +      //fprintf(stderr, "setting object color %d\n", select_col);
  +    }
  +  }else /*fprintf(stderr, "no object selected\n")*/;
  +
  +  for (index=0; index < MAX_COLORS;index++) {
  +    
  +    if ((buf=x_color_get_name(index)) != NULL) {
  +      temp = index2functionstring(index);
  +      menu_string = g_strdup_printf("%d | %s | %s", index, 
  +				    temp,
  +				    buf);
  +      free(temp);
  +      temp = NULL;
  +      g_free(buf);
  +      buf = NULL;
  +      menuitem = gtk_radio_menu_item_new_with_label (group, 
  +                                                     menu_string);
  +      free(menu_string);
  +      menu_string = NULL;
  +      
  +      group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(
  +                                                            menuitem));
  +      
  +      gtk_menu_append (GTK_MENU (menu), menuitem);
  +      
  +      gtk_signal_connect (GTK_OBJECT (menuitem), 
  +                          "activate", 
  +                          (GtkSignalFunc) color_set,
  +                          GINT_TO_POINTER( index ));
  +      
  +      /* I have no idea if doing the above cast is valid,
  +       * since index isn't a pointer, it's just being
  +       * treated as one, it's then cast to an int in
  +       * color_set.  This should be ok as long as
  +       * sizeof(void *) >= sizeof(int)
  +       */
  +
  +      if (select_col == -1){
  +	/* set the default to the current color */
  +        if (index == global_window_current->edit_color) {
  +          gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
  +          //fprintf(stderr, "checking item %d\n", index);
  +	  *select_index = item_index;
  +        }
  +      }else{
  +        if (index == select_col){
  +          gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(menuitem), TRUE);
  +          //fprintf(stderr, "checking selected item %d\n", index);
  +	  *select_index = item_index;
  +        }
  +      } 
  +      gtk_widget_show(menuitem);
  +      item_index++;
  +    }
  +  }
  +  
  +  
  +  return menu;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int color_edit_dialog_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			       TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	color_edit_dialog_close(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void color_edit_dialog_close(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  gtk_widget_destroy(w_current->clwindow);
  +  w_current->clwindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void color_edit_dialog_apply(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  SELECTION *s_current = NULL;
  +  OBJECT *object = NULL;
  +
  +  /* skip over head */
  +  s_current = w_current->page_current->selection2_head->next;
  +
  +  while(s_current != NULL) {
  +
  +    object = s_current->selected_object;
  +    if (object == NULL) {
  +      fprintf(stderr, _("ERROR: NULL object in color_edit_dialog_apply!\n"));
  +      exit(-1);
  +    }
  +
  +    switch(object->type) {
  +      case(OBJ_LINE):
  +      case(OBJ_BOX):
  +      case(OBJ_CIRCLE):
  +      case(OBJ_NET):
  +      case(OBJ_BUS):
  +      case(OBJ_PIN):
  +      case(OBJ_ARC):
  +        object->saved_color = w_current->edit_color;
  +        w_current->page_current->CHANGED = 1;
  +        break;
  +
  +      case(OBJ_TEXT):
  +        object->saved_color = w_current->edit_color;	
  +        o_complex_set_saved_color_only(
  +                                       object->text->prim_objs,
  +                                       w_current->edit_color);
  +        w_current->page_current->CHANGED = 1;
  +        break;
  +    }
  +
  +    s_current = s_current->next;
  +  }
  +  o_undo_savestate(w_current, UNDO_ALL);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void color_edit_dialog (TOPLEVEL *w_current)
  +{
  +  GtkWidget *buttonclose = NULL;
  +  GtkWidget *buttonapply = NULL;
  +  GtkWidget *optionmenu;
  +  GtkWidget *vbox, *action_area;
  +  int select_index = 0;
  +
  +  if (!w_current->clwindow) {
  +    w_current->clwindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position (GTK_WINDOW (w_current->clwindow),
  +                         GTK_WIN_POS_MOUSE);
  +
  +    gtk_window_set_title (GTK_WINDOW (w_current->clwindow),
  +                          _("Color Edit"));
  +    gtk_container_border_width(
  +                               GTK_CONTAINER(w_current->clwindow), 5);
  +
  +    gtk_signal_connect (GTK_OBJECT (w_current->clwindow),
  +                        "destroy", GTK_SIGNAL_FUNC(destroy_window),
  +                        &w_current->clwindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->clwindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) color_edit_dialog_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect (GTK_OBJECT (w_current->clwindow),
  +                        "delete_event",
  +                        GTK_SIGNAL_FUNC(destroy_window),
  +                        &w_current->clwindow);
  +#endif
  +
  +    optionmenu = gtk_option_menu_new ();
  +    gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),
  +                             create_color_menu (w_current, &select_index));
  +    gtk_option_menu_set_history(GTK_OPTION_MENU (optionmenu), select_index);
  +    gtk_box_pack_start(
  +                       GTK_BOX(vbox),
  +                       optionmenu, TRUE, TRUE, 0);
  +    gtk_widget_show (optionmenu);
  +
  +#ifdef HAS_GTK12
  +    buttonapply = gtk_button_new_with_label (_("Apply"));
  +#else
  +    buttonapply = gtk_button_new_from_stock (GTK_STOCK_APPLY);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonapply, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonapply, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonapply), "clicked",
  +                       GTK_SIGNAL_FUNC(color_edit_dialog_apply),
  +                       w_current);
  +    gtk_widget_show (buttonapply);
  +    gtk_widget_grab_default(buttonapply);
  +
  +#ifdef HAS_GTK12
  +    buttonclose = gtk_button_new_with_label (_("Close"));
  +#else
  +    buttonclose = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonclose, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonclose), "clicked",
  +                       GTK_SIGNAL_FUNC(color_edit_dialog_close),
  +                       w_current);
  +    gtk_widget_show(buttonclose);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(w_current->clwindow)) {
  +    gtk_widget_show(w_current->clwindow);
  +  } else {
  +    gdk_window_raise(w_current->clwindow->window);
  +  }
  +}
  +
  +/***************** End of color edit dialog box *********************/
  +
  +/***************** Start of help/keymapping dialog box **************/
  +
  +/* limit this to 128 hotkeys */
  +static char *hotkey_strings[128];
  +static int hotkey_counter=0;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int x_dialog_hotkeys_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			      TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	x_dialog_hotkeys_close(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_dialog_hotkeys_close (GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  gtk_widget_destroy(w_current->hkwindow);
  +  w_current->hkwindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_dialog_hotkeys_free_all(void)
  +{
  +  int i;
  +
  +  for (i = 0 ; i < hotkey_counter; i++) {
  +    if (hotkey_strings[i]) {
  +      free(hotkey_strings[i]);
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_dialog_hotkeys_fill(char *string) 
  +{
  +
  +  if (hotkey_counter > 127) {
  +    printf(_("Ran out of space in the hotkey buffer...\n"));
  +    return;
  +  }	
  +
  +  hotkey_strings[hotkey_counter] = (char *) malloc(sizeof(char)*(
  +                                                                 strlen(string)+1));
  +  ;
  +  strcpy(hotkey_strings[hotkey_counter], string);
  +  hotkey_counter++;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_dialog_hotkeys (TOPLEVEL *w_current)
  +{
  +  GtkWidget *buttonclose = NULL;
  +  GtkWidget *vbox, *action_area, *scrolled_win, *list;
  +  GtkWidget *item;
  +  int i;
  +
  +  if (!w_current->hkwindow) {
  +
  +
  +    w_current->hkwindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position (GTK_WINDOW (w_current->hkwindow),
  +                         GTK_WIN_POS_MOUSE);
  +
  +    gtk_window_set_title (GTK_WINDOW (w_current->hkwindow),
  +                          _("Hotkeys..."));
  +    gtk_container_border_width (GTK_CONTAINER (
  +                                               w_current->hkwindow), 5);
  +
  +    gtk_widget_set_usize(w_current->hkwindow, 300,300);
  +
  +    gtk_signal_connect (GTK_OBJECT (w_current->hkwindow),
  +                        "destroy", GTK_SIGNAL_FUNC(destroy_window),
  +                        &w_current->hkwindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->hkwindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) x_dialog_hotkeys_keypress, w_current);
  +
  +#if 0 /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect (GTK_OBJECT (w_current->hkwindow),
  +                        "delete_event",
  +                        GTK_SIGNAL_FUNC(destroy_window),
  +                        &w_current->hkwindow);
  +#endif
  +
  +    scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  +    gtk_container_set_border_width (GTK_CONTAINER (scrolled_win), 5);
  +    gtk_widget_set_usize (scrolled_win, -1, 300);
  +    gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
  +    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
  +                                    GTK_POLICY_AUTOMATIC,
  +                                    GTK_POLICY_AUTOMATIC);
  +    gtk_widget_show (scrolled_win);
  +
  +    list = gtk_list_new ();
  +    gtk_list_set_selection_mode (GTK_LIST (list), GTK_SELECTION_SINGLE);
  +    gtk_scrolled_window_add_with_viewport
  +      (GTK_SCROLLED_WINDOW (scrolled_win), list);
  +    gtk_container_set_focus_vadjustment
  +      (GTK_CONTAINER (list),
  +       gtk_scrolled_window_get_vadjustment
  +       (GTK_SCROLLED_WINDOW (scrolled_win)));
  +    gtk_container_set_focus_hadjustment
  +      (GTK_CONTAINER (list),
  +       gtk_scrolled_window_get_hadjustment
  +       (GTK_SCROLLED_WINDOW (scrolled_win)));
  +    gtk_widget_show(list);
  +
  +    item = gtk_list_item_new_with_label (
  +                                         _("Function : keystroke(s)"));
  +    gtk_container_add (GTK_CONTAINER (list), item);
  +    gtk_widget_show(item);
  +
  +    item = gtk_list_item_new_with_label (" ");
  +    gtk_container_add (GTK_CONTAINER (list), item);
  +    gtk_widget_show(item);
  +
  +    for (i = 0 ; i < hotkey_counter; i++) {
  +
  +      if (hotkey_strings[i]) {	
  +        item = gtk_list_item_new_with_label (
  +                                             hotkey_strings[i]);
  +        gtk_container_add (GTK_CONTAINER (list), item);
  +        gtk_widget_show(item);
  +      }
  +    }
  +
  +#ifdef HAS_GTK12
  +    buttonclose = gtk_button_new_with_label (_("Close"));
  +#else
  +    buttonclose = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonclose, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(
  +                       GTK_BOX(action_area),
  +                       buttonclose, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT (buttonclose), "clicked",
  +                       GTK_SIGNAL_FUNC(x_dialog_hotkeys_close),
  +                       w_current);
  +    gtk_widget_show(buttonclose);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(w_current->hkwindow)) {
  +    gtk_widget_show(w_current->hkwindow);
  +  } else {
  +    gdk_window_raise(w_current->hkwindow->window);
  +  }
  +}
  +
  +/***************** End of help/keymapping dialog box ****************/
  +
  +/*********** Start of misc support functions for dialog boxes *******/
  +extern GtkWidget *stwindow;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_dialog_raise_all(TOPLEVEL *w_current)
  +{
  +
  +#if 0 /* don't raise the log window */
  +  if (stwindow) {
  +    gdk_window_raise(stwindow->window);
  +  }
  +#endif
  +
  +  if(w_current->fowindow) {
  +    gdk_window_raise(w_current->fowindow->window);
  +  }
  +  if(w_current->fswindow) {
  +    gdk_window_raise(w_current->fswindow->window);
  +  }
  +  if(w_current->sowindow) {
  +    gdk_window_raise(w_current->sowindow->window);
  +  }
  +  if(w_current->aswindow) {
  +    gdk_window_raise(w_current->aswindow->window);
  +  }
  +  if(w_current->cswindow) {
  +    gdk_window_raise(w_current->cswindow->window);
  +  }
  +
  +#if 0 /* don't raise these windows ever */ 
  +  if(w_current->fileselect[FILESELECT].xfwindow) {
  +    gdk_window_raise(w_current->fileselect[FILESELECT].xfwindow->window);
  +  }
  +  if(w_current->fileselect[COMPSELECT].xfwindow) {
  +    gdk_window_raise(w_current->fileselect[COMPSELECT].xfwindow->window);
  +  }
  +#endif
  +
  +  if(w_current->pwindow) {
  +    gdk_window_raise(w_current->pwindow->window);
  +  }
  +  if(w_current->iwindow) {
  +    gdk_window_raise(w_current->iwindow->window);
  +  }
  +
  +#if 0 /* don't raise the page manager window */
  +  if(w_current->pswindow) {
  +    gdk_window_raise(w_current->pswindow->window);
  +  }
  +#endif
  +
  +  if(w_current->tiwindow) {
  +    gdk_window_raise(w_current->tiwindow->window);
  +  }
  +  if(w_current->tewindow) {
  +    gdk_window_raise(w_current->tewindow->window);
  +  }
  +  if(w_current->sewindow) {
  +    gdk_window_raise(w_current->sewindow->window);
  +  }
  +  if(w_current->exwindow) {
  +    gdk_window_raise(w_current->exwindow->window);
  +  }
  +  if(w_current->aawindow) {
  +    gdk_window_raise(w_current->aawindow->window);
  +  }
  +  if(w_current->mawindow) {
  +    gdk_window_raise(w_current->mawindow->window);
  +  }
  +  if(w_current->aewindow) {
  +    gdk_window_raise(w_current->aewindow->window);
  +  }
  +  if(w_current->trwindow) {
  +    gdk_window_raise(w_current->trwindow->window);
  +  }
  +  if(w_current->tswindow) {
  +    gdk_window_raise(w_current->tswindow->window);
  +  }
  +  if(w_current->abwindow) {
  +    gdk_window_raise(w_current->abwindow->window);
  +  }
  +  if(w_current->hkwindow) {
  +    gdk_window_raise(w_current->hkwindow->window);
  +  }
  +  if(w_current->cowindow) {
  +    gdk_window_raise(w_current->cowindow->window);
  +  }
  +  if(w_current->clwindow) {
  +    gdk_window_raise(w_current->clwindow->window);
  +  }
  +  if(w_current->ltwindow) {
  +    gdk_window_raise(w_current->ltwindow->window);
  +  }
  +  if(w_current->ftwindow) {
  +    gdk_window_raise(w_current->ftwindow->window);
  +  }
  +
  +}
  +
  +/*********** End of misc support functions for dialog boxes *******/
  +
  +/***************** Start of generic message dialog box *******************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void generic_msg_dialog (const char *msg)
  +{
  +  GtkWidget *dialog;
  +  
  +  dialog = gtk_message_dialog_new (NULL,
  +
  +
  +                                   GTK_DIALOG_MODAL
  +                                   | GTK_DIALOG_DESTROY_WITH_PARENT,
  +                                   GTK_MESSAGE_INFO,
  +                                   GTK_BUTTONS_OK,
  +                                   msg);
  +
  +  gtk_dialog_run (GTK_DIALOG (dialog));
  +  gtk_widget_destroy (dialog);
  +
  +}
  +
  +/***************** End of generic message dialog box *********************/
  +
  +/***************** Start of generic confirm dialog box *******************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int generic_confirm_dialog (const char *msg)
  +{
  +  GtkWidget *dialog;
  +  gint r;
  +
  +  dialog = gtk_message_dialog_new (NULL,
  +
  +
  +                                   GTK_DIALOG_MODAL
  +                                   | GTK_DIALOG_DESTROY_WITH_PARENT,
  +                                   GTK_MESSAGE_INFO,
  +                                   GTK_BUTTONS_OK_CANCEL,
  +                                   msg);
  +
  +  r = gtk_dialog_run (GTK_DIALOG (dialog));
  +  gtk_widget_destroy (dialog);
  +
  +  if (r ==  GTK_RESPONSE_OK)
  +    return 1;
  +  else 
  +    return 0;
  +}
  +
  +/***************** End of generic confirm dialog box *********************/
  +
  +/***************** Start of generic file select dialog box ***************/
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \warning
  + *   Caller must free returned character string.
  + */
  +char *generic_filesel_dialog (const char *msg, const char *templ, gint flags)
  +{
  +  GtkWidget *dialog;
  +  gchar *result = NULL, *folder, *seed;
  +  char *title;
  +  static gchar *path = NULL;
  +  static gchar *shortcuts = NULL;
  +
  +  /* Default to load if not specified.  Maybe this should cause an error. */ 
  +  if (! (flags & (FSB_LOAD | FSB_SAVE))) {
  +    flags = flags | FSB_LOAD;
  +  }
  +
  +  if (flags & FSB_LOAD) {
  +    title = g_strdup_printf("%s: Open", msg);
  +    dialog = gtk_file_chooser_dialog_new (title,
  +					  NULL,
  +					  GTK_FILE_CHOOSER_ACTION_OPEN,
  +					  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  +					  GTK_STOCK_OPEN, GTK_RESPONSE_OK,
  +					  NULL);
  +    /* Since this is a load dialog box, the file must exist! */
  +    flags = flags | FSB_MUST_EXIST;
  +
  +  } else {
  +    title = g_strdup_printf("%s: Save", msg);
  +    dialog = gtk_file_chooser_dialog_new (title,
  +					  NULL,
  +					  GTK_FILE_CHOOSER_ACTION_SAVE,
  +					  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  +					  GTK_STOCK_OPEN, GTK_RESPONSE_OK,
  +					  NULL);
  +  }
  +
  +  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
  +
  +  /* Pick the current default folder to look for files in */
  +  if (path && *path) {
  +    gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), path);
  +  }
  +
  +
  +  /* Pick the current template (*.rc) or default file name */
  +  if (templ && *templ) {
  +    if (flags & FSB_SAVE)  {
  +      gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), templ);
  +    } else {
  +      gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (dialog), templ);
  +    }
  +  }
  +
  +  
  +  if (shortcuts && *shortcuts) {
  +    printf ("shortcuts = \"%s\"\n", shortcuts);
  +    folder = g_strdup (shortcuts);
  +    seed = folder;
  +    while ((folder = strtok (seed, ":")) != NULL) {
  +      gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog),
  +					    folder, NULL);
  +      seed = NULL;
  +    }
  +  
  +    g_free (folder);
  +  }
  +
  +  if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
  +    result = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
  +    folder = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
  +    /*! \bug FIXME
  +    if (folder && path) {
  +      dup_string (path, folder);
  +      g_free (folder);
  +    }
  +    */
  +  }
  +  gtk_widget_destroy (dialog);
  +
  +  g_free (title);
  +
  +  return result;
  +
  +}
  +
  +/***************** End of generic file select dialog box *****************/
  +
  +/*********** Start of generic text input dialog box *******/
  +char generic_textstring[256] = "refdes=R";
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void generic_text_input_ok(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  char *string = NULL;
  +
  +  string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->tsentry));
  +  strncpy(generic_textstring, string, 256);
  +
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void generic_text_input_dialog(TOPLEVEL * w_current)
  +{
  +  int len;
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok = NULL;
  +  GtkWidget *vbox, *action_area;
  +
  +  if (!w_current->tswindow) {
  +    w_current->tswindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW(w_current->tswindow),
  +			GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "destroy",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +
  +
  +#if 0				/* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "delete_event",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW(w_current->tswindow),
  +			 _("Generic String"));
  +    gtk_container_border_width(GTK_CONTAINER(w_current->tswindow), 10);
  +
  +    label = gtk_label_new(_("Enter new string."));
  +    gtk_misc_set_padding(GTK_MISC(label), 20, 20);
  +    gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
  +    gtk_widget_show(label);
  +
  +    w_current->tsentry = gtk_entry_new_with_max_length(20);
  +    gtk_editable_select_region(GTK_EDITABLE(w_current->tsentry), 0, -1);
  +    gtk_box_pack_start(GTK_BOX(vbox), w_current->tsentry, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->tsentry), "activate",
  +		       GTK_SIGNAL_FUNC(generic_text_input_ok), w_current);
  +    gtk_widget_show(w_current->tsentry);
  +    gtk_widget_grab_focus(w_current->tsentry);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label(_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS(buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area), buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttonok), "clicked",
  +		       GTK_SIGNAL_FUNC(generic_text_input_ok), w_current);
  +    gtk_widget_show(buttonok);
  +    gtk_widget_grab_default(buttonok);
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(w_current->tswindow)) {
  +    len = strlen(generic_textstring);
  +    gtk_entry_set_text(GTK_ENTRY(w_current->tsentry), generic_textstring);
  +    gtk_entry_select_region(GTK_ENTRY(w_current->tsentry), 0, len);
  +    gtk_widget_show(w_current->tswindow);
  +    gtk_grab_add(w_current->tswindow);
  +  }
  +}
  +
  +/*********** End of generic text input dialog box *******/
  +
  +/*********** Start of find text dialog box *******/
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int find_text_keypress(GtkWidget * widget, GdkEventKey * event, 
  +		       TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	find_text_done(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +GtkWidget *checkdescend = NULL;
  +int start_find;
  +OBJECT *remember_page;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void find_text_ok(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  char *string = NULL;
  +  int done;
  +
  +  string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->tsentry));
  +
  +  /* descend = gtk_object_get_data(GTK_OBJECT(w_current->tsentry),"descend");*/
  +
  +  strncpy(generic_textstring, string, 256);
  +
  +  while (remember_page != w_current->page_current->object_head) {
  +    s_hierarchy_up(w_current, w_current->page_current->up);
  +  }
  +  done =
  +      o_edit_find_text(w_current, remember_page, string,
  +         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
  +          (checkdescend)),
  +         !start_find);
  +  if (done) {
  +    o_redraw_all_fast(w_current);
  +    gtk_grab_remove(w_current->tswindow);
  +    gtk_widget_destroy(w_current->tswindow);
  +    w_current->tswindow = NULL;
  +  }
  +  start_find = 0;
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void find_text_done(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void find_text_dialog(TOPLEVEL * w_current)
  +{
  +  int len;
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok = NULL;
  +  GtkWidget *buttondone = NULL;
  +  GtkWidget *vbox, *action_area;
  +  OBJECT *object = NULL;
  +
  +  start_find = 1;
  +  remember_page = w_current->page_current->object_head;
  +  if ((object = o_select_return_first_object(w_current)) != NULL) {
  +    if (object->type == OBJ_TEXT) {
  +      strncpy(generic_textstring, object->text->string, 256);
  +    }
  +  }
  +
  +
  +
  +  if (!w_current->tswindow) {
  +    w_current->tswindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW(w_current->tswindow),
  +			GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "destroy",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) find_text_keypress, w_current);
  +
  +#if 0				/* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "delete_event",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW(w_current->tswindow), _("Find text"));
  +    gtk_container_border_width(GTK_CONTAINER(w_current->tswindow), 10);
  +    gtk_box_set_spacing(GTK_BOX(vbox),10);
  +
  +    label = gtk_label_new(_("Text to find:"));
  +    gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
  +    gtk_widget_show(label);
  +
  +    w_current->tsentry = gtk_entry_new_with_max_length(20);
  +    gtk_editable_select_region(GTK_EDITABLE(w_current->tsentry), 0, -1);
  +    gtk_box_pack_start(GTK_BOX(vbox), w_current->tsentry, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->tsentry), "activate",
  +		       GTK_SIGNAL_FUNC(find_text_ok), w_current);
  +    gtk_widget_show(w_current->tsentry);
  +    gtk_widget_grab_focus(w_current->tsentry);
  +
  +    checkdescend =
  +	gtk_check_button_new_with_label(_("descend into hierarchy"));
  +    /*          gtk_object_set_data (GTK_OBJECT (w_current->tswindow), "descend", w_current->preview_checkbox);*/
  +    gtk_box_pack_start(GTK_BOX(vbox), checkdescend, TRUE, TRUE, 0);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label(_("Find"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_FIND);
  +#endif
  +    GTK_WIDGET_SET_FLAGS(buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area), buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttonok), "clicked",
  +		       GTK_SIGNAL_FUNC(find_text_ok), w_current);
  +
  +#ifdef HAS_GTK12
  +    buttondone = gtk_button_new_with_label(_("Done"));
  +#else
  +    buttondone = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +    GTK_WIDGET_SET_FLAGS(buttondone, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area), buttondone, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttondone), "clicked",
  +		       GTK_SIGNAL_FUNC(find_text_done), w_current);
  +
  +
  +
  +    gtk_widget_show(buttonok);
  +    gtk_widget_show(buttondone);
  +    gtk_widget_show(checkdescend);
  +    gtk_widget_grab_default(buttonok);
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(w_current->tswindow)) {
  +    len = strlen(generic_textstring);
  +    gtk_entry_set_text(GTK_ENTRY(w_current->tsentry), generic_textstring);
  +    gtk_entry_select_region(GTK_ENTRY(w_current->tsentry), 0, len);
  +    gtk_widget_show(w_current->tswindow);
  +    gtk_grab_add(w_current->tswindow);
  +  }
  +}
  +
  +/*********** End of find text dialog box *******/
  +
  +/*********** Start of hide text dialog box *******/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int hide_text_keypress(GtkWidget * widget, GdkEventKey * event, 
  +		       TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	hide_text_done(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void hide_text_ok(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  char *string = NULL;
  +
  +  string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->tsentry));
  +  strncpy(generic_textstring, string, 256);
  +
  +  o_edit_hide_specific_text(w_current,
  +			    w_current->page_current->object_head, string);
  +
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void hide_text_done(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void hide_text_dialog(TOPLEVEL * w_current)
  +{
  +  int len;
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok = NULL;
  +  GtkWidget *vbox, *action_area;
  +
  +  if (!w_current->tswindow) {
  +    w_current->tswindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW(w_current->tswindow),
  +			GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "destroy",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) hide_text_keypress, w_current);
  +
  +#if 0				/* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "delete_event",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW(w_current->tswindow), _("Hide text"));
  +    gtk_container_border_width(GTK_CONTAINER(w_current->tswindow), 10);
  +
  +    label = gtk_label_new(_("Hide text starting with:"));
  +    gtk_misc_set_padding(GTK_MISC(label), 20, 20);
  +    gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
  +    gtk_widget_show(label);
  +
  +    w_current->tsentry = gtk_entry_new_with_max_length(20);
  +    gtk_editable_select_region(GTK_EDITABLE(w_current->tsentry), 0, -1);
  +    gtk_box_pack_start(GTK_BOX(vbox), w_current->tsentry, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->tsentry), "activate",
  +		       GTK_SIGNAL_FUNC(hide_text_ok), w_current);
  +    gtk_widget_show(w_current->tsentry);
  +    gtk_widget_grab_focus(w_current->tsentry);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label(_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS(buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area), buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttonok), "clicked",
  +		       GTK_SIGNAL_FUNC(hide_text_ok), w_current);
  +    gtk_widget_show(buttonok);
  +    gtk_widget_grab_default(buttonok);
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(w_current->tswindow)) {
  +    len = strlen(generic_textstring);
  +    gtk_entry_set_text(GTK_ENTRY(w_current->tsentry), generic_textstring);
  +    gtk_entry_select_region(GTK_ENTRY(w_current->tsentry), 0, len);
  +    gtk_widget_show(w_current->tswindow);
  +    gtk_grab_add(w_current->tswindow);
  +  }
  +}
  +
  +/*********** End of hide text dialog box *******/
  +
  +/*********** Start of show text dialog box *******/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int show_text_keypress(GtkWidget * widget, GdkEventKey * event, 
  +		       TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	show_text_done(NULL, w_current);	
  +        return TRUE;
  +   }
  +
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void show_text_ok(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  char *string = NULL;
  +
  +  string = (char *) gtk_entry_get_text(GTK_ENTRY(w_current->tsentry));
  +  strncpy(generic_textstring, string, 256);
  +
  +  o_edit_show_specific_text(w_current,
  +			    w_current->page_current->object_head, string);
  +
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void show_text_done(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void show_text_dialog(TOPLEVEL * w_current)
  +{
  +  int len;
  +  GtkWidget *label = NULL;
  +  GtkWidget *buttonok = NULL;
  +  GtkWidget *vbox, *action_area;
  +
  +  if (!w_current->tswindow) {
  +    w_current->tswindow = x_create_dialog_box(&vbox, &action_area);
  +
  +    gtk_window_position(GTK_WINDOW(w_current->tswindow),
  +			GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "destroy",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +                     "key_press_event",
  +                     (GtkSignalFunc) show_text_keypress, w_current);
  +
  +#if 0				/* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "delete_event",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW(w_current->tswindow), _("Show text"));
  +    gtk_container_border_width(GTK_CONTAINER(w_current->tswindow), 10);
  +
  +    label = gtk_label_new(_("Show text starting with:"));
  +    gtk_misc_set_padding(GTK_MISC(label), 20, 20);
  +    gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
  +    gtk_widget_show(label);
  +
  +    w_current->tsentry = gtk_entry_new_with_max_length(20);
  +    gtk_editable_select_region(GTK_EDITABLE(w_current->tsentry), 0, -1);
  +    gtk_box_pack_start(GTK_BOX(vbox), w_current->tsentry, FALSE, FALSE, 5);
  +    gtk_signal_connect(GTK_OBJECT(w_current->tsentry), "activate",
  +		       GTK_SIGNAL_FUNC(show_text_ok), w_current);
  +    gtk_widget_show(w_current->tsentry);
  +    gtk_widget_grab_focus(w_current->tsentry);
  +
  +#ifdef HAS_GTK12
  +    buttonok = gtk_button_new_with_label(_("OK"));
  +#else
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS(buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area), buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttonok), "clicked",
  +		       GTK_SIGNAL_FUNC(show_text_ok), w_current);
  +    gtk_widget_show(buttonok);
  +    gtk_widget_grab_default(buttonok);
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(w_current->tswindow)) {
  +    len = strlen(generic_textstring);
  +    gtk_entry_set_text(GTK_ENTRY(w_current->tsentry), generic_textstring);
  +    gtk_entry_select_region(GTK_ENTRY(w_current->tsentry), 0, len);
  +    gtk_widget_show(w_current->tswindow);
  +    gtk_grab_add(w_current->tswindow);
  +  }
  +}
  +
  +/*********** End of show text dialog box *******/
  +
  +/*********** Start of autonumber text dialog box *******/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int autonumber_text_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			     TOPLEVEL * w_current)
  +{
  +   if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +	autonumber_text_done(NULL, w_current);	
  +        return TRUE;
  +   }
  +   if (strcmp(gdk_keyval_name(event->keyval), "Return") == 0) {
  +	autonumber_text_ok(NULL, w_current);	
  +        return TRUE;
  +   }
  +   return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void autonumber_text_ok(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  char *searchtext = NULL;
  +  char *startnumber = NULL;
  +  int sortorder, searchfocus, unnumbered, startnumber_i=1;
  +  GtkWidget * widget;
  +  
  +  widget = g_object_get_data (G_OBJECT (w_current->tswindow), "searchtext");
  +  searchtext = (char *) gtk_entry_get_text(GTK_ENTRY(widget));
  +  strncpy(generic_textstring, searchtext, 256); /* ???????? */
  +
  +  widget = g_object_get_data (G_OBJECT (w_current->tswindow), "startnumber");
  +  startnumber = (char *) gtk_entry_get_text(GTK_ENTRY(widget));
  +  sscanf(startnumber," %d",&startnumber_i);
  +
  +  widget = g_object_get_data (G_OBJECT (w_current->tswindow), "searchfocus");
  +  searchfocus = (int) gtk_option_menu_get_history (GTK_OPTION_MENU(widget));
  +
  +  widget = g_object_get_data (G_OBJECT (w_current->tswindow), "unnumbered");
  +  unnumbered = (int) gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
  +
  +  widget = g_object_get_data (G_OBJECT (w_current->tswindow), "sortorder");
  +  sortorder = (int) gtk_option_menu_get_history(GTK_OPTION_MENU(widget));
  +
  +  if (startnumber_i < 0) {  /* disallow negativ numbers */
  +    fprintf(stderr, _("Warning: negative numbers not allowed in the "
  +		      "autonumber_text dialog\n"));
  +    return;
  +  }
  +
  +  /*  printf("autonumber_text_ok: searchtext: %s\n"
  +	 "   startnumber: %i\n   searchfocus: %i\n"
  +	 "   unnumbered: %i\n   sortorder: %i\n" ,searchtext,
  +	 startnumber_i, searchfocus, unnumbered, sortorder); */
  +  o_edit_autonumber_text(w_current, searchtext, startnumber_i, searchfocus, 
  +			 unnumbered, sortorder);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void autonumber_text_done(GtkWidget * w, TOPLEVEL * w_current)
  +{
  +  gtk_grab_remove(w_current->tswindow);
  +  gtk_widget_destroy(w_current->tswindow);
  +  w_current->tswindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void autonumber_text_dialog(TOPLEVEL * w_current)
  +{
  +  GtkWidget *vbox, *action_area;
  +  GtkWidget *frame1; /* selection frame */
  +  GtkWidget *label1;
  +  GtkWidget *table1;
  +  GtkWidget *label1_1, *label1_2;
  +  GtkWidget *combo1;
  +  GList *combo1_items = NULL;
  +  GtkWidget *combo_entry1;
  +
  +  GtkWidget *optionmenu1_2, *menu1_2;
  +  GtkWidget *option_selection1, *option_selection2, *option_selection3;
  +  GtkWidget *hbox1;  /* contains radio buttons */
  +  GtkWidget *radiobutton1;
  +  GtkWidget *radiobutton2;
  +
  +  GtkWidget *frame2; /* option frame */
  +  GtkWidget *label2;
  +  GtkWidget *table2;
  +  GtkWidget *label2_1, *label2_2;
  +  GtkWidget *entry2;
  +  GtkWidget *optionmenu2_1, *menu2_1;
  +  GtkWidget *option_order1, *option_order2, *option_order3, *option_order4;
  +
  +  GtkWidget *buttonok = NULL;
  +  GtkWidget *buttoncancel = NULL;
  +
  +  if (!w_current->tswindow) {
  +    w_current->tswindow = gtk_dialog_new();
  +    vbox=GTK_DIALOG(w_current->tswindow)->vbox;
  +    action_area=GTK_DIALOG(w_current->tswindow)->action_area;
  +
  +    gtk_window_position(GTK_WINDOW(w_current->tswindow),
  +			GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "destroy",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +                       "key_press_event",
  +                       (GtkSignalFunc) autonumber_text_keypress, 
  +		       w_current);
  +
  +#if 0	   /* removed because it was causing the dialog box to not close */
  +    gtk_signal_connect(GTK_OBJECT(w_current->tswindow),
  +		       "delete_event",
  +		       GTK_SIGNAL_FUNC(destroy_window),
  +		       &w_current->tswindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW(w_current->tswindow),
  +			 _("Autonumber text"));
  +
  +    /* selection frame */
  +    frame1 = gtk_frame_new(NULL);
  +    gtk_widget_show (frame1);
  +    gtk_box_pack_start (GTK_BOX(vbox), frame1, TRUE, TRUE, 0);
  +    label1 = gtk_label_new (_("selection"));
  +    gtk_widget_show (label1);
  +    gtk_frame_set_label_widget (GTK_FRAME(frame1), label1);
  +
  +    table1 = gtk_table_new(2,3,FALSE);
  +    gtk_widget_show (table1);
  +    gtk_container_add (GTK_CONTAINER(frame1), table1);
  +
  +    /* search text section */
  +    label1_1 = gtk_label_new (_("search text"));
  +    gtk_widget_show (label1_1);
  +    gtk_table_attach (GTK_TABLE (table1), label1_1, 0, 1, 0, 1,
  +		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
  +		      (GtkAttachOptions) (0), 0, 0);
  +
  +    combo1 = gtk_combo_new ();
  +    /* g_object_set_data (G_OBJECT (GTK_COMBO (combo1)->popwin),
  +       "GladeParentKey", combo1);*/
  +    gtk_widget_show (combo1);
  +    gtk_table_attach (GTK_TABLE (table1), combo1, 1, 2, 0, 1,
  +		      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
  +		      (GtkAttachOptions) (0), 0, 0);
  +    /* gtk_combo_set_value_in_list (GTK_COMBO (combo1), TRUE, TRUE);*/
  +    combo1_items = g_list_append (combo1_items, (gpointer) "refdes=C");
  +    combo1_items = g_list_append (combo1_items, (gpointer) "refdes=Q");
  +    combo1_items = g_list_append (combo1_items, (gpointer) "refdes=R");
  +    combo1_items = g_list_append (combo1_items, (gpointer) "refdes=U");
  +    combo1_items = g_list_append (combo1_items, (gpointer) "refdes=X");
  +    gtk_combo_set_popdown_strings (GTK_COMBO (combo1), combo1_items);
  +    g_list_free (combo1_items);
  +
  +    combo_entry1 = GTK_COMBO (combo1)->entry;
  +    gtk_widget_show (combo_entry1);
  +    gtk_entry_set_text (GTK_ENTRY (combo_entry1), "refdes=C");	
  +    GLADE_HOOKUP_OBJECT(w_current->tswindow,combo_entry1,"searchtext");
  +
  +    /* search focus section */
  +    label1_2 = gtk_label_new (_("search focus"));
  +    gtk_widget_show (label1_2);
  +    gtk_table_attach (GTK_TABLE (table1), label1_2, 0, 1, 1, 2,
  +		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
  +		      (GtkAttachOptions) (0), 0, 0);
  +
  +    optionmenu1_2 = gtk_option_menu_new ();
  +    gtk_widget_show (optionmenu1_2);
  +    gtk_table_attach (GTK_TABLE (table1), optionmenu1_2, 1, 2, 1, 2,
  +		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
  +		      (GtkAttachOptions) (0), 0, 0);
  +
  +    menu1_2 = gtk_menu_new();
  +    option_selection1 = gtk_menu_item_new_with_label (_("selected objects"));
  +    gtk_widget_show (option_selection1);
  +    gtk_container_add (GTK_CONTAINER (menu1_2), option_selection1);
  +    option_selection2 = gtk_menu_item_new_with_label (_("current sheet"));
  +    gtk_widget_show (option_selection2);
  +    gtk_container_add (GTK_CONTAINER (menu1_2), option_selection2);
  +    option_selection3 = gtk_menu_item_new_with_label (_("hierarchical sheets"));
  +    gtk_widget_show (option_selection3);
  +    gtk_container_add (GTK_CONTAINER (menu1_2), option_selection3);
  +    gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu1_2), menu1_2);
  +    GLADE_HOOKUP_OBJECT(w_current->tswindow,optionmenu1_2,"searchfocus");
  +
  +    /* radio buttons */
  +    hbox1=gtk_hbox_new (FALSE,0);
  +    gtk_widget_show (hbox1);
  +    gtk_table_attach (GTK_TABLE (table1), hbox1, 0, 2, 2, 3,
  +		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
  +		      (GtkAttachOptions) (0), 0, 0);
  +    radiobutton1 = gtk_radio_button_new_with_label (NULL, _("unnumbered"));
  +    gtk_widget_show (radiobutton1);
  +    gtk_box_pack_start (GTK_BOX (hbox1), radiobutton1, TRUE, TRUE, 0);
  +    radiobutton2 = gtk_radio_button_new_with_label_from_widget(
  +		     GTK_RADIO_BUTTON (radiobutton1), _("all"));
  +    gtk_widget_show (radiobutton2);
  +    gtk_box_pack_start (GTK_BOX (hbox1), radiobutton2, TRUE, TRUE, 0);
  +    GLADE_HOOKUP_OBJECT(w_current->tswindow,radiobutton1,"unnumbered");
  +
  +    /* option frame */
  +    frame2=gtk_frame_new(NULL);
  +    gtk_widget_show(frame2);
  +    gtk_box_pack_start (GTK_BOX(vbox), frame2, TRUE, TRUE, 0);
  +    label2 = gtk_label_new (_("options"));
  +    gtk_widget_show (label2);
  +    gtk_frame_set_label_widget (GTK_FRAME(frame2), label2);
  +    
  +    table2 = gtk_table_new(2,2,FALSE);
  +    gtk_widget_show(table2);
  +    gtk_container_add (GTK_CONTAINER (frame2),table2);
  +    label2_1=gtk_label_new(_("start number"));
  +    gtk_widget_show(label2_1);
  +    gtk_table_attach (GTK_TABLE (table2), label2_1, 0, 1, 0, 1,
  +		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
  +		      (GtkAttachOptions) (0), 0, 0);
  +    entry2=gtk_entry_new();
  +    gtk_entry_set_text(GTK_ENTRY(entry2), "1");
  +    gtk_widget_show(entry2);
  +    gtk_table_attach (GTK_TABLE (table2), entry2, 1, 2, 0, 1,
  +		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
  +		      (GtkAttachOptions) (0), 0, 0);
  +    GLADE_HOOKUP_OBJECT(w_current->tswindow,entry2,"startnumber");
  +
  +    label2_2=gtk_label_new(_("sort order"));
  +    gtk_widget_show(label2_2);
  +    gtk_table_attach (GTK_TABLE (table2), label2_2, 0, 1, 1, 2,
  +		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
  +		      (GtkAttachOptions) (0), 0, 0);
  +
  +    optionmenu2_1 = gtk_option_menu_new ();
  +    gtk_widget_show (optionmenu2_1);
  +    gtk_table_attach (GTK_TABLE (table2), optionmenu2_1, 1, 2, 1, 2,
  +		      (GtkAttachOptions) (GTK_FILL|GTK_EXPAND),
  +		      (GtkAttachOptions) (0), 0, 0);
  +    menu2_1 = gtk_menu_new();
  +    option_order1 = gtk_menu_item_new_with_label (_("file order"));
  +    gtk_widget_show (option_order1);
  +    gtk_container_add (GTK_CONTAINER (menu2_1), option_order1);
  +    option_order2 = gtk_menu_item_new_with_label (_("top down"));
  +    gtk_widget_show (option_order2);
  +    gtk_container_add (GTK_CONTAINER (menu2_1), option_order2);
  +    option_order3 = gtk_menu_item_new_with_label (_("left right"));
  +    gtk_widget_show (option_order3);
  +    gtk_container_add (GTK_CONTAINER (menu2_1), option_order3);
  +    option_order4 = gtk_menu_item_new_with_label (_("diagonal"));
  +    gtk_widget_show (option_order4);
  +    gtk_container_add (GTK_CONTAINER (menu2_1), option_order4);
  +    gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu2_1), menu2_1);
  +    GLADE_HOOKUP_OBJECT(w_current->tswindow,optionmenu2_1,"sortorder");
  +    
  +    /* Why is the entry attached to w_current ?? (Werner) */
  +    w_current->tsentry = combo_entry1;
  +
  +    buttonok = gtk_button_new_from_stock (GTK_STOCK_APPLY);
  +    GTK_WIDGET_SET_FLAGS(buttonok, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area), buttonok, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttonok), "clicked",
  +		       GTK_SIGNAL_FUNC(autonumber_text_ok), w_current);
  +    gtk_widget_show(buttonok);
  +    gtk_widget_grab_default(buttonok);
  +
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +    gtk_box_pack_start(GTK_BOX(action_area), buttoncancel, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttoncancel), "clicked",
  +		       GTK_SIGNAL_FUNC(autonumber_text_done), w_current);
  +    gtk_widget_show(buttoncancel);
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(w_current->tswindow)) {
  +    gtk_entry_set_text(GTK_ENTRY(w_current->tsentry), generic_textstring);
  +    gtk_entry_select_region(GTK_ENTRY(w_current->tsentry),
  +			    0,strlen(generic_textstring));
  +    gtk_widget_show(w_current->tswindow);
  +    gtk_grab_add(w_current->tswindow);
  +  }
  +}
  +
  +/*********** End of autonumber text dialog box *******/
  +
  +/*********** Start of some Gtk utils  *******/
  +#ifdef HAS_GTK22
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void select_all_text_in_textview(GtkTextView *textview) 
  +{
  +  GtkTextBuffer *textbuffer;
  +  GtkTextIter start, end;
  +  GtkTextMark *mark;
  +	
  +  textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
  +  gtk_text_buffer_get_bounds (textbuffer, &start, &end);
  +  gtk_text_buffer_place_cursor(textbuffer, &start);
  +  mark = gtk_text_buffer_get_selection_bound(textbuffer);
  +  gtk_text_buffer_move_mark(textbuffer, mark, &end);
  +}
  +#endif
  +
  +#ifdef HAS_GTK22
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int text_view_calculate_real_tab_width(GtkTextView *textview, int tab_size) 
  +{
  +  PangoLayout *layout;
  +  gchar *tab_string;
  +  gint counter = 0;
  +  gint tab_width = 0;
  +
  +  if (tab_size == 0)
  +  return -1;
  +
  +  tab_string = g_malloc (tab_size + 1);
  +
  +  while (counter < tab_size) {
  +    tab_string [counter] = ' ';
  +    counter++;
  +  }
  +
  +  tab_string [tab_size] = 0;
  +
  +  layout = gtk_widget_create_pango_layout (
  +                                           GTK_WIDGET (textview), 
  +                                           tab_string);
  +  g_free (tab_string);
  +
  +  if (layout != NULL) {
  +    pango_layout_get_pixel_size (layout, &tab_width, NULL);
  +    g_object_unref (G_OBJECT (layout));
  +  } else
  +  tab_width = -1;
  +
  +  return tab_width;
  +
  +}
  +#endif
  +
  +/*********** End of some Gtk utils *******/
  +
  +/*********** Start of major symbol changed dialog box *******/
  +#ifdef HAS_GTK12
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void quick_message_dialog(char *message)
  +{
  +  GtkWidget *dialog, *label, *close_button;
  +   
  +  /* Create the widgets */
  +   
  +  dialog = gtk_dialog_new();
  +  label = gtk_label_new (message);
  +#ifdef HAS_GTK12
  +  close_button = gtk_button_new_with_label("Close");
  +#else
  +  close_button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +   
  +  /* Ensure that the dialog box is destroyed when the user clicks ok. */
  +   
  +  gtk_signal_connect_object (GTK_OBJECT (close_button), "clicked",
  +                             GTK_SIGNAL_FUNC (gtk_widget_destroy), 
  +                             (gpointer) dialog);
  +  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area),
  +                     close_button);
  +
  +  /* Add the label, and show everything we've added to the dialog. */
  +
  +  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox),
  +                     label);
  +  gtk_widget_show_all (dialog);
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void major_changed_dialog(TOPLEVEL* w_current)
  +{
  +  GtkWidget* dialog;
  +  char* refdes_string = NULL;
  +  char* tmp;
  +
  +  if (w_current->major_changed_refdes) {
  +
  +    GList* current = w_current->major_changed_refdes;
  +    while (current)
  +    {
  +      char *value = (char*) current->data;
  +
  +      if (!refdes_string)
  +      {
  +        refdes_string = g_strdup (value);
  +      } else {
  +        tmp = g_strconcat (refdes_string, "\n", value, NULL);
  +        free(refdes_string);
  +        refdes_string = tmp;
  +      }
  +      
  +      current = current->next;
  +    }
  +
  +    tmp = g_strconcat (refdes_string, 
  +                       "\n\nBe sure to verify each of these symbols!", 
  +                       NULL);
  +    free(refdes_string);
  +    refdes_string = tmp;
  +
  +#ifdef HAS_GTK22
  +    dialog = gtk_message_dialog_new ((GtkWindow*) w_current->main_window,
  +                                     GTK_DIALOG_DESTROY_WITH_PARENT,
  +                                     GTK_MESSAGE_ERROR,
  +                                     GTK_BUTTONS_CLOSE,
  +                        "Major symbol changes detected in refdes:\n\n%s\n",
  +                                     refdes_string);
  +
  +    gtk_widget_show(dialog);
  +
  +    g_signal_connect_swapped (dialog, "response",
  +                              G_CALLBACK (gtk_widget_destroy),
  +                              dialog);
  +#else
  +    tmp = g_strconcat(
  +      "\n  Major symbol changes detected in refdes:  \n\n", 
  +      refdes_string, 
  +      NULL);
  +    free(refdes_string);
  +    refdes_string = tmp;
  +    quick_message_dialog(refdes_string);
  +#endif
  +
  +    if (refdes_string) free(refdes_string);
  +  }
  +}
  +
  +/*********** End of major symbol changed dialog box *******/
  
  
  
  1.34      +1390 -1029eda/geda/gaf/gschem/src/x_event.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_event.c
  ===================================================================
  RCS file: x_event.c
  diff -N x_event.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_event.c	14 Jul 2006 02:23:55 -0000	1.34
  @@ -0,0 +1,1587 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <math.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/* used in key_press, since it isn't passed this information */
  +/* filled in x_event_motion */
  +int mouse_x, mouse_y;
  +
  +/* used by mouse pan */
  +extern int current_center_x, current_center_y;
  +int start_pan_x, start_pan_y;
  +int throttle = 0;
  +
  +/* used for the stroke stuff */
  +#ifdef HAS_LIBSTROKE
  +
  +#define MAX_SEQUENCE 20
  +static int DOING_STROKE = FALSE;
  +char sequence[MAX_SEQUENCE+1];
  +
  +/* libstroke prototypes */
  +void stroke_init (void);
  +void stroke_record (int x, int y);
  +int stroke_trans (char *sequence);
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_event_expose(GtkWidget *widget, GdkEventExpose *event,
  +		    TOPLEVEL *w_current)
  +{
  +#if DEBUG
  +  printf("EXPOSE\n");
  +#endif
  +
  +  exit_if_null(w_current);
  +  /* nasty global variable */
  +  global_window_current = (TOPLEVEL *) w_current;
  +
  +  gdk_draw_pixmap(widget->window,
  +                  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
  +                  w_current->backingstore,
  +                  event->area.x, event->area.y,
  +                  event->area.x, event->area.y,
  +                  event->area.width, event->area.height);
  +
  +  /* either this or put xor's and friends into backingstore */
  +  /* take care of ghosting when you get an expose event */
  +  if (w_current->inside_action) {
  +    switch(w_current->event_state) {
  +      case(MOVE):
  +      case(ENDMOVE):
  +      case(COPY): 
  +      case(ENDCOPY):
  +      case(ENDMCOPY):
  +        o_drawbounding(w_current, NULL,
  +                       w_current->page_current->selection2_head->next,
  +                       x_get_darkcolor(w_current->bb_color), FALSE);
  +        break;
  +      case(DRAWCOMP):
  +      case(ENDCOMP):
  +      case(ENDPASTE):
  + 	 o_drawbounding(w_current, 
  +		       w_current->page_current->complex_place_head->next,
  +                       NULL,
  +                       x_get_darkcolor(w_current->bb_color), FALSE); 
  +        break;
  +
  +      case(BUSCONT):
  +      case(DRAWBUS):
  +	 o_bus_xorrubber(w_current);  
  +        break;
  +      case(DRAWNET):   
  +      case(NETCONT):
  +	 o_net_xorrubber(w_current); 
  +        break;
  +      case(ENDARC): 
  +	 o_arc_rubberarc_xor(w_current); 
  +        break;
  +      case(ENDATTRIB): /*! \todo how to test ??? */
  +	 o_attrib_rubberattrib(w_current);
  +        break;
  +      case(ENDBOX):
  +	 o_box_rubberbox_xor(w_current); 
  +        break;
  +      case(ENDCIRCLE):
  +	 o_circle_rubbercircle_xor(w_current); 
  +        break;
  +      case(ENDLINE): 
  +	 o_line_rubberline_xor(w_current); 
  +        break;
  +      case(ENDPIN): /*! \todo (no function in o_pin.nw available) */
  +        break;
  +      case(ENDTEXT): 
  +	 o_text_rubberattrib(w_current);
  +        break;
  +      case(GRIPS): /*! \todo (larger changes in o_grips.nw necessary) */
  +        break;
  +      case(ZOOMBOXEND): /*! \todo (not realy a problem as zoom will redraw) */
  +        break;
  +    }
  +  }
  +
  +  /* raise the dialog boxes if this feature is enabled */
  +  if (w_current->raise_dialog_boxes) {
  +    x_dialog_raise_all(w_current);
  +  }
  +
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_event_button_pressed(GtkWidget *widget, GdkEventButton *event,
  +			    TOPLEVEL *w_current)
  +{
  +  int prev_state; 
  +
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +
  +#if DEBUG
  +  printf("pressed button %d! \n", event->button);
  +  printf("event state: %d \n", event->state);
  +  printf("w_current state: %d \n", w_current->event_state);
  +  printf("Selection is:\n");
  +  o_selection_print_all( w_current->page_current->selection2_head);
  +  printf("\n");
  +#endif
  +
  +  if (event->type == GDK_2BUTTON_PRESS && 
  +      (w_current->event_state == STARTSELECT || 
  +       w_current->event_state == SELECT)) {
  +    o_find_object(w_current, (int) event->x, (int) event->y, TRUE);
  +    if (w_current->page_current->selection2_head->next) {
  +       o_edit(w_current, w_current->page_current->selection2_head->next);
  +       return(0);
  +    }
  +  }
  +
  +  w_current->SHIFTKEY   = (event->state & GDK_SHIFT_MASK  ) ? 1 : 0;
  +  w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0;
  +  w_current->ALTKEY     = (event->state & GDK_MOD1_MASK) ? 1 : 0;
  +
  +  if (event->button == 1) {
  +    switch(w_current->event_state) {
  +
  +      case(SELECT):
  +        /* look for grips or fall through if not enabled */
  +        if (!o_grips_start(
  +                           w_current, (int) event->x, (int) event->y)) {
  +				/* now go into normal SELECT */
  +	  w_current->event_state = STARTSELECT;
  +	  w_current->start_x = w_current->last_x =
  +	    (int) event->x;
  +	  w_current->start_y = w_current->last_y =
  +	    (int) event->y;
  +        } else {
  +				/* a grip was found */
  +          w_current->event_state = GRIPS;
  +          w_current->inside_action = 1;
  +        }
  +        break;
  +
  +      case(STARTCOPY):
  +        if (o_select_selected(w_current)) {
  +	  w_current->rotated_inside = 0;
  +          o_copy_start(w_current, 
  +                       (int) event->x, (int) event->y);
  +          w_current->event_state = COPY;
  +          w_current->inside_action = 1;
  +        }
  +        break;
  +
  +      case(STARTMCOPY):
  +        if (o_select_selected(w_current)) {
  +	  w_current->rotated_inside = 0;
  +          o_copy_start(w_current, 
  +                       (int) event->x, (int) event->y);
  +          w_current->event_state = MCOPY;
  +          w_current->inside_action = 1;
  +        }
  +        break;
  +
  +      case(STARTMOVE):
  +        if (o_select_selected(w_current)) {
  +	  w_current->rotated_inside = 0;
  +          o_move_start(w_current,
  +                       (int) event->x, (int) event->y);
  +          w_current->event_state = MOVE;
  +          w_current->inside_action = 1;
  +        }
  +        break;
  +
  +      case(STARTPASTE):
  +        o_buffer_paste_start(w_current, 
  +                             (int) event->x,
  +                             (int) event->y,
  +                             w_current->buffer_number);
  +        w_current->event_state = ENDPASTE;
  +        w_current->inside_action = 1;
  +        break;
  +
  +      case(DRAWLINE):
  +        o_line_start(w_current,
  +                     (int) event->x,
  +                     (int) event->y);
  +        w_current->event_state = ENDLINE;
  +        w_current->inside_action = 1;
  +        break;
  +
  +      case(ENDLINE):
  +        o_line_end(w_current,
  +                   (int) event->x,
  +                   (int) event->y);
  +        w_current->inside_action = 0;
  +        w_current->event_state = DRAWLINE;
  +        break;
  +
  +      case(DRAWBOX):
  +        o_box_start(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +        w_current->event_state = ENDBOX;
  +        w_current->inside_action = 1;
  +        break;
  +
  +      case(ENDBOX):
  +        o_box_end(w_current,
  +                  (int) event->x,
  +                  (int) event->y);
  +        w_current->inside_action = 0;
  +        w_current->event_state = DRAWBOX;
  +        break;
  +
  +      case(DRAWPICTURE):
  +#ifndef HAS_GTK12
  +        o_picture_start(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +        w_current->event_state = ENDPICTURE;
  +        w_current->inside_action = 1;
  +#endif
  +        break;
  +
  +      case(ENDPICTURE):
  +#ifndef HAS_GTK12
  +        o_picture_end(w_current,
  +                  (int) event->x,
  +                  (int) event->y);
  +        w_current->inside_action = 0;
  +        w_current->event_state = DRAWPICTURE;
  +#endif
  +        break;
  +
  +      case(DRAWCIRCLE):
  +        o_circle_start(w_current,
  +                       (int) event->x,
  +                       (int) event->y);
  +        w_current->event_state = ENDCIRCLE;
  +        w_current->inside_action = 1;
  +        break;
  +
  +      case(ENDCIRCLE):
  +        o_circle_end(w_current,
  +                     (int) event->x,
  +                     (int) event->y);
  +        w_current->inside_action = 0;
  +        w_current->event_state = DRAWCIRCLE;
  +        break;
  +
  +      case(DRAWARC):
  +        o_arc_start(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +        w_current->event_state = ENDARC;
  +        w_current->inside_action = 1;
  +        break;
  +
  +      case(ENDARC):
  +        o_arc_end1(w_current,
  +                   (int) event->x,
  +                   (int) event->y);
  +        w_current->inside_action = 0;
  +        w_current->event_state = DRAWARC;
  +        break;
  +
  +      case(DRAWPIN):
  +        o_pin_start(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +        w_current->event_state = ENDPIN;
  +        w_current->inside_action = 1;
  +        break;
  +
  +      case(ENDPIN):
  +        o_pin_end(w_current,
  +                  (int) event->x,
  +                  (int) event->y);
  +        w_current->inside_action = 0;
  +        w_current->event_state = DRAWPIN;
  +        break;
  +
  +      case(STARTDRAWNET):  /*! \todo change state name? */
  +        o_net_start(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +        w_current->inside_action = 1;
  +        w_current->event_state=DRAWNET;
  +
  +        break;
  +
  +      case(STARTDRAWBUS):  
  +        o_bus_start(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +        w_current->inside_action = 1;
  +        w_current->event_state=DRAWBUS;
  +
  +        break;
  +
  +      case(DRAWNET):
  +      case(NETCONT):
  +        /* Only continue the net if net end worked */
  +        if (o_net_end(w_current, (int) event->x,
  +                      (int) event->y)) {
  +          o_net_start(w_current,
  +                      (int) w_current->save_x,
  +                      (int) w_current->save_y);
  +          w_current->event_state=NETCONT;
  +        }
  +        break;
  +
  +      case(DRAWBUS):
  +      case(BUSCONT):
  +        /* Only continue the net if net end worked */
  +        if (o_bus_end(w_current, (int) event->x,
  +                      (int) event->y)) {
  +          o_bus_start(w_current,
  +                      (int) w_current->save_x,
  +                      (int) w_current->save_y);
  +          w_current->event_state=BUSCONT;
  +        }
  +        break;
  +
  +#if 0 /* old way with the text dialog box which was around only once */
  +      case(DRAWTEXT):
  +        w_current->start_x = fix_x(w_current, (int) event->x);
  +        w_current->start_y = fix_y(w_current, (int) event->y);
  +        o_text_input(w_current);
  +        w_current->inside_action = 1;
  +        break;
  +#endif
  +
  +      case(ENDCOMP):
  +        o_complex_end(w_current,
  +                      fix_x(w_current, (int) event->x),
  +                      fix_y(w_current, (int) event->y));
  +				/* not sure on this one */
  +				/* probably keep this one */
  +
  +        o_redraw_single(w_current, w_current->page_current->
  +                        object_tail);
  +        if (w_current->continue_component_place) {
  +          o_complex_start(w_current,
  +                          (int) event->x,
  +                          (int) event->y);
  +        } else {
  +          w_current->inside_action = 0;
  +	  i_set_state(w_current, SELECT);
  +          i_update_toolbar(w_current);
  +        }
  +        break;
  +
  +      case(ENDPASTE):
  +        o_buffer_paste_end(w_current,
  +                           fix_x(w_current, (int) event->x),
  +                           fix_y(w_current, (int) event->y),
  +                           w_current->buffer_number);
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +      case(ENDATTRIB):
  +        o_attrib_end(w_current);
  +				/* not sure on this one either... */
  +				/* keep it as well */
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +				/* the following happen inside attrib_end */
  +				/* therefore they are commeneted out here */
  +                                /* o_redraw_single(object_tail);*/
  +                                /* o_redraw_selected(); not sure on this */
  +        break;
  +
  +      case(ENDROTATEP):
  +	prev_state = w_current->DONT_REDRAW;
  +	w_current->DONT_REDRAW = 0;
  +        o_rotate_90(
  +                    w_current,
  +                    w_current->page_current->selection2_head->next,
  +                    (int) event->x, (int) event->y);
  +	w_current->DONT_REDRAW = prev_state;
  +
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +      case(ENDMIRROR):
  +        o_mirror(w_current,
  +                 w_current->page_current->selection2_head->next,
  +                 (int) event->x, (int) event->y);
  +
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +      case(ENDTEXT):
  +        o_text_end(w_current);
  +				/* not sure on this one either... */
  +				/* keep it as well */
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +				/* the following happen inside attrib_end */
  +				/* therefore they are commeneted out here */
  +                                /* o_redraw_single(object_tail);*/
  +                                /* o_redraw_selected(); not sure on this */
  +        break;
  +
  +      case(STARTPAN):
  +        a_pan(w_current,
  +              (int) event->x,
  +              (int) event->y);
  +
  +				/* keep this one too */
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +				/* go to select state or not? hack */
  +        break;
  +
  +      case(ZOOMBOXSTART):
  +        a_zoom_box_start(w_current,
  +                         (int) event->x,
  +                         (int) event->y);
  +        w_current->event_state = ZOOMBOXEND;
  +        w_current->inside_action = 1;
  +        break;
  +
  +    }
  +  } else if (event->button == 2) {
  +
  +    /* try this out and see how it behaves */
  +    if (w_current->inside_action) {
  +      if (w_current->event_state == ENDCOMP ||
  +          w_current->event_state == ENDTEXT ||
  +	  w_current->event_state == ENDMOVE ||
  +	  w_current->event_state == ENDCOPY ||
  +	  w_current->event_state == ENDMCOPY) {
  +            return(0);
  +          } else {
  +            i_callback_cancel(w_current, 0, NULL);
  +            return(0);
  +          }
  +    }
  +
  +    switch(w_current->middle_button) {
  +
  +      case(ACTION): 
  +				/* determine here if copy or move */
  +				/* for now do move only */
  +				/* make sure the list is not empty */
  +      if (o_select_selected(w_current)) {
  +
  +        /* don't want to search if shift */
  +        /* key is depresed */
  +        if (!w_current->SHIFTKEY) {
  +          o_find_object(w_current, 
  +                        (int) event->x, 
  +                        (int) event->y, TRUE);
  +        }
  +      } else {
  +        o_select_unselect_all(w_current);
  +        /* don't want to search if shift */
  +        /* key is depresed */
  +        if (!w_current->SHIFTKEY) {
  +          o_find_object(w_current, 
  +                        (int) event->x, 
  +                        (int) event->y, TRUE);
  +        }
  +      }
  +
  +      if (!o_select_selected(w_current)) {
  +        /* this means the above find did not 
  +         * find anything */
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        return(0);
  +      }
  +
  +      if (w_current->ALTKEY) {
  +        o_copy_start(w_current,
  +                     (int) event->x,
  +                     (int) event->y);
  +        w_current->inside_action = 1;
  +	i_set_state(w_current, COPY);
  +      } else {
  +        o_move_start(w_current,
  +                     (int) event->x,
  +                     (int) event->y);
  +        w_current->inside_action = 1;
  +	i_set_state(w_current, MOVE);
  +      }
  +      break;
  +
  +      case(REPEAT):	
  +      if (w_current->last_callback != NULL) {
  +        (*w_current->last_callback)(w_current, 	
  +                                    0, NULL);
  +      }
  +      break;
  +#ifdef HAS_LIBSTROKE
  +      case(STROKE):
  +      DOING_STROKE=TRUE;
  +      break;
  +
  +#endif
  +    }
  +
  +  } else if (event->button == 3) {
  +    if (!w_current->inside_action) {
  +      if (w_current->third_button == POPUP_ENABLED) {
  +	i_update_menus(w_current);  /* update menus before popup  */
  +        do_popup(w_current, event);
  +      } else {
  +        w_current->event_state = MOUSEPAN; /* start */
  +        w_current->inside_action = 1;
  +        w_current->doing_pan = TRUE;
  +        start_pan_x = (int) event->x;
  +        start_pan_y = (int) event->y;
  +        throttle=0;
  +      }
  +    } else { /* this is the default cancel */
  +      switch (w_current->event_state) {
  +        case(STARTDRAWNET):
  +        case(DRAWNET):
  +        case(NETCONT):
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, STARTDRAWNET);
  +        o_net_eraserubber(w_current);
  +        break;
  +
  +        case(STARTDRAWBUS):
  +        case(DRAWBUS):
  +        case(BUSCONT):
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, STARTDRAWBUS);
  +        o_bus_eraserubber(w_current);
  +        break;
  +
  +        case(DRAWPIN):
  +        case(ENDPIN):
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, DRAWPIN);
  +        o_pin_eraserubber(w_current);
  +        break;
  +
  +        case(DRAWLINE):
  +        case(ENDLINE):
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, DRAWLINE);
  +        o_line_eraserubber(w_current);
  +        break;
  +
  +        case(DRAWBOX):
  +        case(ENDBOX):
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, DRAWBOX);
  +        o_box_eraserubber(w_current);
  +        break;
  +
  +        case(DRAWPICTURE):
  +        case(ENDPICTURE):
  +#ifndef HAS_GTK12
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, DRAWPICTURE);
  +        o_picture_eraserubber(w_current);
  +#endif
  +        break;
  +
  +        case(DRAWCIRCLE):
  +        case(ENDCIRCLE):
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, DRAWCIRCLE);
  +        o_circle_eraserubber(w_current);
  +        break;
  +
  +        case(DRAWARC):
  +        case(ENDARC):
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, DRAWARC);
  +        o_arc_eraserubber(w_current);
  +        break;
  +
  +        default:
  +        i_callback_cancel(w_current, 0, NULL);
  +        break;
  +      }
  +      i_update_toolbar(w_current);	
  +    }
  +  }
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_event_button_released(GtkWidget *widget, GdkEventButton *event,
  +			     TOPLEVEL *w_current)
  +{
  +  int prev_state;
  +  int redraw_state;
  +
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +
  +#if DEBUG
  +  printf("released! %d \n", w_current->event_state);
  +#endif
  +
  +  w_current->SHIFTKEY   = (event->state & GDK_SHIFT_MASK  ) ? 1 : 0;
  +  w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0;
  +  w_current->ALTKEY     = (event->state & GDK_MOD1_MASK) ? 1 : 0;
  +
  +  if (event->button == 1) {
  +    switch(w_current->event_state) {
  +      case(SELECT):
  +        /* do nothing */
  +        break;
  +
  +      case(MOVE):
  +        w_current->event_state = ENDMOVE;
  +        break;
  +
  +      case(COPY):
  +        w_current->event_state = ENDCOPY;
  +        break;
  +
  +      case(MCOPY):
  +        w_current->event_state = ENDMCOPY;
  +        break;
  +
  +      case(GRIPS):
  +        o_grips_end(w_current), 
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +      case(ENDMOVE):
  +        o_move_end(w_current);
  +        /* having this stay in copy was driving me nuts*/
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +      case(ENDCOPY):
  +        o_copy_end(w_current);
  +        /* having this stay in copy was driving me nuts*/
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +      case(ENDMCOPY):
  +        o_copy_end(w_current);
  +        /* having this stay in copy was driving me nuts*/
  +        w_current->inside_action = 1;
  +	/* Keep the state and the inside_action, as the copy has not finished. */	
  +	w_current->last_x = w_current->start_x = fix_x(w_current, mouse_x);
  +	w_current->last_y = w_current->start_y = fix_y(w_current, mouse_y);
  +	i_set_state(w_current, ENDMCOPY); 
  +        i_update_toolbar(w_current);
  +	o_undo_savestate(w_current, UNDO_ALL);
  +        break;
  +
  +      case(SBOX):
  +        /* fix_x,y was removed to allow more flex */
  +        w_current->last_x = (int) event->x;
  +        w_current->last_y = (int) event->y;
  +        /* NEW SELECTION code */
  +        o_select_box_end(w_current,
  +                         (int) event->x,
  +                         (int) event->y);
  +        /* this one stays */
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +      case(ZOOMBOXEND):
  +        /* fix_x,y was removed to allow more flex */
  +        w_current->last_x = (int) event->x;
  +        w_current->last_y = (int) event->y;
  +        a_zoom_box_end(w_current,
  +                       (int) event->x,
  +                       (int) event->y);
  +        /* this one stays */
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +      case(STARTSELECT):
  +
  +        /* first look for grips */
  +        if (!o_grips_start(
  +                           w_current, (int) event->x, (int) event->y)) {
  +				/* now go looking for objects to select */
  +          o_find_object(w_current, 
  +                        (int) event->x, 
  +                        (int) event->y, TRUE);
  +          w_current->event_state = SELECT;
  +          w_current->inside_action = 0;
  +        } else {
  +				/* an grip was found */
  +          w_current->event_state = GRIPS;
  +          w_current->inside_action = 1;
  +        }
  +        break;
  +
  +    }
  +  } else if (event->button == 2) {
  +
  +    if (w_current->inside_action) {
  +      if (w_current->event_state == ENDCOMP) {
  +        o_drawbounding(w_current,
  +                       w_current->page_current->
  +                       complex_place_head->next, 
  +                       NULL, x_get_darkcolor(w_current->bb_color), TRUE);
  +
  +        w_current->complex_rotate = 
  +        (w_current->complex_rotate + 90) % 360;
  +
  +	o_complex_place_rotate(w_current);
  +	  
  +        o_drawbounding(w_current,
  +                       w_current->page_current->
  +                       complex_place_head->next, 
  +                       NULL, x_get_darkcolor(w_current->bb_color), TRUE);
  +        return(0);
  +      } else if (w_current->event_state == ENDTEXT) {
  +        o_drawbounding(w_current,
  +                       w_current->page_current->
  +                       attrib_place_head->next, 
  +                       NULL, x_get_darkcolor(w_current->bb_color), TRUE);
  +
  +        w_current->complex_rotate = 
  +        (w_current->complex_rotate + 90) % 360;
  +
  +        o_text_place_rotate(w_current);
  +
  +        o_drawbounding(w_current,
  +                       w_current->page_current->
  +                       attrib_place_head->next, 
  +                       NULL, x_get_darkcolor(w_current->bb_color), TRUE);
  +        return(0);
  +
  +      }
  +      else if ((w_current->event_state == ENDMOVE) ||
  +	       (w_current->event_state == ENDCOPY) ||
  +	       (w_current->event_state == ENDMCOPY) ) {
  +	g_assert (w_current->page_current->selection2_head != NULL);
  +	prev_state = w_current->event_state;
  +
  +	o_drawbounding(w_current, NULL,
  +		       w_current->page_current->selection2_head->next,
  +		       x_get_darkcolor(w_current->bb_color), TRUE);
  +
  +	/* Don't allow o_rotate_90 to erase the selection, neither to
  +	   redraw the objects after rotating */
  +	/* skip over head node */
  +	redraw_state = w_current->DONT_REDRAW;
  +	w_current->DONT_REDRAW = 1;
  +
  +	o_rotate_90(w_current, w_current->page_current->selection2_head->next,
  +		    fix_x(w_current, w_current->start_x),
  +		    fix_y(w_current, w_current->start_y));
  +	w_current->DONT_REDRAW = redraw_state;
  +	w_current->rotated_inside ++;	
  +	w_current->event_state = prev_state;
  +
  +	o_drawbounding(w_current, NULL,
  +		       w_current->page_current->selection2_head->next,
  +		       x_get_darkcolor(w_current->bb_color), TRUE);
  +	
  +        return(0);
  +      }
  +
  +    }
  +
  +    switch(w_current->middle_button) { 
  +      case(ACTION): 	
  +      switch(w_current->event_state) {
  +        case(MOVE):
  +        o_move_end(w_current);
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +
  +        case(COPY):
  +        o_copy_end(w_current);
  +        w_current->inside_action = 0;
  +	i_set_state(w_current, SELECT);
  +        i_update_toolbar(w_current);
  +        break;
  +      }
  +      break;
  +
  +#ifdef HAS_LIBSTROKE
  +      case(STROKE):
  +
  +      DOING_STROKE = FALSE;
  +
  +      if (stroke_trans (sequence) == TRUE) {
  +        if (stroke_info_mode) {
  +          printf ("LibStroke Translation"
  +                  " succeeded: ");
  +        }
  +      } else {
  +        if (stroke_info_mode) {
  +          printf ("LibStroke Translation"
  +                  " failed: ");
  +        }
  +      }
  +	
  +      if (stroke_info_mode) {
  +        printf ("Sequence=\"%s\"\n",sequence);
  +      }
  +	
  +				/* new way written by Stefan Petersen */ 
  +				/* much better */
  +      if (x_stroke_search_execute(sequence)) {
  +
  +        if (stroke_info_mode) {
  +          printf("Sequence understood\n");
  +        }
  +        x_stroke_erase_all(w_current);
  +      }
  +      break;
  +#endif
  +    }
  +
  +  } else if (event->button == 3) {
  +    if (w_current->doing_pan) { /* just for ending a mouse pan */
  +      w_current->doing_pan=FALSE;
  +      o_redraw_all_fast(w_current);
  +      o_undo_savestate(w_current, UNDO_VIEWPORT_ONLY);
  +      /* this needs to be REDONE */
  +      /* if you mouse pan, you will be thrown out of the current mode. */
  +      /* not good */
  +      w_current->inside_action = 0;
  +      i_set_state(w_current, SELECT);
  +      i_update_toolbar(w_current);
  +    }
  +  }
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_event_motion(GtkWidget *widget, GdkEventMotion *event,
  +		    TOPLEVEL *w_current)
  +{
  +  int temp_x, temp_y;
  +  int pdiff_x, pdiff_y;
  +
  +  int zoom_scale;
  +  int diff_x; 
  +  int skip_event=0;
  +  GdkEvent *test_event;
  +
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +
  +  w_current->SHIFTKEY   = (event->state & GDK_SHIFT_MASK  ) ? 1 : 0;
  +  w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0;
  +  w_current->ALTKEY     = (event->state & GDK_MOD1_MASK) ? 1 : 0;
  +
  +#if DEBUG
  +  /*  printf("MOTION!\n");*/
  +#endif
  +
  +#ifdef HAS_LIBSTROKE
  +  if (DOING_STROKE == TRUE) {
  +    x_stroke_add_point(w_current, (int) event->x, (int) event->y);
  +
  +    stroke_record ((int) event->x, (int) event->y);
  +    return(0);
  +  }
  +#endif
  +
  +  /* skip the moving event if there are other moving events in the 
  +     gdk event queue (Werner)
  +     Only skip the event if is the same event and no buttons or modifier 
  +     keys changed*/
  +  if ((test_event = gdk_event_get()) != NULL) {
  +    if (test_event->type == GDK_MOTION_NOTIFY
  +	&& ((GdkEventMotion *) test_event)->state == event->state) {
  +      skip_event= 1;
  +    }
  +    gdk_event_put(test_event); /* put it back in front of the queue */
  +    gdk_event_free(test_event);
  +    if (skip_event == 1)
  +      return 0;
  +  }
  +
  +  mouse_x = (int) event->x;
  +  mouse_y = (int) event->y;
  +
  +  if (w_current->cowindow) {
  +    coord_display_update(w_current, mouse_x, mouse_y);
  +  }
  +
  +  if (w_current->third_button == MOUSEPAN_ENABLED) {
  +    if((w_current->event_state == MOUSEPAN) &&
  +       w_current->inside_action) {
  +         pdiff_x = mouse_x - start_pan_x;
  +         pdiff_y = mouse_y - start_pan_y;
  +
  +#if 0
  +         printf("current center: %d %d\n", current_center_x, current_center_y);
  +         printf("pdiff: %d %d\n", pdiff_x, pdiff_y);
  +#endif
  +
  +         if (!(throttle % 5)) {
  +           a_pan_mouse(w_current, pdiff_x*5, pdiff_y*5);
  +
  +           start_pan_x = (int) event->x;
  +           start_pan_y = (int) event->y;
  +         }
  +         throttle++;
  +         return(0);
  +       }
  +  }
  +
  +  switch(w_current->event_state) {
  +
  +    case(SELECT):
  +    /* do nothing */
  +    break;
  +
  +    case(GRIPS):
  +    o_grips_motion(w_current, (int) event->x, (int) event->y);
  +    break;
  +
  +    case(STARTSELECT):
  +    if ( (!w_current->drag_can_move) ||
  +	 (w_current->drag_can_move && 
  +	  (! o_find_selected_object(w_current, 
  +				    w_current->start_x, w_current->start_y)))) {
  +      temp_x = fix_x(w_current, (int) event->x);
  +      temp_y = fix_y(w_current, (int) event->y);
  +      /* is eight enough of a threshold? */
  +      /* make this configurable anyways */
  +      diff_x = fabs(w_current->page_current->right -
  +		    w_current->page_current->left);
  +      
  +#ifdef HAS_RINT
  +      zoom_scale = (int) rint(w_current->init_right / diff_x);
  +#else
  +      zoom_scale = (int) w_current->init_right / diff_x;
  +#endif
  +      
  +      if (zoom_scale < 10) {
  +	zoom_scale = 10;
  +      }
  +      
  +      if ( (abs(temp_x - w_current->start_x) > zoom_scale) ||
  +	   (abs(temp_y - w_current->start_y) > zoom_scale) ) {
  +	w_current->event_state = SBOX;
  +	/* NEW SELECTION code */
  +	o_select_box_start(w_current,
  +			   (int) event->x,
  +			   (int) event->y);
  +	     w_current->inside_action = 1;
  +      }
  +      break;
  +    }
  +    else {
  +      /* Start the object movement */
  +      w_current->rotated_inside = 0;
  +      o_move_start(w_current,
  +		   (int) event->x, (int) event->y);
  +      w_current->event_state = ENDMOVE;
  +      w_current->inside_action = 1;
  +      
  +      /* Continue to the MOVE actions */
  +      /* Important!! keep the MOVE and ENDMOVE cases below this 
  +	 without the break statement!! */
  +    }
  +
  +    case(ENDMOVE):
  +    case(MOVE):
  +    if (w_current->inside_action) {
  +
  +      if (w_current->netconn_rubberband) {
  +        o_move_stretch_rubberband(w_current);
  +      }
  +
  +      o_drawbounding(
  +                     w_current, NULL,
  +                     w_current->page_current->selection2_head->next,
  +                     x_get_darkcolor(w_current->bb_color), FALSE);
  +      w_current->last_x = fix_x(w_current,  (int) event->x);
  +      w_current->last_y = fix_y(w_current,  (int) event->y);
  +      o_drawbounding(
  +                     w_current, NULL,
  +                     w_current->page_current->selection2_head->next,
  +                     x_get_darkcolor(w_current->bb_color), FALSE);
  +
  +      if (w_current->netconn_rubberband) {
  +        o_move_stretch_rubberband(w_current);
  +      }
  +
  +    }
  +    break;
  +
  +    case(ENDCOPY):
  +    case(COPY):
  +    case(ENDMCOPY):
  +    case(MCOPY):
  +    if (w_current->inside_action) {
  +      o_drawbounding(
  +                     w_current, NULL,
  +                     w_current->page_current->selection2_head->next,
  +                     x_get_darkcolor(w_current->bb_color), FALSE);
  +      w_current->last_x = fix_x(w_current,  (int) event->x);
  +      w_current->last_y = fix_y(w_current,  (int) event->y);
  +      o_drawbounding(
  +                     w_current, NULL,
  +                     w_current->page_current->selection2_head->next,
  +                     x_get_darkcolor(w_current->bb_color), FALSE);
  +    }
  +    break;
  +
  +    case(ENDLINE):
  +    if (w_current->inside_action)
  +    o_line_rubberline(w_current,
  +                      (int) event->x,
  +                      (int) event->y);
  +    break;
  +
  +    case(ENDBOX):
  +    if (w_current->inside_action)
  +    o_box_rubberbox( w_current,
  +                     (int) event->x,
  +                     (int) event->y);
  +    break;
  +
  +    case(ENDPICTURE):
  +#ifndef HAS_GTK12
  +    if (w_current->inside_action)
  +    o_picture_rubberbox( w_current,
  +                        (int) event->x,
  +                        (int) event->y);
  +#endif
  +    break;
  +
  +    case(ENDCIRCLE):
  +    if (w_current->inside_action)
  +    o_circle_rubbercircle(w_current,
  +                          (int) event->x,
  +                          (int) event->y);
  +    break;
  +
  +    case(ENDARC):
  +    if (w_current->inside_action)
  +	/* pb20011022 - changed name to _rubberarc() and added a parameter */
  +    o_arc_rubberarc(w_current,
  +					(int) event->x,
  +					(int) event->y, ARC_RADIUS);
  +    break;
  +
  +    case(DRAWNET):
  +    case(NETCONT):
  +    if (w_current->inside_action)
  +    o_net_rubbernet(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +    break;
  +
  +    case(DRAWBUS):
  +    case(BUSCONT):
  +    if (w_current->inside_action)
  +    o_bus_rubberbus(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +    break;
  +
  +    case(ENDPIN):
  +    if (w_current->inside_action)
  +    o_pin_rubberpin(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +    break;
  +
  +    case(DRAWCOMP):
  +    w_current->complex_rotate = 0; /* reset to known state */
  +    o_complex_start(w_current,
  +                    (int) event->x,
  +                    (int) event->y);
  +    w_current->event_state = ENDCOMP;
  +    w_current->inside_action = 1;
  +    break;
  +
  +    case(ENDCOMP):
  +    o_complex_rubbercomplex(w_current);
  +    w_current->last_x = fix_x(w_current, (int) event->x);
  +    w_current->last_y = fix_y(w_current, (int) event->y);
  +    o_complex_rubbercomplex(w_current);
  +    break;
  +
  +    case(ENDPASTE):
  +    o_buffer_paste_rubberpaste(w_current, w_current->buffer_number);
  +    w_current->last_x = fix_x(w_current, (int) event->x);
  +    w_current->last_y = fix_y(w_current, (int) event->y);
  +    o_buffer_paste_rubberpaste(w_current, w_current->buffer_number);
  +    break;
  +
  +    case(DRAWATTRIB):
  +    o_attrib_start(w_current, (int) event->x, (int) event->y);
  +    w_current->event_state = ENDATTRIB;
  +    w_current->inside_action = 1;
  +    break;
  +
  +    case(DRAWTEXT):
  +    w_current->complex_rotate = 0; /* reset to known state */
  +    o_text_start(w_current, (int) event->x, (int) event->y);
  +    w_current->event_state = ENDTEXT;
  +    w_current->inside_action = 1;
  +    break;
  +
  +    case(ENDATTRIB):
  +    o_attrib_rubberattrib(w_current);
  +    w_current->last_x = fix_x(w_current, (int) event->x);
  +    w_current->last_y = fix_y(w_current, (int) event->y);
  +    o_attrib_rubberattrib(w_current);
  +    break;
  +
  +    case(ENDTEXT):
  +    o_text_rubberattrib(w_current);
  +    w_current->last_x = fix_x(w_current, (int) event->x);
  +    w_current->last_y = fix_y(w_current, (int) event->y);
  +    o_text_rubberattrib(w_current);
  +    break;
  +
  +    case(SBOX):
  +    if (w_current->inside_action)
  +    /* NEW SELECTION code */
  +    o_select_box_rubberband(w_current,
  +                            (int) event->x,
  +                            (int) event->y);
  +    break;
  +
  +    case(ZOOMBOXEND):
  +    if (w_current->inside_action)
  +    a_zoom_box_rubberband( w_current,
  +                           (int) event->x,
  +                           (int) event->y);
  +    break;
  +
  +  }
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_event_configure(GtkWidget *widget, GdkEventConfigure *event,
  +		       TOPLEVEL *w_current)
  +{
  +  int new_height, new_width;
  +  double cx,cy;
  +
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +
  +  /* don't want to call this if the current page isn't setup yet */
  +  if (w_current->page_current == NULL) {
  + 	return 0;
  +  }
  +        
  +  /* this callback is for drawing areas only! */
  +  /* things like changing a label causes a resize */
  +  /* this code is no longer needed.*/
  +
  +#if DEBUG
  +  printf("RESIZE\n");
  +#endif
  +
  +  /* get the new width/height */
  +  new_width  = widget->allocation.width;
  +  new_height = widget->allocation.height;
  +
  +  /* if it's equal to the current width/height don't do anything */
  +  if (new_width == w_current->win_width &&
  +      new_height == w_current->win_height) {
  +    return(0);
  +  }
  +
  +#if 0 /* my experiments with getting resize to work differently */
  +  diff_width  = (new_width - w_current->win_width)*100;
  +  diff_height = (new_height - w_current->win_height)*100;
  +
  +  printf("diff %d %d\n", diff_width, diff_height);
  +
  +  printf("world %d %d\n", SCREENabs(w_current, diff_width),
  +         SCREENabs(w_current, diff_height));
  +
  +  w_current->page_current->right = w_current->page_current->right + diff_width;
  +  w_current->page_current->bottom = w_current->page_current->bottom + diff_height;
  +
  +  diff_x =
  +  w_current->page_current->right -
  +  w_current->page_current->left;
  +  diff_y =
  +  w_current->page_current->bottom -
  +  w_current->page_current->top;
  +
  +  new_aspect =
  +  (float) fabs(w_current->page_current->right -
  +               w_current->page_current->left) /
  +  (float) fabs(w_current->page_current->bottom -
  +               w_current->page_current->top);
  +
  +#if DEBUG
  +  printf("wxh: %d %d\n", diff_x, diff_y);
  +  printf("diff is: %f\n", fabs(new_aspect - coord_aspectratio));
  +#endif
  +
  +  /* Make sure aspect ratio is correct */
  +  if (fabs(new_aspect - w_current->page_current->coord_aspectratio)) {
  +    if (new_aspect > w_current->page_current->coord_aspectratio) {
  +#if DEBUG
  +      printf("new larger then coord\n");
  +      printf("implies that height is too large\n");
  +#endif
  +      w_current->page_current->bottom =
  +        w_current->page_current->top +
  +        (w_current->page_current->right -
  +         w_current->page_current->left) /
  +        w_current->page_current->coord_aspectratio;
  +    } else {
  +#if DEBUG
  +      printf("new smaller then coord\n");
  +      printf("implies that width is too small\n");
  +#endif
  +      w_current->page_current->right =
  +        w_current->page_current->left +
  +        (w_current->page_current->bottom -
  +         w_current->page_current->top) *
  +        w_current->page_current->coord_aspectratio;
  +    }
  +#if DEBUG
  +    printf("invalid aspectratio corrected\n");
  +#endif
  +  }
  +
  +#endif
  +
  +  /* of the actual win window (drawing_area) */
  +  w_current->win_width  = widget->allocation.width;
  +  w_current->win_height = widget->allocation.height;
  +
  +  w_current->width  = w_current->win_width;
  +  w_current->height = w_current->win_height;
  +
  +  /* need to do this every time you change width / height */
  +  /* at the moment this set_w.. call is doing really nothing, because  ..->left...
  +     aren't recalculated (hw) */
  +  /*	set_window(w_current,
  +        w_current->page_current->left,
  +        w_current->page_current->right,
  +        w_current->page_current->top,
  +        w_current->page_current->bottom);
  +  */	
  +  /* doing this the aspectratio is kept when changing (hw)*/
  +  cx = (double) (w_current->page_current->left +
  +		 w_current->page_current->right) /2;
  +  cy = (double) (w_current->page_current->top +
  +                 w_current->page_current->bottom) /2;	
  +  a_pan_general(w_current, cx, cy, 1.0, A_PAN_DONT_REDRAW);	
  +	
  +
  +  if (w_current->backingstore) {
  +    gdk_pixmap_unref(w_current->backingstore);
  +  }
  +
  +  w_current->backingstore = gdk_pixmap_new(widget->window,
  +                                           widget->allocation.width,
  +                                           widget->allocation.height,
  +                                           -1);
  +  if (!w_current->DONT_REDRAW) {
  +    o_redraw_all_fast(w_current);
  +    x_scrollbars_update(w_current);
  +  }
  +
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is used during an open command
  + *  to setup the correct sizes
  + */
  +void x_manual_resize(TOPLEVEL *w_current)
  +{
  +  
  +  /* of the actual win window (drawing_area) */
  +  w_current->win_width  = w_current->drawing_area->allocation.width;
  +  w_current->win_height = w_current->drawing_area->allocation.height;
  +
  +#if DEBUG
  +  printf("manual: %d %d\n", w_current->win_width, w_current->win_height);
  +#endif
  +
  +  w_current->width = w_current->win_width;
  +  w_current->height = w_current->win_height;
  +
  +  /* need to do this every time you change width / height */
  +  set_window(w_current, w_current->page_current,
  +             w_current->page_current->left,
  +             w_current->page_current->right,
  +             w_current->page_current->top,
  +             w_current->page_current->bottom);
  +
  +#if DEBUG
  +  printf("Window aspect: %f\n",
  +         (float) w_current->win_width / (float) w_current->win_height);
  +  /* No longer used?
  +     printf("w: %d h: %d\n", width, height); */
  +  printf("aw: %d ah: %d\n", w_current->win_width, w_current->win_height);
  +#endif
  +
  +  /* I'm assuming that the backingstore pixmap is of the right
  +   * size */
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_event_hschanged (GtkAdjustment *adj, TOPLEVEL *w_current)
  +{
  +  int current_left;
  +  int new_left;
  +  GtkAdjustment        *hadjustment;
  +
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +
  +  if (w_current->scrollbars_flag == FALSE) {
  +    return;
  +  }
  +
  +  hadjustment =
  +  gtk_range_get_adjustment(GTK_RANGE(w_current->h_scrollbar));
  +
  +  current_left = w_current->page_current->left;
  +  new_left = (int) hadjustment->value;
  +
  +  if (!w_current->DONT_RECALC) {
  +    w_current->page_current->left = new_left;
  +    w_current->page_current->right =
  +      w_current->page_current->right -
  +      (current_left - new_left);
  +  }
  +
  +  if (!w_current->DONT_REDRAW) {	
  +    o_redraw_all_fast(w_current);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_event_vschanged (GtkAdjustment *adj, TOPLEVEL *w_current)
  +{
  +  int current_bottom;
  +  int new_bottom;
  +  GtkAdjustment        *vadjustment;
  +
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +        
  +  if (w_current->scrollbars_flag == FALSE) {
  +    return;
  +  }
  +
  +  vadjustment = gtk_range_get_adjustment(
  +                                         GTK_RANGE(w_current->v_scrollbar));
  +
  +  current_bottom = w_current->page_current->bottom;
  +  new_bottom = w_current->init_bottom - (int) vadjustment->value;
  +
  +  if (!w_current->DONT_RECALC) {
  +    w_current->page_current->bottom = new_bottom;
  +    w_current->page_current->top =
  +      w_current->page_current->top -
  +      (current_bottom - new_bottom);
  +  }
  +
  +#if DEBUG
  +  printf("vrange %f %f\n", vadjustment->lower, vadjustment->upper);
  +  printf("vvalue %f\n", vadjustment->value);
  +  printf("actual: %d %d\n", w_current->page_current->top, 
  +	 w_current->page_current->bottom);
  +#endif
  +
  +  if (!w_current->DONT_REDRAW) {	
  +    o_redraw_all_fast(w_current);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_event_enter(GtkWidget *widget, GdkEventCrossing *event,
  +		   TOPLEVEL *w_current)
  +{
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +  /* do nothing or now */
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_event_key_press (GtkWidget *widget, GdkEventKey *event,
  +			TOPLEVEL *w_current)
  +{
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +
  +  set_window_current_key(w_current);
  +
  +  if (event) {
  +#if DEBUG
  +    printf("x_event_key_pressed: Pressed key %i.\n", event->keyval);
  +#endif
  +    g_keys_execute(event->state, event->keyval);
  +  }
  +
  +  return(0);
  +}
  +
  +#ifdef HAS_GTK22
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_event_scroll (GtkWidget *widget, GdkEventScroll *event,
  +		     TOPLEVEL *w_current)
  +{
  +  GtkAdjustment *adj;
  +
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +
  +  /* You must have scrollbars enabled if you want to use the scroll wheel */
  +  if (w_current->scrollbars_flag == FALSE) {
  +    return 0;
  +  }
  +
  +  /* update the state of the modifiers */
  +  w_current->SHIFTKEY   = (event->state & GDK_SHIFT_MASK  ) ? 1 : 0;
  +  w_current->CONTROLKEY = (event->state & GDK_CONTROL_MASK) ? 1 : 0;
  +  w_current->ALTKEY     = (event->state & GDK_MOD1_MASK) ? 1 : 0;
  +
  +  switch (event->direction) {
  +  case(GDK_SCROLL_UP):
  +    if (!w_current->CONTROLKEY)
  +    {
  +      adj = gtk_range_get_adjustment(GTK_RANGE(w_current->v_scrollbar));
  +      gtk_adjustment_set_value(adj, adj->value - (adj->page_increment / 4));
  +    } else {
  +      /* if the control key is held down, then scroll left as well */
  +      adj = gtk_range_get_adjustment(GTK_RANGE(w_current->h_scrollbar));
  +      gtk_adjustment_set_value(adj, adj->value - (adj->page_increment / 4));
  +    }
  +    break;
  +
  +  case(GDK_SCROLL_DOWN):
  +    if (!w_current->CONTROLKEY)
  +    {
  +      adj = gtk_range_get_adjustment(GTK_RANGE(w_current->v_scrollbar));
  +      gtk_adjustment_set_value(adj, min(adj->value + (adj->page_increment / 4),
  +                                        adj->upper - adj->page_size));
  +    } else {
  +      /* if the control key is held down, then scroll right as well */
  +      adj = gtk_range_get_adjustment(GTK_RANGE(w_current->h_scrollbar));
  +      gtk_adjustment_set_value(adj, min(adj->value + (adj->page_increment / 4),
  +                                        adj->upper - adj->page_size));
  +    }
  +    break;
  +
  +  case(GDK_SCROLL_LEFT):
  +    adj = gtk_range_get_adjustment(GTK_RANGE(w_current->h_scrollbar));
  +    gtk_adjustment_set_value(adj, adj->value - (adj->page_increment / 4));
  +    break;
  +
  +  case(GDK_SCROLL_RIGHT):
  +    adj = gtk_range_get_adjustment(GTK_RANGE(w_current->h_scrollbar));
  +    gtk_adjustment_set_value(adj, min(adj->value + (adj->page_increment / 4),
  +                                      adj->upper - adj->page_size));
  +    break;
  +
  +  }
  +
  +  return(0);
  +}
  +#endif
  
  
  
  1.20      +2288 -1666eda/geda/gaf/gschem/src/x_fileselect.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_fileselect.c
  ===================================================================
  RCS file: x_fileselect.c
  diff -N x_fileselect.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_fileselect.c	14 Jul 2006 02:23:55 -0000	1.20
  @@ -0,0 +1,2482 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <stdlib.h>
  +#include <sys/types.h>
  +#ifdef HAVE_SYS_PARAM_H
  +#include <sys/param.h>
  +#endif
  +#include <sys/stat.h>
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +#ifdef HAVE_DIRENT_H
  +#include <dirent.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +#include <gtk/gtk.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#define DIR_LIST_WIDTH   180
  +#define DIR_LIST_HEIGHT  180
  +#define FILE_LIST_WIDTH  180
  +#define FILE_LIST_HEIGHT 180
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_destroy_window(GtkWidget *widget, FILEDIALOG *f_current)
  +{
  +
  +#if DEBUG
  +  printf("destroy\n");
  +#endif
  +  x_fileselect_free_list_buffers(f_current);
  +
  +  if (f_current->directory) {
  +    free(f_current->directory);
  +    f_current->directory = NULL;
  +  }
  +
  +  if (f_current->filename) {
  +    free(f_current->filename);
  +    f_current->filename = NULL;
  +  }
  +
  +  x_preview_close(f_current->preview);
  +  gtk_grab_remove(f_current->xfwindow);
  +  f_current->toplevel = NULL;
  +  f_current->xfwindow = NULL;
  +  /* *window = NULL;*/
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int x_fileselect_keypress(GtkWidget * widget, GdkEventKey * event, 
  +			  FILEDIALOG* f_current)
  +{
  +  if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +    x_fileselect_close (NULL, f_current);
  +    return TRUE;
  +  }
  +
  +  return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_init_list_buffers(FILEDIALOG *f_current) 
  +{
  +  int i;
  +
  +  for (i = 0; i < MAX_FILES; i++) {
  +    f_current->file_entries[i] = NULL;
  +  }
  +
  +  for (i = 0; i < MAX_DIRS; i++) {
  +    f_current->directory_entries[i] = NULL;
  +  }
  +	
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_free_list_buffers(FILEDIALOG *f_current) 
  +{
  +  int i;
  +
  +  for (i = 0; i < MAX_FILES; i++) {
  +    if (f_current->file_entries[i]) 
  +      free(f_current->file_entries[i]);
  +
  +    f_current->file_entries[i] = NULL;
  +  }
  +
  +  for (i = 0; i < MAX_DIRS; i++) {
  +    if (f_current->directory_entries[i]) 
  +    free(f_current->directory_entries[i]);
  +
  +    f_current->directory_entries[i] = NULL;
  +  }
  +}
  +
  +/*********** File Open/Save As... specific code starts here ***********/
  +/*! \section file-open-save-as File Open/Save As Functions.
  + *  \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_update_dirfile(FILEDIALOG *f_current, char *filename)
  +{
  +  char *temp=NULL;
  +
  +  if (f_current->filename) {
  +    free(f_current->filename);
  +    f_current->filename = NULL;
  +  }
  +
  +  if (f_current->directory) {
  +    free(f_current->directory);
  +    f_current->directory = NULL;
  +  }
  +
  +  /* this may cause problems on non POSIX complient systems */	
  +  temp = getcwd(NULL, 1024);
  +	
  +  if (filename) {
  +    f_current->directory = g_strdup (temp); 
  +    f_current->filename = g_strdup (filename);
  +					
  +    free(temp); 
  +#ifdef __MINGW32__
  +    if (u_basic_has_trailing(f_current->directory, G_DIR_SEPARATOR)) {
  +       temp = g_strconcat (f_current->directory, 
  +                           f_current->filename, NULL);
  +    } else {
  +#endif
  +       temp = g_strconcat (f_current->directory, 
  +                           G_DIR_SEPARATOR_S,
  +                           f_current->filename, NULL);
  +#ifdef __MINGW32__
  +    }
  +#endif
  +
  +    gtk_entry_set_text(GTK_ENTRY(f_current->filename_entry), temp);
  +
  +  } else {
  +    f_current->directory = g_strdup (temp);
  +
  +    if (f_current->filename) { 
  +      free(f_current->filename);
  +      f_current->filename=NULL;
  +    }
  +
  +    gtk_entry_set_text(GTK_ENTRY(f_current->filename_entry), 
  +                       f_current->directory);
  +  }
  +
  +  free(temp);
  +
  +#if DEBUG
  +  printf("directory: %s\n", f_current->directory);
  +#endif
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_setup_list_buffers(FILEDIALOG *f_current, 
  +				     int num_files, int num_directories)
  +{
  +  int i;
  +
  +  for (i = 0; i < num_files+1; i++) {
  +    if (f_current->file_entries[i]) {
  +      free(f_current->file_entries[i]);
  +    }
  +    f_current->file_entries[i] = NULL;
  +  }
  +
  +  for (i = 0; i < num_directories+1; i++) {
  +    if (f_current->directory_entries[i]) {
  +      free(f_current->directory_entries[i]);
  +    }
  +    f_current->directory_entries[i] = NULL;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \return TRUE if the file should be included (passes the filter),
  + *          FALSE otherwise.
  + */
  +int x_fileselect_include_file(char *filename, int filter_type)
  +{
  +  switch(filter_type) {
  +    case(FILEDIALOG_SCH_ONLY):
  +    if (strstr(filename, ".sch")) {
  +      return(TRUE);
  +    }
  +    break;
  +
  +    case(FILEDIALOG_SYM_ONLY):
  +    if (strstr(filename, ".sym")) {
  +      return(TRUE);
  +    }
  +    break;
  +
  +    case(FILEDIALOG_SCH_SYM):
  +    if (strstr(filename, ".sch") || 
  +        strstr(filename, ".sym")) {
  +      return(TRUE);
  +    }
  +    break;
  +
  +    case(FILEDIALOG_ALL_FILES):
  +    return(TRUE);
  +    break;
  +  }
  +
  +  return(FALSE);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_fill_lists(FILEDIALOG *f_current)
  +{
  +  DIR* directory;
  +  struct dirent *dirent_ptr;
  +  int num_files=0;
  +  int num_directories=0;
  +  int file_count = 0;
  +  int dir_count = 0;
  +  struct stat stat_en;
  +  char path_buf[MAXPATHLEN*2];
  +  char *text[2];
  +  char *temp;
  +  int i;
  +  int max_width=0;
  +  int width;
  +  int first, last, j, done=0;
  +#ifdef __MINGW32__
  +  int has_trailing = FALSE;
  +#endif
  +
  +  directory = opendir(f_current->directory);
  +#ifdef __MINGW32__
  +  has_trailing = u_basic_has_trailing(f_current->directory, 
  +				      G_DIR_SEPARATOR);
  +#endif
  +
  +  if (!directory) {
  +    fprintf(stderr, _("Agg, could not open directory: %s\n"), f_current->directory);
  +    return;
  +  }
  +
  +  while((dirent_ptr = readdir(directory)) != NULL) {
  +#ifdef __MINGW32__
  +    if (has_trailing) {
  +    	sprintf(path_buf, "%s%s", f_current->directory, dirent_ptr->d_name);
  +    } else {
  +#endif
  +    	sprintf(path_buf, "%s%c%s", f_current->directory, G_DIR_SEPARATOR,
  +	        dirent_ptr->d_name);
  +#ifdef __MINGW32__
  +    }
  +#endif
  +
  +    if(stat(path_buf, &stat_en) >= 0 && S_ISDIR(stat_en.st_mode)) {
  +/*     	printf("dir: %s\n", path_buf);	 */
  +      num_directories++;	
  +    } else {
  +/*     	printf("file: %s\n", path_buf);	*/
  +      num_files++;	
  +    }
  +  }
  +
  +
  +  if (num_directories > MAX_DIRS) {
  +    fprintf(stderr, _("Too many directories! Increase MAX_DIRS\n"));
  +    exit(-1);
  +  }
  +
  +  if (num_files > MAX_FILES) {
  +    fprintf(stderr, _("Too many files! Increase MAX_FILES\n"));
  +    exit(-1);
  +  }
  +
  +  x_fileselect_setup_list_buffers(f_current, num_directories, num_files);
  +
  +  rewinddir(directory);
  +
  +  while((dirent_ptr = readdir(directory)) != NULL) {
  +#ifdef __MINGW32__
  +    if (has_trailing) {
  +    	sprintf(path_buf, "%s%s", f_current->directory, dirent_ptr->d_name);
  +    } else {
  +#endif
  +    	sprintf(path_buf, "%s%c%s", f_current->directory, G_DIR_SEPARATOR,
  +	        dirent_ptr->d_name);
  +#ifdef __MINGW32__
  +    }
  +#endif
  +    if(stat(path_buf, &stat_en) >= 0 && S_ISDIR(stat_en.st_mode) &&
  +       (strcmp(dirent_ptr->d_name, ".") != 0)) {
  +
  +      f_current->directory_entries[dir_count] = (char *)
  +        malloc(sizeof(char)*(strlen(dirent_ptr->d_name)+2));
  +	
  +      sprintf(f_current->directory_entries[dir_count], 
  +              "%s", dirent_ptr->d_name);
  +      dir_count++;
  +
  +    } else {
  +      if (x_fileselect_include_file(dirent_ptr->d_name,
  +                                    f_current->filter_type)) {	
  +        f_current->file_entries[file_count] = (char *)
  +          malloc(sizeof(char)*(strlen(dirent_ptr->d_name)+1));
  +        strcpy(f_current->file_entries[file_count], 
  +               dirent_ptr->d_name);
  +        file_count++;
  +      } 
  +    }
  +  }
  +
  +#if DEBUG
  +  printf("FILE COUNT: %d\n", file_count);
  +#endif
  +
  +  /* lame bubble sort */
  +  first = 0;
  +  last = file_count;
  +  while(!done) {
  +
  +    done = 1;
  +    for (j = first ; j < last-1; j++) {
  +      if (strcmp(f_current->file_entries[j], 
  +                 f_current->file_entries[j+1]) > 0) {
  +        temp = f_current->file_entries[j];
  +        f_current->file_entries[j] = 
  +          f_current->file_entries[j+1];
  +        f_current->file_entries[j+1] = temp;
  +        done = 0;
  +      }
  +    }
  +    last = last - 1;
  +
  +#if DEBUG 
  +    pass_count++;
  +#endif
  +  }
  +
  +#if DEBUG 
  +  printf("file passes: %d\n", pass_count);
  +  pass_count = 0;
  +  printf("test: %d\n", strcmp("./", "../"));
  +  printf("DIR COUNT: %d\n", dir_count);
  +#endif
  +
  +
  +  /* lame bubble sort */
  +  done = 0;
  +  first = 0;
  +  last = dir_count;
  +  while(!done) {
  +    done = 1;
  +    for (j = first ; j < last-1; j++) {
  +      if (strcmp(f_current->directory_entries[j], 
  +                 f_current->directory_entries[j+1]) > 0) {
  +        temp = f_current->directory_entries[j];
  +        f_current->directory_entries[j] = 
  +          f_current->directory_entries[j+1];
  +        f_current->directory_entries[j+1] = temp;
  +        done = 0;
  +      }
  +    }
  +    last = last - 1;
  +
  +#if DEBUG 
  +    pass_count++;
  +#endif
  +  }
  +
  +#if DEBUG
  +  printf("directory passes: %d\n", pass_count);
  +#endif
  +
  +
  +  gtk_clist_freeze (GTK_CLIST (f_current->dir_list));
  +  gtk_clist_clear (GTK_CLIST (f_current->dir_list));
  +  gtk_clist_freeze (GTK_CLIST (f_current->file_list));
  +  gtk_clist_clear (GTK_CLIST (f_current->file_list));
  +
  +  text[0] = NULL;
  +  text[1] = NULL;
  +  max_width = 0;
  +  for (i = 0 ; i < dir_count; i++) {
  +    temp = g_strconcat (f_current->directory_entries[i],
  +                        G_DIR_SEPARATOR_S, NULL);
  +    text[0] = temp; 
  +    gtk_clist_append (GTK_CLIST (f_current->dir_list), text);
  +
  +#ifdef HAS_GTK22
  +    width = gdk_string_width(gtk_style_get_font(f_current->dir_list->style),
  +                             f_current->directory_entries[i]);
  +#else
  +    width = gdk_string_width(f_current->dir_list->style->font,
  +                             f_current->directory_entries[i]);
  +#endif
  +
  +    if (width > max_width) {
  +      gtk_clist_set_column_width(GTK_CLIST(f_current->
  +                                           dir_list), 0, width);
  +      max_width = width;
  +    }
  +
  +    free(temp);
  +#if DEBUG
  +    printf("directory: %s\n", f_current->directory_entries[i]);
  +#endif
  +  }
  +
  +  max_width = 0;
  +  for (i = 0 ; i < file_count; i++) {
  +    text[0] = f_current->file_entries[i]; 
  +    gtk_clist_append (GTK_CLIST (f_current->file_list), text);
  +
  +#ifdef HAS_GTK22
  +    width = gdk_string_width(gtk_style_get_font(f_current->dir_list->style), 
  +                             f_current->file_entries[i]);
  +#else
  +    width = gdk_string_width(f_current->dir_list->style->font,
  +                             f_current->file_entries[i]);
  +#endif
  +
  +    if (width > max_width) {
  +      gtk_clist_set_column_width(GTK_CLIST(f_current->
  +                                           file_list), 0, width);
  +      max_width = width;
  +    }
  +
  +#if DEBUG
  +    printf("file: %s\n", f_current->file_entries[i]);
  +#endif
  +  }
  +
  +  closedir(directory);
  +  gtk_clist_thaw (GTK_CLIST (f_current->file_list));
  +  gtk_clist_thaw (GTK_CLIST (f_current->dir_list));
  +  f_current->last_search = -1;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_fileselect_sch_files(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  f_current->filter_type = FILEDIALOG_SCH_ONLY;
  +  x_fileselect_fill_lists(f_current);
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_fileselect_sym_files(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  f_current->filter_type = FILEDIALOG_SYM_ONLY;
  +  x_fileselect_fill_lists(f_current);
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_fileselect_both_files(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  f_current->filter_type = FILEDIALOG_SCH_SYM;
  +  x_fileselect_fill_lists(f_current);
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_fileselect_all_files(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  f_current->filter_type = FILEDIALOG_ALL_FILES;
  +  x_fileselect_fill_lists(f_current);
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is from gtktest.c
  + */
  +static GtkWidget *x_fileselect_filter_menu (FILEDIALOG *f_current)
  +{
  +  GtkWidget *menu;
  +  GtkWidget *menuitem;
  +  GSList *group;
  +  char *buf;
  +
  +  menu = gtk_menu_new ();
  +  group = NULL;
  +
  +  buf = g_strdup_printf(_("sch - Schematics"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) x_fileselect_sch_files,
  +                     f_current);
  +  gtk_widget_show(menuitem);
  +
  +  buf = g_strdup_printf( _("sym - Symbols "));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) x_fileselect_sym_files,
  +                     f_current);
  +  gtk_widget_show(menuitem);
  +
  +  buf = g_strdup_printf(_("sym/sch - Schematics and Symbols"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) x_fileselect_both_files,
  +                     f_current);
  +  gtk_widget_show(menuitem);
  +
  +  buf = g_strdup_printf( _("* - All Files"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) x_fileselect_all_files,
  +                     f_current);
  +  gtk_widget_show(menuitem);
  +
  +  switch(f_current->filter_type) {
  +
  +    case(FILEDIALOG_SCH_ONLY):
  +      gtk_menu_set_active(GTK_MENU (menu),0);
  +      break;
  +
  +    case(FILEDIALOG_SYM_ONLY):
  +      gtk_menu_set_active(GTK_MENU (menu),1);
  +      break;
  +
  +    case(FILEDIALOG_SCH_SYM):
  +      gtk_menu_set_active(GTK_MENU (menu),2);
  +      break;
  +
  +    case(FILEDIALOG_ALL_FILES):
  +      gtk_menu_set_active(GTK_MENU (menu),3);
  +      break;
  +  }
  +
  +  return menu;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int x_fileselect_preview_checkbox(GtkWidget *widget, FILEDIALOG *f_current)
  +{
  +  if (f_current == NULL) {
  +    fprintf(stderr, _("x_fileselect_preview_checkbox: Oops got a null f_current!\n"));
  +    exit(-1);
  +  }
  +
  +  if (f_current->preview_control) {
  +    f_current->preview_control = FALSE;
  +    x_repaint_background(f_current->preview);
  +  } else {
  +    f_current->preview_control = TRUE;
  +
  +    if (f_current->directory && f_current->filename) {
  +       x_preview_update(f_current->preview, f_current->directory, 
  +	             f_current->filename);
  +    }
  +  }
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_saveas_close (GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  gtk_widget_destroy(GTK_WIDGET(f_current->xfwindow));
  +  f_current->xfwindow = NULL;
  +
  +#if 0 /* this isn't relavent anymore */
  +  w_current = f_current->toplevel;
  +
  +  if (f_current->filesel_type == SAVEAS_QUIT) {
  +    exit_dialog(w_current);
  +  }
  +
  +  if (f_current->filesel_type == SAVEAS_OPEN) {
  +    x_fileselect_setup (w_current, FILESELECT, SAVEAS_OPEN);
  +  }
  +
  +  if (f_current->filesel_type == SAVEAS_NEW) {
  +    w_current->page_current->CHANGED = 0;
  +    i_callback_file_new(w_current, 0, NULL);
  +  }
  +#endif
  +
  +  /* do nothing if close is pressed for SAVEAS_CLOSE case */
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_saveas(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  TOPLEVEL *w_current;
  +  const char *string = NULL;
  +  int len;
  +
  +  w_current = f_current->toplevel;
  +#if ((GTK_MAJOR_VERSION > 2) || \
  +     ((GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION >= 4)) )
  +  string = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(f_current->xfwindow));
  +#else
  +  string = gtk_entry_get_text(GTK_ENTRY(f_current->filename_entry));
  +#endif
  +  if (!string) {
  +    return;
  +  }
  +
  +  len = strlen(string);
  +
  +  if (string[len - 1] != G_DIR_SEPARATOR) {
  +    if (w_current->page_current->page_filename) {
  +      free(w_current->page_current->page_filename);
  +    }
  +
  +    w_current->page_current->page_filename = g_strdup (string);
  +
  +    if (f_save(w_current, string)) {
  +      s_log_message(_("Saved As [%s]\n"), 
  +                    w_current->page_current->page_filename);
  +    
  +      i_set_filename(w_current, string);
  +
  +      w_current->page_current->CHANGED = 0;
  +      x_pagesel_update (w_current);
  +    } else {
  +      s_log_message(_("Could NOT save [%s]\n"),w_current->page_current->page_filename);
  +      i_set_state_msg(w_current, SELECT, _("Error while trying to save"));
  +      i_update_toolbar(w_current);
  +    }
  +
  +    x_fileselect_close (NULL, f_current);
  +    if (f_current->filesel_type == SAVEAS_QUIT) {
  +      x_window_close(w_current);
  +    } else if (f_current->filesel_type == SAVEAS_OPEN) {
  +      i_callback_file_open(w_current, 0, NULL);
  +    } else if (f_current->filesel_type == SAVEAS_NEW) {
  +      i_callback_file_new(w_current, 0, NULL);
  +    } else if (f_current->filesel_type == SAVEAS_CLOSE) {
  +      i_callback_page_close(w_current, 0, NULL);
  +    }
  +
  +    /* do nothing if SAVEAS_NONE */
  +  } else {
  +    s_log_message(_("Specify a Filename!\n"));
  +  }
  +  if (string != NULL) {
  +    free ( (void *) string);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_change_dir(FILEDIALOG *f_current, char *new_directory)
  +{
  +  if (new_directory) {
  +    chdir(new_directory);
  +    x_fileselect_update_dirfile(f_current, NULL);
  +    x_fileselect_fill_lists(f_current);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use widget, since it can be NULL
  + *
  + *  \par SDB notes
  + *       This is the fcn which opens the file(s) selected in the "open file"
  + *       dialog box.
  + */
  +void x_fileselect_open_file(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  TOPLEVEL *w_current;
  +  PAGE *found_page;
  +  char *string;
  +  int len;
  +
  +  char *filename = NULL;
  +#if ((GTK_MAJOR_VERSION > 2) || \
  +     ((GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION >= 4)) )
  +  GSList *files;
  +#else
  +  GList *files;
  +  int row;
  +#endif
  +
  +  /* get GList of selected files  */
  +#if ((GTK_MAJOR_VERSION > 2) || \
  +     ((GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION >= 4)) )
  +  files = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER(f_current->xfwindow));
  +#else
  +  files = (GTK_CLIST(f_current->file_list))->selection;
  +#endif
  +  if (files) {
  +    /* iterate over selected files  */
  +    for (; files ; files = files->next) {     
  +#if ((GTK_MAJOR_VERSION > 2) || \
  +     ((GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION >= 4)) )
  +      filename = files->data;
  +      string = filename;
  +#else
  +      row = (int) files->data;     /* Why do we need to do cast here?  */
  +                                   /* because files->data is a void *  */
  +      gtk_clist_get_text (GTK_CLIST(f_current->file_list), row, 0, &filename);
  +      /* allocate space, then stick full, absolute filename into string */
  +      string = g_build_path (G_DIR_SEPARATOR_S,
  +                             f_current->directory,
  +                             filename,
  +                             NULL);
  +
  +#endif
  +      w_current = f_current->toplevel;
  +	
  +      len = strlen(string);
  +      if (string[len - 1] != G_DIR_SEPARATOR) {
  +        found_page = s_page_search (f_current->toplevel, string);
  +        
  +        if (found_page == NULL) {
  +          /* create a new page and make it the current page */
  +          s_page_goto (w_current,
  +                       s_page_new (w_current, string));
  +          
  +          w_current->DONT_REDRAW = 1;
  +
  +#if DEBUG
  +          printf("In x_fileselect_open_file, after checking, full filename to open = %s\n", string);
  +#endif
  +          (void)f_open(w_current, 
  +                       w_current->page_current->page_filename);
  +          i_set_filename(w_current, w_current->page_current->
  +                         page_filename);
  +
  +          x_repaint_background(w_current);
  +          x_manual_resize(w_current);
  +          a_zoom_extents(w_current, 
  +                         w_current->page_current->object_head,
  +                         A_PAN_DONT_REDRAW);
  +          o_undo_savestate(w_current, UNDO_ALL);
  +
  +          /* now update the scrollbars */
  +          x_hscrollbar_update(w_current);
  +          x_vscrollbar_update(w_current);
  +          x_pagesel_update (w_current);
  +
  +          w_current->DONT_REDRAW = 0;
  +          o_redraw_all(w_current);
  +
  +        } else {   /* page already exists . . . */
  +          s_page_goto(w_current, found_page);
  +          x_pagesel_update (w_current);
  +          i_set_filename(w_current, w_current->
  +                         page_current->page_filename);
  +          x_scrollbars_update(w_current);
  +          o_redraw_all(w_current);
  +        }
  +      } else {       /* no filename given . . . . */
  +        s_log_message(_("Specify a Filename!\n"));
  +      }
  +
  +      free(string);
  +    }       /* end for files . . .     */
  +
  +    /* Now close file dialog window . . . . */
  +    gtk_widget_destroy(GTK_WIDGET(f_current->xfwindow));
  +    f_current->xfwindow = NULL;
  +
  +#if ((GTK_MAJOR_VERSION > 2) || \
  +     ((GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION >= 4)) )
  +    g_slist_free(files);
  +#endif
  +  }     /* end of if string . . .  */                   
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \par SDB notes
  + *  This fcn is called for almost every event which occurs
  + *  to the "open file" widget, except when the actual file is to be
  + *  opened.  Stuff handled by this fcn are e.g. highlighting the file
  + *  selected in the file list, updating the dir/file lists upon change
  + *  of directory, etc.
  + */
  +void x_fileselect_dir_button (GtkWidget *widget, gint row, gint column,
  +			      GdkEventButton *bevent, FILEDIALOG *f_current)
  +{
  +  char *temp = NULL;
  +
  +  gtk_clist_get_text (GTK_CLIST (f_current->dir_list), row, 0, &temp);
  +
  +  if (temp) {	
  +#if DEBUG
  +    printf("In x_fileselect_dir_button, selected: %d _%s_\n", row, temp);
  +#endif
  +    if (bevent) {
  +      switch (bevent->type) {
  +        case(GDK_2BUTTON_PRESS):
  +          x_fileselect_change_dir(f_current, 
  +                                  temp);
  +          break;
  +
  +        default:
  +					
  +          break;
  +      }
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_file_button (GtkWidget *widget, gint row, gint column,
  +			       GdkEventButton *bevent, FILEDIALOG *f_current)
  +/*
  + * SDB notes:  This fcn is apparently called for each event occuring to
  + * the file clist.  This fcn determines if the button event captured was to
  + * update the directory/file display or was a doubleclick on a file
  + * in the clist meant to open the file.  It then
  + * calls the appropriate handler.  Unfortunately, in the event of 
  + * selecting multiple files (using ENHANCED mode), bevent is nonnull 
  + * only on the first call.
  + */
  +{
  +  char *temp = NULL;
  +
  +  /* put name of desired file into temp */
  +  gtk_clist_get_text (GTK_CLIST (f_current->file_list), row, 0, &temp);
  +
  +  if (temp) {	
  +
  +#if DEBUG
  +    printf("In x_fileselect_file_button, file selected: %d %s\n", row, temp);
  +    if (bevent) {
  +      printf("in x_fileselect_file_button, bevent->type = %d\n", bevent->type);
  +    }
  +    else {
  +      printf("In x_fileselect_file_button, bevent = NULL\n");
  +    }
  +#endif
  +    
  +    if (bevent) {
  +      switch (bevent->type) {
  +        case(GDK_2BUTTON_PRESS):
  +          x_fileselect_open_file(NULL, f_current);
  +          break;
  +
  +        default:
  +          x_fileselect_update_dirfile(
  +                                      f_current, temp);
  +          if (f_current->preview_control && f_current->directory && temp) { 
  +            x_preview_update(f_current->preview, f_current->directory, temp);
  +          }
  +          break;
  +      }
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_update_dirfile_saveas(FILEDIALOG *f_current,
  +					char *new_filename)
  +{
  +  char *temp=NULL;
  +  char *ptr=NULL;
  +  char *filename=NULL;
  +  char *directory=NULL;
  +  int i;
  +
  +  if (f_current->filename) {
  +    free(f_current->filename);
  +    f_current->filename = NULL;
  +  }
  +
  +  if (f_current->directory) {
  +    free(f_current->directory);
  +    f_current->directory = NULL;
  +  }
  +
  +  if (new_filename == NULL) {
  +    return;
  +  }
  +
  +  directory = (char *) malloc(sizeof(char)*(strlen(new_filename)+1));
  +  filename = (char *) malloc(sizeof(char)*(strlen(new_filename)+1));
  +
  +  ptr = new_filename;	
  +  temp = strrchr(new_filename, G_DIR_SEPARATOR);	
  +  if (temp) {
  +    i = 0;
  +    while(ptr != temp && ptr[0] != '\0') {
  +      directory[i] = *ptr;	
  +      ptr++;
  +      i++;
  +    }
  +    directory[i] = '\0';
  +    ptr++; /* skip over last '/' */
  +#if DEBUG
  +    printf("directory: %s\n", directory);
  +#endif
  +    i = 0;
  +    while(ptr[0] != '\0') {
  +      filename[i] = *ptr;	
  +      ptr++;	
  +      i++;
  +    }
  +    filename[i] = '\0';
  +#if DEBUG
  +    printf("filename: %s\n", filename);
  +#endif
  +  } else {
  +    printf("somehow got a filename which does not have a / in it\n");
  +  }
  +
  +  if (directory) {
  +    f_current->directory = g_strdup (directory);
  +    free(directory);
  +  }
  +
  +  if (filename) {
  +    f_current->filename = g_strdup (filename);
  +    free(filename);
  +  }
  +				
  +#ifdef __MINGW32__
  +  if (u_basic_has_trailing(f_current->directory, G_DIR_SEPARATOR)) {
  +  	temp = g_strconcat (f_current->directory, 
  +                        f_current->filename, NULL);
  +  } else { 
  +#endif
  +  	temp = g_strconcat (f_current->directory, 
  +                        G_DIR_SEPARATOR_S,
  +                        f_current->filename, NULL);
  +#ifdef __MINGW32__
  +  }
  +#endif
  +  gtk_entry_set_text(GTK_ENTRY(f_current->filename_entry), temp);
  +
  +  free(temp);
  +
  +#if DEBUG
  +  printf("directory: %s\n", f_current->directory);
  +  printf("filename: %s\n", f_current->filename);
  +#endif
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_close (GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  gtk_widget_destroy(GTK_WIDGET(f_current->xfwindow));
  +  f_current->xfwindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use widget, since it can be NULL
  + */
  +void x_fileselect_search(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  TOPLEVEL *w_current;
  +  const char *string;
  +  int i;
  +
  +  w_current = f_current->toplevel;
  +
  +  string = gtk_entry_get_text(GTK_ENTRY(f_current->search_entry));
  +	
  +  if (!string) {
  +    return;
  +  }
  +
  +  gtk_entry_select_region(GTK_ENTRY(f_current->search_entry), 0, -1);
  +
  +#if 0 /* not used right now */
  +  /* search directories */
  +  i = 0;
  +  if (f_current->file_entries[0] == NULL) {
  +    while (f_current->directory_entries[i] != NULL) {
  +      printf("compare: %s %s\n", f_current->directory_entries[i], string);
  +      if (strstr(f_current->directory_entries[i], string)) {
  +
  +				/*text[0] = f_current->directory_entries[i];
  +                                  text[1] = NULL; 
  +                                  row = gtk_clist_find_row_from_data(GTK_CLIST(
  +                                  f_current->dir_list),
  +                                  f_current->directory_entries[i]);
  +				*/
  +				
  +        gtk_clist_select_row(GTK_CLIST(
  +                                       f_current->dir_list), 
  +                             i, 0);
  +        printf("%d found: %s\n", i, f_current->directory_entries[i]);
  +				
  +				/*x_fileselect_update_dirfile(f_current, NULL);
  +                                  x_fileselect_fill_lists(f_current);*/
  +        return;
  +      }
  +      i++;
  +    }
  +  }
  +#endif
  +
  +  if (f_current->last_search != -1) {
  +    i = f_current->last_search;	
  +    gtk_label_set(GTK_LABEL(f_current->search_label), 
  +                  _("Search in Files")); 
  +  } else {
  +    gtk_label_set(GTK_LABEL(f_current->search_label), 
  +                  _("Search in Files")); 
  +    i = 0;
  +  }
  +
  +  while (f_current->file_entries[i] != NULL) {
  +    if (strstr(f_current->file_entries[i], string)) {
  +      gtk_clist_select_row(GTK_CLIST(f_current->file_list), 
  +                           i, 0);
  +
  +      gtk_clist_moveto(GTK_CLIST(
  +                                 f_current->file_list), 
  +                       i, 0, -1, -1);
  +
  +      x_fileselect_update_dirfile(f_current, 
  +                                  f_current->file_entries[i]);
  +      f_current->last_search = i + 1;
  +      return;
  +    }
  +    i++;
  +  }
  +  f_current->last_search = -1;
  +  gtk_label_set(GTK_LABEL(f_current->search_label), 
  +		_("Search in Files - End of list")); 
  +}
  +/*********** File Open/Save As... specific code ends here ***********/
  +
  +/*********** Component Place specific code starts here **************/
  +/*! \section component-place-specific-code Component Place Specific Code.
  + *  \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint default_components(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->embed_complex = 0;
  +  w_current->include_complex = 0;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint embed_components(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->embed_complex = 1;
  +  w_current->include_complex = 0;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint include_components(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->include_complex = 1;
  +  w_current->embed_complex = 0;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is from gtktest.c
  + */
  +static GtkWidget *create_menu (TOPLEVEL *w_current)
  +{
  +  GtkWidget *menu;
  +  GtkWidget *menuitem;
  +  GSList *group;
  +  char *buf;
  +
  +  menu = gtk_menu_new ();
  +  group = NULL;
  +
  +  buf = g_strdup_printf(_("Default behavior - reference component"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) default_components,
  +                     w_current);
  +
  +  gtk_widget_show(menuitem);
  +
  +  buf = g_strdup_printf(_("Embed component in schematic"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) embed_components,
  +                     w_current);
  +  gtk_widget_show(menuitem);
  +
  +  buf = g_strdup_printf(_("Include component as individual objects"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) include_components,
  +                     w_current);
  +  gtk_widget_show(menuitem);
  +
  +  if (w_current->embed_complex) {
  +    gtk_menu_set_active(GTK_MENU (menu),1);
  +    embed_components(NULL, w_current);
  +  } else {
  +    default_components(NULL, w_current);
  +  }
  +
  +  return menu;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_comp_fill_libs(TOPLEVEL *w_current, FILEDIALOG *f_current)
  +{
  +  char *text[2];
  +  char *temp;
  +  int i;
  +  int max_width=0;
  +  int width;
  +  int first,last,done,j;		/* variables for the sort */
  +  const GSList *dirs, *dir;
  +
  +  gtk_clist_freeze (GTK_CLIST (f_current->dir_list));
  +  gtk_clist_clear (GTK_CLIST (f_current->dir_list));
  +
  +  i = 0;
  +  text[0] = NULL;
  +  text[1] = NULL;
  +  max_width = 0;
  +
  +  /* populate the directory list */
  +  dirs = s_clib_get_directories ();
  +  for (dir = dirs; dir != NULL; dir = g_slist_next (dir)) {
  +    gchar *string = (gchar*)dir->data;
  +
  +    temp = strrchr(string, G_DIR_SEPARATOR);
  +    if (temp) {
  +      temp++; /* get past last '/' */
  +      text[0] = temp;
  +    } else {
  +      text[0] = string;
  +    }
  +
  +    f_current->directory_entries[i++] = g_strdup (string);
  +    
  +    gtk_clist_append (GTK_CLIST (f_current->dir_list), text);
  +
  +#ifdef HAS_GTK22
  +    width = gdk_string_width(gtk_style_get_font(f_current->dir_list->style), 
  +                             text[0]);
  +#else
  +    width = gdk_string_width(f_current->dir_list->style->font,
  +                             text[0]);
  +#endif
  +
  +    if (width > max_width) {
  +      gtk_clist_set_column_width(GTK_CLIST(f_current->
  +                                           dir_list), 0, width);
  +      max_width = width;
  +    }
  +  }
  +
  +  gtk_clist_thaw (GTK_CLIST (f_current->dir_list));
  +  f_current->last_search_lib = -1;
  +
  +  /* added sort for the directory list so it would match the 
  +     automatically sorted clist of directories
  +     Chris Ellec - May 2001                           */
  +  if (w_current->sort_component_library == TRUE) {
  +    done = 0;
  +    first = 0;
  +    last = i;
  +    while(!done) {
  +      done = 1;
  +      for (j = first ; j < last-1; j++) {
  +        /*printf ("%i:",j);*/
  +        if (strcmp(f_current->directory_entries[j], 
  +                   f_current->directory_entries[j+1]) > 0) {
  +          temp = f_current->directory_entries[j];
  +          f_current->directory_entries[j] = 
  +            f_current->directory_entries[j+1];
  +          f_current->directory_entries[j+1] = temp;
  +          done = 0;
  +        }
  +      }
  +      last = last - 1;
  +
  +#if DEBUG 
  +      pass_count++;
  +#endif
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_comp_fill_components(FILEDIALOG *f_current, int row)
  +{
  +  GSList *filenames, *filename;
  +  gint width = 0, max_width = 0;
  +	
  +  gtk_clist_freeze (GTK_CLIST (f_current->file_list));
  +  gtk_clist_clear (GTK_CLIST (f_current->file_list));
  +
  +  /* update current_clib in toplevel with new directory name */
  +  if (f_current->toplevel->current_clib) {
  +    free (f_current->toplevel->current_clib);
  +  }
  +  f_current->toplevel->current_clib = g_strdup (
  +    f_current->directory_entries[row]);
  +
  +  /* get the list of filenames in directory */
  +  filenames = s_clib_get_files (f_current->directory_entries[row], ".sym");
  +
  +  filename = filenames;
  +  while (filename != NULL) {
  +    gchar *text[2];
  +
  +    text[0] = (gchar*) filename->data;
  +    text[1] = NULL;
  +    
  +    /* add filename to the clist */
  +    gtk_clist_append (GTK_CLIST (f_current->file_list), text);
  +    
  +#ifdef HAS_GTK22
  +    width = gdk_string_width (gtk_style_get_font (
  +                                f_current->file_list->style),
  +                              (gchar*) filename->data);
  +#else
  +    width = gdk_string_width (f_current->file_list->style->font,
  +                              (gchar*) filename->data);
  +#endif
  +    if (width > max_width) {
  +      /* increase the width of the column */
  +      gtk_clist_set_column_width (GTK_CLIST (f_current->file_list),
  +                                  0, width);
  +      max_width = width;
  +    }
  +    
  +    /* continue with the next filename */
  +    filename = g_slist_next (filename);
  +  }
  +
  +  /* get ride of the list of filenames */
  +  g_slist_foreach (filenames, (GFunc)free, NULL);
  +  g_slist_free (filenames);
  +
  +  /* allow visual updates to clist */
  +  gtk_clist_thaw (GTK_CLIST (f_current->file_list));
  +      
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't pass in f_current->filename or f_current->directory for component
  + *  or library
  + */
  +void x_fileselect_comp_update_current(FILEDIALOG *f_current, 
  +				      char *library, char *component)
  +{
  +  char *temp=NULL;
  +
  +  /* component */
  +  if (f_current->filename) {
  +    free(f_current->filename);
  +    f_current->filename = NULL;
  +  }
  +
  +  /* library */
  +  if (f_current->directory) {
  +    free(f_current->directory);
  +    f_current->directory = NULL;
  +  }
  +
  +  if (library) {
  +    f_current->directory = g_strdup(library);
  +  } else {
  +    f_current->directory = NULL;
  +  }
  +
  +  if (component) {
  +    f_current->filename = g_strdup(component);
  +  } else {
  +    f_current->filename = NULL;
  +  }
  +
  +  if (f_current->directory && f_current->filename) {
  +#ifdef __MINGW32__
  +    if (u_basic_has_trailing(f_current->directory, G_DIR_SEPARATOR)) {
  +    	temp = g_strconcat (f_current->directory, 
  +                            f_current->filename, NULL);
  +    } else {
  +#endif
  +    	temp = g_strconcat (f_current->directory, 
  +                            G_DIR_SEPARATOR_S,
  +                            f_current->filename, NULL);
  +#ifdef __MINGW32__
  +    }
  +#endif
  +    gtk_entry_set_text(GTK_ENTRY(f_current->filename_entry), temp);
  +    free(temp);
  +  } else if (f_current->directory && !f_current->filename) {
  +    gtk_entry_set_text(GTK_ENTRY(f_current->filename_entry), 
  +                       f_current->directory);
  +  } else if (!f_current->directory) {
  +    gtk_entry_set_text(GTK_ENTRY(f_current->filename_entry), 
  +                       "NONE");
  +  }
  +
  +#if 0 /* old code */
  +  if (f_current->directory && f_current->filename) {
  +    temp = g_strconcat (f_current->directory, 
  +                        f_current->filename, NULL);
  +    gtk_label_set(GTK_LABEL(f_current->filename_entry), temp);
  +  } else if (f_current->directory && !f_current->filename) {
  +    gtk_label_set(GTK_LABEL(f_current->filename_entry), 
  +                  f_current->directory);
  +  } else if (!f_current->directory) {
  +    gtk_label_set(GTK_LABEL(f_current->filename_entry), 
  +                  " ");
  +  }
  +#endif
  +
  +#if DEBUG 
  +  printf("directory: %s\n", f_current->directory);
  +  printf("filename: %s\n", f_current->filename);
  +#endif
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_change_clib(FILEDIALOG *f_current, char *new_clib,
  +			      int row)
  +{
  +  x_fileselect_comp_update_current(f_current, new_clib, NULL);
  +  x_fileselect_comp_fill_components(f_current, row);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_lib_select (GtkWidget *widget, gint row, gint column,
  +			      GdkEventButton *bevent, FILEDIALOG *f_current)
  +{
  +  char *temp = NULL;
  +
  +  gtk_clist_get_text (GTK_CLIST (f_current->dir_list), row, 0, &temp);
  +
  +  if (temp) {	
  +#if DEBUG 
  +    printf("selected: %d _%s_ _%s_\n", row, temp, 
  +           f_current->directory_entries[row]);
  +#endif
  +    if (bevent) {
  +      switch (bevent->type) {
  +        /*	case(GDK_2BUTTON_PRESS): */
  +        default:
  +          x_fileselect_change_clib(f_current, 
  +                                   f_current->directory_entries[row],
  +                                   row);
  +          break;
  +
  +      }
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_comp_select (GtkWidget *widget, gint row, gint column,
  +			       GdkEventButton *bevent, FILEDIALOG *f_current)
  +{
  +  char *comp = NULL;
  +  int diff_x, diff_y;
  +  TOPLEVEL *w_current;
  +
  +  w_current = f_current->toplevel;
  +
  +  gtk_clist_get_text (GTK_CLIST (f_current->file_list), row, 0, &comp);
  +
  +  if (comp) {	
  +    strcpy(w_current->current_basename, comp);
  +
  +    if (f_current->preview_control && w_current->current_clib && comp) { 
  +      x_preview_update(f_current->preview, 
  +                       w_current->current_clib,
  +                       comp);
  +    }
  +
  +    x_fileselect_comp_update_current(f_current, 
  +                                     w_current->current_clib, comp);
  +
  +    if (w_current->event_state == ENDCOMP) {
  +      diff_x = w_current->last_x - w_current->start_x;
  +      diff_y = w_current->last_y - w_current->start_y;
  +
  +      o_complex_translate_display(w_current,
  +                                  diff_x, diff_y,
  +                                  w_current->page_current->complex_place_head);
  +    }
  +
  +    o_list_delete_rest(w_current,
  +                       w_current->page_current->complex_place_head);
  +    o_complex_set_filename(w_current, w_current->current_clib,
  +                           w_current->current_basename);
  +
  +    w_current->event_state = DRAWCOMP;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_comp_apply(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  TOPLEVEL *w_current;
  +  int diff_x, diff_y;
  +	
  +  w_current = f_current->toplevel;
  +
  +  if (w_current->current_basename && w_current->current_clib) {
  +    if (w_current->event_state == ENDCOMP) {
  +      diff_x = w_current->last_x - w_current->start_x;
  +      diff_y = w_current->last_y - w_current->start_y;
  +
  +      o_complex_translate_display(w_current,
  +                                  diff_x, diff_y,
  +                                  w_current->page_current->complex_place_head);
  +    }
  +
  +    o_list_delete_rest(w_current,
  +                       w_current->page_current->complex_place_head);
  +    o_complex_set_filename(w_current, w_current->current_clib,
  +                           w_current->current_basename);
  +
  +    w_current->event_state = DRAWCOMP;
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_comp_close (GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  TOPLEVEL *w_current;
  +
  +  w_current = f_current->toplevel;
  +
  +  /* erase any existing component while it's being placed */
  +  /* do this instead of the below o_redraw_all */
  +  if (w_current->inside_action &&
  +      (w_current->event_state == ENDCOMP ||
  +       w_current->event_state == DRAWCOMP)) {
  +    o_complex_rubbercomplex(w_current);
  +  }
  +
  +  o_list_delete_rest(w_current, w_current->page_current->
  +                     complex_place_head);
  +
  +  i_set_state(w_current, SELECT);
  +  i_update_toolbar(w_current);
  +
  +  gtk_widget_destroy(GTK_WIDGET(f_current->xfwindow));
  +  f_current->xfwindow = NULL;
  +  /* do nothing if close is pressed for SAVEAS_CLOSE case */
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int x_fileselect_search_library(FILEDIALOG *f_current,
  +				char *library, const char *string) 
  +{
  +  GSList *filenames, *filename;
  +  int ret;
  +
  +  /* get the filenames with '.sym' in library */
  +  filenames = s_clib_get_files(library, ".sym");
  +
  +  if (f_current->last_search == -1) {
  +    /* last search failed: start over */
  +    f_current->last_search = 0;
  +  }
  +
  +  /* start search from last known position */
  +  filename = g_slist_nth (filenames, (guint)f_current->last_search);
  +  while (filename != NULL) {
  +    /* increase position in search */
  +    f_current->last_search++;
  +
  +    /* does filename match the query? */
  +    if (strstr ((gchar*) filename->data, string)) {
  +      /* yes, stop the search, prepare to return last_search */
  +#if DEBUG
  +      printf("found: %s %s %s %d\n", library, filename->data, string, f_current->last_search - 1);
  +#endif
  +      break;
  +    }
  +    
  +    filename = g_slist_next (filename);
  +  }
  +
  +  /* free the list of filenames */
  +  g_slist_foreach (filenames, (GFunc)free, NULL);
  +  g_slist_free (filenames);
  +
  +  /* nothing found? */
  +  if (filename == NULL) {
  +    /* no, reset for next search */
  +    f_current->last_search = -1;
  +    ret = -1;
  +  } else {
  +    /* yes, return the position in the list of the filename found */
  +    ret = f_current->last_search - 1;
  +  }
  +
  +  return ret;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  don't use widget, since it can be NULL
  + */
  +void x_fileselect_comp_search(GtkWidget *w, FILEDIALOG *f_current)
  +{
  +  TOPLEVEL *w_current;
  +  const char *string;
  +  int lib_count;
  +  int flag;
  +
  +  w_current = f_current->toplevel;
  +
  +  string = gtk_entry_get_text(GTK_ENTRY(f_current->search_entry));
  +	
  +  if (!string) {
  +    return;
  +  }
  +
  +  gtk_entry_select_region(GTK_ENTRY(f_current->search_entry), 0, -1);
  +
  +  if (f_current->last_search_lib != -1) {
  +    lib_count = f_current->last_search_lib;	
  +    gtk_label_set(GTK_LABEL(f_current->search_label),
  +                  _("Search in Components")); 
  +  } else {
  +    lib_count = 0;
  +    gtk_label_set(GTK_LABEL(f_current->search_label),
  +                  _("Search in Components")); 
  +  }
  +
  +  while(f_current->directory_entries[lib_count] != NULL) {
  +    flag = x_fileselect_search_library(f_current, 
  +                                       f_current->directory_entries[lib_count], 
  +                                       string);
  +    if (flag != -1) {
  +      gtk_clist_select_row(GTK_CLIST(f_current->dir_list), 
  +                           lib_count, 0);
  +
  +      gtk_clist_moveto(GTK_CLIST(
  +                                 f_current->dir_list), 
  +                       lib_count, 0, -1, -1);
  +
  +      x_fileselect_change_clib(f_current, 
  +                               f_current->
  +                               directory_entries[lib_count],
  +                               lib_count);
  +
  +      gtk_clist_select_row(GTK_CLIST(f_current->file_list), 
  +                           flag, 0);
  +
  +      gtk_clist_moveto(GTK_CLIST(
  +                                 f_current->file_list), 
  +                       flag, 0, -1, -1);
  +
  +      f_current->last_search_lib = lib_count; 
  +      return;
  +    } else {
  +      lib_count++;
  +    }
  +  }
  +
  +
  +  f_current->last_search_lib = -1;
  +  f_current->last_search = -1;
  +
  +#if 0 /* I'm not sure this is worth the effort and the confusion it causes */
  +  /* now search the library names */
  +  lib_count = 0;
  +  while(f_current->directory_entries[lib_count] != NULL) {
  +    if (strstr(f_current->directory_entries[lib_count], string)) {
  +
  +      printf("%s %s\n", f_current->directory_entries[lib_count], string);
  +
  +      gtk_clist_select_row(GTK_CLIST(f_current->dir_list), 
  +                           lib_count, 0);
  +
  +      gtk_clist_moveto(GTK_CLIST(
  +                                 f_current->dir_list), 
  +                       lib_count, 0, -1, -1);
  +
  +      x_fileselect_change_clib(f_current, 
  +                               f_current->
  +                               directory_entries[lib_count],
  +                               lib_count);
  +
  +      gtk_label_set(GTK_LABEL(f_current->search_label),
  +                    _("Search in Components - Found library only")); 
  +      return;
  +    }
  +    lib_count++;
  +  }
  +  f_current->last_search_lib = -1;
  +#endif
  +
  +  gtk_label_set(GTK_LABEL(f_current->search_label),
  +                _("Search in Components - End of list")); 
  +
  +}
  +/*********** Component Place specific code ends here **************/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_fileselect_setup_old (TOPLEVEL *w_current, int type, int filesel_type)
  +{
  +  GtkWidget *buttonapply = NULL;
  +  GtkWidget *buttonclose = NULL;
  +  GtkWidget *scrolled_win;
  +  GtkWidget *action_area;
  +  GtkWidget *separator;
  +  GtkWidget *optionmenu;
  +  GtkWidget *drawbox;
  +  GtkWidget *label;
  +  GtkWidget *searchbox;
  +	
  +  FILEDIALOG *f_current;
  +
  +  GtkWidget *vbox;
  +  GtkWidget *list_hbox;
  +  char *dir_title [2];
  +  char *file_title [2];
  +
  +
  +  if (type < 0 || type > 2) {
  +    return;
  +  }
  +
  +  f_current = &w_current->fileselect[type];
  +
  +  if (!f_current->xfwindow) {
  +
  +    f_current->xfwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  +    f_current->toplevel = w_current;
  +    f_current->type = type;
  +    f_current->filesel_type = filesel_type;
  +    f_current->last_search = -1;
  +    f_current->filename = NULL;
  +    f_current->directory = NULL;
  +
  +    if (type == FILESELECT) {
  +
  +      gtk_window_position(GTK_WINDOW(f_current->xfwindow),
  +                          GTK_WIN_POS_MOUSE);
  +
  +      if (filesel_type == OPEN) {
  +        gtk_window_set_title(GTK_WINDOW(
  +                                        f_current->xfwindow),
  +                             _("Open..."));
  +      } else if (filesel_type == SAVEAS) {
  +        gtk_window_set_title(GTK_WINDOW(
  +                                        f_current->xfwindow),
  +                             _("Save As..."));
  +      } else if (filesel_type == SAVEAS_CLOSE) {
  +        gtk_window_set_title(GTK_WINDOW(
  +                                        f_current->xfwindow),
  +                             _("Save As..."));
  +      }
  +    } else {
  +      gtk_window_position(GTK_WINDOW(f_current->xfwindow),
  +                          GTK_WIN_POS_NONE);
  +      gtk_window_set_title(GTK_WINDOW(f_current->xfwindow),
  +                           _("Select Component..."));
  +    }
  +
  +    gtk_signal_connect(GTK_OBJECT(f_current->xfwindow),
  +                       "destroy",
  +                       GTK_SIGNAL_FUNC(x_fileselect_destroy_window),
  +                       f_current);
  +
  +    gtk_signal_connect(GTK_OBJECT(f_current->xfwindow), "key_press_event",
  +                       (GtkSignalFunc) x_fileselect_keypress, f_current);
  +
  +    vbox = gtk_vbox_new (FALSE, 0);
  +    gtk_container_set_border_width(GTK_CONTAINER (
  +                                                  f_current->xfwindow), 10);
  +    gtk_container_add(GTK_CONTAINER (f_current->xfwindow), 
  +                      vbox);
  +    gtk_widget_show (vbox);
  +
  +#if 0
  +    action_area = gtk_hbox_new (TRUE, 0);
  +    gtk_container_set_border_width(GTK_CONTAINER (
  +                                                  f_current->xfwindow), 10);
  +    gtk_box_pack_end(GTK_BOX (vbox), action_area, FALSE, FALSE, 0);
  +    gtk_widget_show (action_area);
  +#endif
  +
  +    action_area = gtk_hbutton_box_new ();
  +    gtk_button_box_set_layout(GTK_BUTTON_BOX(action_area), 
  +                              GTK_BUTTONBOX_END);
  +    gtk_button_box_set_spacing(GTK_BUTTON_BOX(action_area), 5);
  +    gtk_box_pack_end (GTK_BOX (vbox), action_area, TRUE, FALSE, 10);
  +    gtk_widget_show (action_area);
  +
  +
  +    /*  ----- Create the filter selection area -----  */
  +    if (type == FILESELECT) {
  +      f_current->filter_type = FILEDIALOG_SCH_ONLY;
  +    } else {
  +      f_current->filter_type = FILEDIALOG_SYM_ONLY;
  +    }
  +
  +    if (type == FILESELECT) {
  +      label=gtk_label_new(_("Filter"));
  +      gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
  +      gtk_box_pack_start(GTK_BOX(vbox), label, 
  +                         FALSE, FALSE, 0);
  +      gtk_widget_show(label);
  +
  +      f_current->filter = gtk_option_menu_new ();
  +      gtk_option_menu_set_menu(GTK_OPTION_MENU(f_current->filter),
  +                               x_fileselect_filter_menu(f_current));
  +      /* gtk_option_menu_set_history(GTK_OPTION_MENU(f_current->filter),
  +         4);*/
  +      gtk_box_pack_start(GTK_BOX(vbox), f_current->filter, 
  +                         FALSE, FALSE, 0);
  +      gtk_widget_show (f_current->filter);
  +    }
  +
  +    list_hbox = gtk_hbox_new (FALSE, 5);
  +    gtk_box_pack_start (GTK_BOX (vbox), list_hbox, TRUE, TRUE, 0);
  +    gtk_widget_show (list_hbox);
  +
  +    separator = gtk_hseparator_new ();
  +    gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, TRUE, 0);
  +    gtk_widget_show (separator);
  +
  +#if 0 /* for demonstration only */
  +    frame = gtk_frame_new (NULL);
  +    gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
  +    gtk_widget_show (frame);
  +    /*		gtk_container_add (GTK_CONTAINER (frame), drawbox); */
  +#endif
  +
  +    drawbox = gtk_hbox_new (FALSE, 0);
  +    gtk_box_pack_start (GTK_BOX (vbox), drawbox, TRUE, FALSE, 5);
  +    gtk_widget_show (drawbox);
  +
  +    searchbox = gtk_vbox_new (FALSE, 0);
  +    gtk_box_pack_end (GTK_BOX (drawbox), searchbox, TRUE, TRUE, 10);
  +    gtk_widget_show (searchbox);
  +
  +    
  +    /*  -----  Create the "directories"/"libraries" clist widgets -----  */
  +    if (type == FILESELECT) {
  +      dir_title[0] = g_strdup(_("Directories"));
  +    } else {
  +      dir_title[0] = g_strdup(_("Libraries"));
  +    }
  +    dir_title[1] = NULL;
  +    f_current->dir_list = gtk_clist_new_with_titles(1, 
  +                                                    (char**) dir_title);
  +    gtk_widget_set_usize(f_current->dir_list, 
  +                         DIR_LIST_WIDTH, DIR_LIST_HEIGHT);
  +    if (type == FILESELECT) {
  +      gtk_signal_connect (GTK_OBJECT (f_current->dir_list), 
  +                          "select_row", (GtkSignalFunc) 
  +                          x_fileselect_dir_button, f_current);
  +    } else {
  +      gtk_signal_connect (GTK_OBJECT (f_current->dir_list), 
  +                          "select_row", (GtkSignalFunc) 
  +                          x_fileselect_lib_select, f_current);
  +    } 
  +    gtk_clist_column_titles_passive(GTK_CLIST(f_current->dir_list));
  +
  +    scrolled_win = gtk_scrolled_window_new(NULL, NULL);
  +    gtk_container_add(GTK_CONTAINER (scrolled_win), 
  +                      f_current->dir_list);
  +    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(
  +                                                       scrolled_win),
  +                                   GTK_POLICY_AUTOMATIC, 
  +                                   GTK_POLICY_ALWAYS);
  +    gtk_container_set_border_width(GTK_CONTAINER (scrolled_win), 5);
  +    gtk_box_pack_start(GTK_BOX (list_hbox), scrolled_win, 
  +                       TRUE, TRUE, 0);
  +    if (w_current->sort_component_library) {
  +      gtk_clist_set_auto_sort(GTK_CLIST(f_current->dir_list), TRUE);
  +    }
  +    gtk_widget_show (f_current->dir_list);
  +    gtk_widget_show (scrolled_win);
  +    free(dir_title[0]);
  +    
  +    /*  ----- Create the files clist -----  */
  +    if (type == FILESELECT) {
  +      file_title[0] = g_strdup (_("Files"));
  +    } else {
  +      file_title[0] = g_strdup (_("Components"));
  +    }
  +    file_title[1] = NULL;
  +    f_current->file_list = gtk_clist_new_with_titles(1, 
  +                                                     (gchar**) file_title);
  +    gtk_widget_set_usize(f_current->file_list, 
  +                         FILE_LIST_WIDTH, FILE_LIST_HEIGHT);
  +    
  +    /*  Stuff added by SDB to enable opening multiple files at once   */
  +    if (type == FILESELECT) {
  +      gtk_clist_set_selection_mode(GTK_CLIST(f_current->file_list),
  +                                   GTK_SELECTION_EXTENDED);
  +    }	
  +
  +    if (type == FILESELECT) {
  +      gtk_signal_connect(GTK_OBJECT (f_current->file_list), 
  +                         "select_row", 
  +                         /* This is file opening callback */
  +                         (GtkSignalFunc) x_fileselect_file_button, 
  +                         f_current);
  +    } else {
  +      gtk_signal_connect(GTK_OBJECT (f_current->file_list), 
  +                         "select_row",
  +                         (GtkSignalFunc) x_fileselect_comp_select,
  +                         f_current);
  +    }
  +    gtk_clist_column_titles_passive(GTK_CLIST(f_current->file_list));
  +
  +    scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  +    gtk_container_add(GTK_CONTAINER(scrolled_win), 
  +                      f_current->file_list);
  +    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(
  +                                                       scrolled_win),
  +                                   GTK_POLICY_AUTOMATIC, 
  +                                   GTK_POLICY_ALWAYS);
  +    gtk_container_set_border_width(GTK_CONTAINER(scrolled_win), 5);
  +    gtk_box_pack_start(GTK_BOX (list_hbox), scrolled_win, 
  +                       TRUE, TRUE, 0);
  +    if (w_current->sort_component_library) {
  +      gtk_clist_set_auto_sort(GTK_CLIST(f_current->file_list), TRUE);
  +    }
  +    gtk_widget_show (f_current->file_list);
  +    gtk_widget_show (scrolled_win);
  +    free(file_title[0]);
  +
  +    /*  ----- create the preview widget -----  */
  +    f_current->preview = x_preview_setup(f_current->xfwindow, 
  +                                         drawbox);
  +
  +    f_current->preview_checkbox = gtk_check_button_new_with_label(
  +                                                                  _("Preview"));
  +    gtk_box_pack_start(GTK_BOX(searchbox), 
  +                       f_current->preview_checkbox, 
  +                       FALSE, FALSE, 0);
  +    /* other checkbox stuff is done AFTER drawing area is mapped */
  +    gtk_widget_show(f_current->preview_checkbox);
  +
  +    /* -----  Create the search input text box -----  */
  +    if (f_current->type == FILESELECT) {
  +      f_current->search_label=gtk_label_new(_("Search in Files"));
  +    } else {
  +      f_current->search_label=gtk_label_new(_("Search in Components"));
  +    }
  +    gtk_misc_set_alignment(GTK_MISC(f_current->search_label), 0, 0);
  +    gtk_box_pack_start(GTK_BOX(searchbox), f_current->search_label,
  +                       FALSE, FALSE, 5);
  +    gtk_widget_show(f_current->search_label);
  +
  +
  +    f_current->search_entry = gtk_entry_new_with_max_length (255);
  +    gtk_editable_select_region(GTK_EDITABLE(
  +                                            f_current->search_entry), 0, -1);
  +    gtk_box_pack_start(GTK_BOX (searchbox), 
  +                       f_current->search_entry, FALSE, FALSE, 0);
  +    if (type == FILESELECT) { 
  +      gtk_signal_connect(GTK_OBJECT(f_current->search_entry), 
  +                         "activate", 
  +                         GTK_SIGNAL_FUNC(x_fileselect_search),
  +                         f_current);
  +    } else {
  +      gtk_signal_connect(GTK_OBJECT(f_current->search_entry), 
  +                         "activate", 
  +                         GTK_SIGNAL_FUNC(x_fileselect_comp_search),
  +                         f_current);
  +    }
  +    gtk_widget_grab_focus(f_current->search_entry);
  +    gtk_widget_show(f_current->search_entry);
  +
  +    /*  ----- Create the "Filename" text entry area -----  */
  +    if (type == COMPSELECT) {
  +      optionmenu = gtk_option_menu_new ();
  +      gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu),
  +                               create_menu (w_current));
  +      gtk_box_pack_start(GTK_BOX(vbox), optionmenu, 
  +                         FALSE, FALSE, 10);
  +      gtk_widget_show (optionmenu);
  +    }
  +
  +    label=gtk_label_new(_("Filename"));
  +    gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
  +    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 5);
  +    gtk_widget_show(label);
  +
  +    f_current->filename_entry = 
  +      gtk_entry_new_with_max_length(1024);
  +    gtk_editable_select_region(GTK_EDITABLE(
  +                                            f_current->filename_entry), 0, -1);
  +    gtk_box_pack_start(GTK_BOX (vbox), 
  +                       f_current->filename_entry, FALSE, FALSE, 0);
  +
  +    if (type == FILESELECT) {
  +      if (filesel_type == OPEN) {
  +        gtk_signal_connect(GTK_OBJECT(f_current->filename_entry),
  +                           /* Here we connect the callback to
  +                              fileselect_open_file to the filename in
  +                              the filename text entry field..  */
  +                           "activate", 
  +                           GTK_SIGNAL_FUNC(
  +					   x_fileselect_open_file),
  +                           f_current);
  +      } else if ((filesel_type == SAVEAS_NONE) ||
  +                 (filesel_type == SAVEAS_QUIT) ||
  +                 (filesel_type == SAVEAS_OPEN) ||
  +                 (filesel_type == SAVEAS_CLOSE) ||
  +                 (filesel_type == SAVEAS_NEW)) { 
  +        gtk_signal_connect(GTK_OBJECT(
  +                                      f_current->filename_entry), 
  +                           "activate", 
  +                           GTK_SIGNAL_FUNC(x_fileselect_saveas),
  +                           f_current);
  +      }
  +      gtk_editable_select_region(GTK_EDITABLE(
  +                                              f_current->filename_entry), 0, -1);
  +    } else {
  +      gtk_entry_set_editable(GTK_ENTRY(
  +                                       f_current->filename_entry), FALSE);
  +    }
  +	
  +    gtk_widget_show(f_current->filename_entry);
  +
  +    /*  ----- Here we create the "open"/"save as"/"apply" buttons -----  */
  +    if (filesel_type == OPEN) {
  +#ifdef HAS_GTK12
  +      buttonapply = gtk_button_new_with_label (_("Open"));
  +#else
  +      buttonapply = gtk_button_new_from_stock (GTK_STOCK_OPEN);
  +#endif
  +      gtk_signal_connect(GTK_OBJECT(buttonapply),
  +                         /* Here we attach callback fileselect_open_file to
  +                            the "Open" button */
  +                         "clicked",
  +                         /* here's where I need another handler */
  +                         GTK_SIGNAL_FUNC(x_fileselect_open_file),
  +                         f_current);
  +    } else if ((filesel_type == SAVEAS_NONE) ||
  +               (filesel_type == SAVEAS_QUIT) ||
  +               (filesel_type == SAVEAS_OPEN) ||
  +               (filesel_type == SAVEAS_CLOSE) ||
  +               (filesel_type == SAVEAS_NEW)) { 
  +#ifdef HAS_GTK12
  +      buttonapply = gtk_button_new_with_label (_("SaveAs"));
  +#else
  +      buttonapply = gtk_button_new_from_stock (GTK_STOCK_SAVE_AS);
  +#endif
  +      gtk_signal_connect(GTK_OBJECT(buttonapply),
  +                         "clicked",
  +                         GTK_SIGNAL_FUNC(x_fileselect_saveas),
  +                         f_current);
  +    } else if (type == COMPSELECT) {
  +#ifdef HAS_GTK12
  +      buttonapply = gtk_button_new_with_label (_("Apply"));
  +#else
  +      buttonapply = gtk_button_new_from_stock (GTK_STOCK_APPLY);
  +#endif
  +      gtk_signal_connect(GTK_OBJECT(buttonapply),
  +                         "clicked",
  +                         GTK_SIGNAL_FUNC(x_fileselect_comp_apply),
  +                         f_current);
  +    }
  +
  +    GTK_WIDGET_SET_FLAGS(buttonapply, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area),
  +                       buttonapply, TRUE, TRUE, 0);
  +    /* This makes the "open" button the default */
  +    gtk_widget_grab_default (buttonapply);
  +    gtk_widget_show(buttonapply);
  +
  +    /*  ----- Here we create the "cancel"/"close" buttons -----  */
  +    if (type == FILESELECT) {
  +      if (filesel_type == OPEN) {
  +#ifdef HAS_GTK12
  +        buttonclose = gtk_button_new_with_label (
  +                                                 _("Cancel"));
  +#else
  +	buttonclose = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +        GTK_WIDGET_SET_FLAGS(buttonclose, 
  +                             GTK_CAN_DEFAULT);
  +        gtk_box_pack_start(GTK_BOX(action_area),
  +                           buttonclose, TRUE, TRUE, 0);
  +        gtk_signal_connect(GTK_OBJECT(buttonclose),
  +                           "clicked",
  +                           GTK_SIGNAL_FUNC(x_fileselect_close),
  +                           f_current);
  +        gtk_widget_show(buttonclose);
  +
  +        x_fileselect_update_dirfile(f_current, NULL);
  +        x_fileselect_fill_lists(f_current);
  +      } else if ((filesel_type == SAVEAS_NONE) ||
  +                 (filesel_type == SAVEAS_QUIT) ||
  +                 (filesel_type == SAVEAS_OPEN) ||
  +                 (filesel_type == SAVEAS_CLOSE) ||
  +                 (filesel_type == SAVEAS_NEW)) { 
  +#ifdef HAS_GTK12
  +        buttonclose = gtk_button_new_with_label (
  +                                                 _("Cancel"));
  +#else
  +	buttonclose = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
  +#endif
  +        GTK_WIDGET_SET_FLAGS(buttonclose, 
  +                             GTK_CAN_DEFAULT);
  +        gtk_box_pack_start(GTK_BOX(action_area),
  +                           buttonclose, TRUE, TRUE, 0);
  +        gtk_signal_connect(GTK_OBJECT(buttonclose),
  +                           "clicked",
  +                           GTK_SIGNAL_FUNC(
  +                                           x_fileselect_saveas_close),
  +                           f_current);
  +        gtk_widget_show(buttonclose);
  +
  +        x_fileselect_update_dirfile_saveas(f_current, 
  +                                           w_current->page_current->page_filename);
  +        x_fileselect_fill_lists(f_current);
  +      }
  +    } else {
  +#ifdef HAS_GTK12
  +      buttonclose = gtk_button_new_with_label (_("Close"));
  +#else
  +      buttonclose = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +      GTK_WIDGET_SET_FLAGS(buttonclose, GTK_CAN_DEFAULT);
  +      gtk_box_pack_start(GTK_BOX(action_area),
  +                         buttonclose, TRUE, TRUE, 0);
  +      gtk_signal_connect(GTK_OBJECT(buttonclose),
  +                         "clicked",
  +                         GTK_SIGNAL_FUNC(x_fileselect_comp_close),
  +                         f_current);
  +      gtk_widget_show(buttonclose);
  +
  +      /* files data structure is not used for components */
  +      x_fileselect_setup_list_buffers(f_current,
  +                                      g_slist_length ((GSList *) s_clib_get_directories()), 0);
  +      x_fileselect_comp_update_current(f_current, NULL, NULL);
  +      x_fileselect_comp_fill_libs(w_current, f_current);
  +    }	
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE(f_current->xfwindow)) {
  +    gtk_widget_show(f_current->xfwindow);
  +    gdk_window_raise(f_current->xfwindow->window);
  +    x_preview_setup_rest(f_current->preview);
  +
  +    if (type == FILESELECT) {
  +      gtk_grab_add (f_current->xfwindow);
  +    }
  +
  +    /* need to delay this till the drawing area is created and
  +     * is showing */
  +    gtk_signal_connect (GTK_OBJECT(f_current->preview_checkbox), 
  +                        "toggled", GTK_SIGNAL_FUNC(x_fileselect_preview_checkbox),
  +                        f_current);
  +    if (w_current->file_preview) {
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +                                                     f_current->preview_checkbox), 
  +                                   TRUE);
  +      f_current->preview_control = TRUE;
  +    } else {
  +      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
  +                                                     f_current->preview_checkbox), 
  +                                   FALSE);
  +      f_current->preview_control = FALSE;
  +    }
  +
  +  } else {
  +    /* window should already be mapped, otherwise this
  +     * will core */
  +    gdk_window_raise(f_current->xfwindow->window);
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief Create "open/save file" dialog box.
  + *  \par Function Description
  + *  This function creates the "open/save file" dialog box.
  + *
  + *  \param [in] w_current     The TOPLEVEL object.
  + *  \param [in] type          \todo What is do?
  + *  \param [in] filesel_type  \todo What to do?
  + */
  +void x_fileselect_setup (TOPLEVEL *w_current, int type, int filesel_type)
  +{
  +#if ((GTK_MAJOR_VERSION > 2) || \
  +     ((GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION >= 4)) )
  +
  +  GtkImage *preview_widget;
  +  gchar *title;
  +  FILEDIALOG *f_current;
  +  if (type < 0 || type > 2) {
  +    return;
  +  }
  +
  +  if ( (filesel_type != OPEN) &&
  +       (filesel_type != SAVEAS) &&
  +       (filesel_type != SAVEAS_CLOSE) ) {
  +    x_fileselect_setup_old(w_current, type, filesel_type);
  +  }
  +
  +  f_current = &w_current->fileselect[type];
  +
  +  if (!f_current->xfwindow) {
  +    GtkFileFilter *sch_filefilter, *sym_filefilter, 
  +      *sch_sym_filefilter, *all_filefilter;
  +
  +    f_current->toplevel = w_current;
  +    f_current->type = type;
  +    f_current->filesel_type = filesel_type;
  +    f_current->last_search = -1;
  +    f_current->filename = NULL;
  +    f_current->directory = NULL;
  +    
  +    /* Create the filefilter */
  +    sch_filefilter = gtk_file_filter_new ();
  +    gtk_file_filter_set_name(sch_filefilter, _("Schematics"));
  +    gtk_file_filter_add_pattern(sch_filefilter, "*.sch");
  +    sym_filefilter = gtk_file_filter_new ();
  +    gtk_file_filter_set_name(sym_filefilter, _("Symbols"));
  +    gtk_file_filter_add_pattern(sym_filefilter, "*.sym");
  +    sch_sym_filefilter = gtk_file_filter_new ();
  +    gtk_file_filter_set_name(sch_sym_filefilter, _("Schematics and symbols"));
  +    gtk_file_filter_add_pattern(sch_sym_filefilter, "*.sym");
  +    gtk_file_filter_add_pattern(sch_sym_filefilter, "*.sch");
  +    all_filefilter = gtk_file_filter_new ();
  +    gtk_file_filter_set_name(all_filefilter, _("All files"));
  +    gtk_file_filter_add_pattern(all_filefilter, "*");
  +
  +    if (filesel_type == OPEN) {
  +      title = g_strdup(_("Open..."));
  +      f_current->xfwindow = gtk_file_chooser_dialog_new (title, 
  +							 GTK_WINDOW(w_current->main_window),
  +							 GTK_FILE_CHOOSER_ACTION_OPEN,
  +							 GTK_STOCK_OPEN, 
  +							 GTK_RESPONSE_ACCEPT,
  +							 GTK_STOCK_CANCEL, 
  +							 GTK_RESPONSE_CANCEL,
  +							 NULL);	     
  +
  +      gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(f_current->xfwindow), TRUE);
  +      gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(f_current->xfwindow), 
  +				  sch_filefilter);
  +      gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(f_current->xfwindow), 
  +				  sym_filefilter);
  +      gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(f_current->xfwindow), 
  +				  sch_sym_filefilter);
  +      gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(f_current->xfwindow), 
  +				  all_filefilter);
  +
  +      /* Code for handle the file preview. Not working yet!! */
  +
  +      /* Always have a file preview */
  +      /*
  +      f_current->preview_control = TRUE;
  +      
  +      f_current->preview = x_preview_setup(f_current->xfwindow, 
  +					   NULL);
  +					   
  +      preview_widget = ???
  +      gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER(f_current->xfwindow), 
  +					   GTK_WIDGET(preview_widget));
  +      */
  +      /* There is a problem with setup_rest : 
  +	 gdk_pixmap_new: Assertion drawable != NULL || depth != -1 failed.
  +	 gdk_gc_new: drawable != NULL failed 
  +	 x_preview_setup_rest (f_current->preview); */
  +      /*
  +      g_signal_connect (GTK_FILE_CHOOSER(f_current->xfwindow), 
  +			"update-preview",
  +			G_CALLBACK (x_preview_update_gtk24), 
  +			f_current);
  +      */
  +
  +      if (gtk_dialog_run (GTK_DIALOG (f_current->xfwindow)) == GTK_RESPONSE_ACCEPT)
  +	{
  +	  char *filename;
  +	  
  +	  filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (f_current->xfwindow));
  +	  x_fileselect_open_file(NULL, f_current);
  +	  g_free (filename);
  +	}
  +      else {
  +	x_fileselect_close (NULL, f_current);
  +      }
  +      
  +      free (title);
  +						   
  +    } else if ( (filesel_type == SAVEAS) || (filesel_type == SAVEAS_CLOSE) ){
  +      title = g_strdup(_("Save As..."));
  +      f_current->xfwindow = gtk_file_chooser_dialog_new (title, 
  +							 GTK_WINDOW(w_current->main_window),
  +							 GTK_FILE_CHOOSER_ACTION_SAVE,
  +							 GTK_STOCK_SAVE_AS, 
  +							 GTK_RESPONSE_ACCEPT,
  +							 GTK_STOCK_CANCEL, 
  +							 GTK_RESPONSE_CANCEL,
  +							 _("Discard changes"),
  +							 GTK_RESPONSE_REJECT,
  +							 NULL);	     
  +      gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(f_current->xfwindow), 
  +				  sch_filefilter);
  +      gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(f_current->xfwindow), 
  +				  sym_filefilter);
  +      gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(f_current->xfwindow), 
  +				  sch_sym_filefilter);
  +      gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(f_current->xfwindow), 
  +				  all_filefilter);
  +
  +      /* Select the filename */
  +      if (!gtk_file_chooser_set_filename(GTK_FILE_CHOOSER (f_current->xfwindow),
  +					 w_current->page_current->page_filename)) {
  +	gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER (f_current->xfwindow),
  +					  w_current->page_current->page_filename);
  +      }
  +      switch (gtk_dialog_run (GTK_DIALOG (f_current->xfwindow))) {
  +
  +        case GTK_RESPONSE_ACCEPT:
  +	  {
  +	    char *filename;
  +	    
  +	    filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (f_current->xfwindow));
  +	    x_fileselect_saveas(NULL, f_current);
  +	    g_free (filename);
  +	  }
  +	  break;
  +        case GTK_RESPONSE_CANCEL:
  +	  x_fileselect_close (NULL, f_current);
  +	  break;
  +	  
  +        case GTK_RESPONSE_REJECT:
  +	  x_fileselect_close (NULL, f_current);
  +	  /* Set the CHANGED flag to 0, so i_callback_page_close won't
  +	     ask again if save the page or not. */
  +	  w_current->page_current->CHANGED = 0;
  +	  i_callback_page_close (w_current, 0, NULL);
  +	  break;
  +      }
  +
  +      free (title);
  +    }
  +    else {
  +      /* If it's not file load/save, then it's component library selection.
  +	 Use the old interface */
  +      x_fileselect_setup_old(w_current, type, filesel_type);
  +    }
  +    /* This is not the way to free filefilters. Really do they need to be freed?  */
  +    /*
  +    gtk_object_destroy(GTK_OBJECT(sch_filefilter));
  +    gtk_object_destroy(GTK_OBJECT(sym_filefilter));
  +    gtk_object_destroy(GTK_OBJECT(sch_sym_filefilter));
  +    gtk_object_destroy(GTK_OBJECT(all_filefilter));
  +    */
  +  } else {
  +    /* window should already be mapped, otherwise this
  +     * will core */
  +    gdk_window_raise(f_current->xfwindow->window);
  +  }
  +#else
  +  x_fileselect_setup_old(w_current, type, filesel_type);
  +#endif
  +}
  +
  +/*! \brief Load/Backup selection dialog.
  + *  \par Function Description
  + *  This function opens a message dialog and wait for the user to choose
  + *  if load the backup or the original file.
  + *
  + *  \param [in] toplevel  The TOPLEVEL object.
  + *  \param [in] message   Message to display to user.
  + *  \return TRUE if the user wants to load the backup file, FALSE otherwise.
  + */
  +int x_fileselect_load_backup(TOPLEVEL *toplevel, GString *message)
  +{
  +  GtkWidget *dialog;
  +
  +  g_string_append(message, "\nIf you load the original file, the backup file will be overwritten in the next autosave timeout and it will be lost.\n\nDo you want to load the backup file?\n");
  +
  +  dialog = gtk_message_dialog_new(GTK_WINDOW(toplevel->main_window),
  +			  GTK_DIALOG_MODAL,
  +			  GTK_MESSAGE_QUESTION,
  +			  GTK_BUTTONS_YES_NO,
  +			  message->str);
  +  gtk_widget_show (dialog);
  +  if (gtk_dialog_run ((GtkDialog*)dialog) == GTK_RESPONSE_YES) {
  +    gtk_widget_destroy(dialog);  
  +    return TRUE;
  +  }
  +  else {
  +    gtk_widget_destroy(dialog);  
  +    return FALSE;
  +  }
  +}
  
  
  
  1.14      +184 -145  eda/geda/gaf/gschem/src/x_grid.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_grid.c
  ===================================================================
  RCS file: x_grid.c
  diff -N x_grid.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_grid.c	14 Jul 2006 02:23:55 -0000	1.14
  @@ -0,0 +1,232 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <math.h>
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/x_states.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +static GdkPoint points[5000];
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_grid_draw(TOPLEVEL *w_current)
  +{
  +  int i, j;
  +  int x, y;
  +  int x_start, y_start;
  +  int count = 0;
  +
  +  int incr = 100;
  +  int screen_incr = 0;
  +
  +  if (!w_current->grid) {
  +    return;
  +  }
  +
  +  if (w_current->grid_mode == GRID_VARIABLE_MODE)
  +  {
  +    /* In the variable mode around every 30th screenpixel will be grid-point */
  +    /* adding 0.1 for correct cast*/
  +    incr = round_5_2_1(w_current->page_current->to_world_x_constant *30)+0.1;
  +
  +    /*limit grid to snap_size; only a idea of mine, hope you like it (hw) */
  +    if (incr < w_current->snap_size) {
  +      incr = w_current->snap_size;
  +    }
  +    /* usually this should never happen */
  +    if (incr < 1){
  +      incr = 1;
  +    }
  +  }
  +  else
  +  {
  +    incr = w_current->snap_size;
  +    screen_incr = SCREENabs(w_current, incr);
  +    if (screen_incr < w_current->grid_fixed_threshold)
  +    {
  +      /* don't draw the grid if the screen incr spacing is less than the */
  +      /* threshold */
  +      return;
  +    }
  +  }
  +
  +#if DEBUG 
  +  printf("---------x_grid_draw\n incr: %d\n",incr);
  +
  +  printf("x1 %d\n", pix_x(w_current, 100));
  +  printf("x2 %d\n", pix_x(w_current, 200));
  +  printf("y1 %d\n", pix_y(w_current, 100));
  +  printf("y2 %d\n", pix_y(w_current, 200));
  +#endif
  +
  +  gdk_gc_set_foreground(w_current->gc,
  +                        x_get_color(w_current->grid_color));
  +
  +  /* figure starting grid coordinates, work by taking the start
  +   * and end coordinates and rounding down to the nearest
  +   * increment */
  +  x_start = (w_current->page_current->left -
  +             (w_current->page_current->left % incr));
  +  y_start = (w_current->page_current->top -
  +             (w_current->page_current->top  % incr));
  +
  +  for (i = x_start; i < w_current->page_current->right; i = i + incr) {
  +    for(j = y_start; j < w_current->page_current->bottom; j = j + incr) {
  +      WORLDtoSCREEN(w_current, i,j, &x, &y);
  +      if (inside_region(w_current->page_current->left,
  +                        w_current->page_current->top,
  +                        w_current->page_current->right,
  +                        w_current->page_current->bottom,
  +                        i, j)) {
  +
  +	if (w_current->grid_dot_size == 1)
  +        {
  +          points[count].x = x;
  +          points[count].y = y;
  +          count++;
  +
  +          /* get out of loop if more than 1000 points */
  +          if (count == 5000) {
  +            gdk_draw_points(w_current->window,
  +                            w_current->gc,
  +                            points, count);
  +            gdk_draw_points(
  +                            w_current->backingstore,
  +                            w_current->gc, points, count);
  +            count=0;
  +          }
  +        }
  +        else
  +        {
  +          gdk_draw_arc(w_current->window, w_current->gc,
  +                       TRUE, x, y,
  +                       w_current->grid_dot_size,
  +                       w_current->grid_dot_size, 0, FULL_CIRCLE);
  +          gdk_draw_arc(w_current->backingstore, w_current->gc,
  +                       TRUE, x, y,
  +                       w_current->grid_dot_size,
  +                       w_current->grid_dot_size, 0, FULL_CIRCLE);
  +        }
  +      }
  +    }
  +  }
  +
  +  /* now draw all the points in one step */
  +  if(count != 0) {
  +    gdk_draw_points(w_current->window,
  +                    w_current->gc, points, count);
  +    gdk_draw_points(w_current->backingstore,
  +                    w_current->gc, points, count);
  +  }
  +
  +#if 0
  +  gdk_draw_pixmap(w_current->window,
  +                  w_current->gc,
  +                  w_current->backingstore,
  +                  0, 0, 0, 0,
  +                  w_current->drawing_area->allocation.width,
  +                  w_current->drawing_area->allocation.height);
  +
  +#endif
  +
  +#if DEBUG
  +  /* highly temp, just for diag purposes */
  +  x_draw_tiles(w_current);
  +#endif        
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_draw_tiles(TOPLEVEL *w_current)
  +{
  +  TILE *t_current;
  +  GdkFont *font;
  +  int i,j;
  +  int x1, y1, x2, y2;
  +  int screen_x, screen_y;
  +  int width, height;
  +  char *tempstring;
  +
  +  gdk_gc_set_foreground(w_current->gc, x_get_color(w_current->lock_color));
  +
  +  font = gdk_fontset_load ("fixed");
  +  for (j = 0; j < MAX_TILES_Y; j++) {
  +    for (i = 0; i < MAX_TILES_X; i++) {
  +      t_current = &w_current->page_current->world_tiles[i][j];
  +      WORLDtoSCREEN(w_current, t_current->left, 
  +                    t_current->top, &x1, &y1);
  +      WORLDtoSCREEN(w_current, t_current->right, 
  +                    t_current->bottom, &x2, &y2);
  +
  +      screen_x = min(x1, x2);
  +      screen_y = min(y1, y2);
  +
  +      width = abs(x1 - x2);
  +      height = abs(y1 - y2);
  +
  +#if DEBUG
  +      printf("x, y: %d %d\n", screen_x, screen_y);
  +      printf("w x h: %d %d\n", width, height);
  +#endif
  +      gdk_draw_rectangle(w_current->window, 
  +                         w_current->gc, 
  +                         FALSE, screen_x, screen_y,
  +                         width, height);
  +      gdk_draw_rectangle(w_current->backingstore, 
  +                         w_current->gc, 
  +                         FALSE, screen_x, screen_y,
  +                         width, height);
  +
  +      tempstring = g_strdup_printf("%d %d", i, j);
  +      gdk_draw_text (w_current->window,
  +                     font,
  +                     w_current->gc,
  +                     screen_x+10, screen_y+10, 
  +                     tempstring,
  +                     strlen(tempstring));
  +
  +      gdk_draw_text (w_current->backingstore,
  +                     font,
  +                     w_current->gc,
  +                     screen_x+10, screen_y+10, 
  +                     tempstring,
  +                     strlen(tempstring));
  +      free(tempstring);
  +    }
  +  }
  +
  +  gdk_font_unref(font);
  +}
  
  
  
  1.20      +610 -286  eda/geda/gaf/gschem/src/x_image.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_image.c
  ===================================================================
  RCS file: x_image.c
  diff -N x_image.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_image.c	14 Jul 2006 02:23:55 -0000	1.20
  @@ -0,0 +1,711 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +
  +/* static const   gchar   *list_item_data_key="list_item_data";	*/
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint image_320(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->image_width = 320;
  +  w_current->image_height = 240;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint image_640(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->image_width = 640;
  +  w_current->image_height = 480;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint image_800(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->image_width = 800;
  +  w_current->image_height = 600;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint image_1024(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->image_width = 1024;
  +  w_current->image_height = 768;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint image_1280(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->image_width = 1280;
  +  w_current->image_height = 960;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint image_1600(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->image_width = 1600;
  +  w_current->image_height = 1200;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint image_3200(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->image_width = 3200;
  +  w_current->image_height = 2400;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is from gtktest.c and only used in this file,
  + *  there are other create_menus...
  + */
  +static GtkWidget *create_menu_size(TOPLEVEL *w_current)
  +{
  +  GtkWidget *menu;
  +  GtkWidget *menuitem;
  +  GSList *group;
  +  char *buf;
  +
  +  menu = gtk_menu_new ();
  +  group = NULL;
  +
  +  buf = g_strdup_printf("320x240");
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  +                      (GtkSignalFunc) image_320,
  +                      w_current);
  +
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf("640x480");
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  +                      (GtkSignalFunc) image_640,
  +                      w_current);
  +
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf("800x600");
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  +                      (GtkSignalFunc) image_800,
  +                      w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf("1024x768");
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  +                      (GtkSignalFunc) image_1024,
  +                      w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf("1280x960");
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  +                      (GtkSignalFunc) image_1280,
  +                      w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf("1600x1200");
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  +                      (GtkSignalFunc) image_1600,
  +                      w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf("3200x2400");
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  +                      (GtkSignalFunc) image_3200,
  +                      w_current);
  +  gtk_widget_show (menuitem);
  +
  +  gtk_menu_set_active(GTK_MENU (menu),2);
  +
  +  return menu;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_image_lowlevel(TOPLEVEL *w_current, const char* filename)
  +{
  +  int width, height;
  +  int save_height, save_width;
  +  int save_page_left, save_page_right, save_page_top, save_page_bottom;
  +  int page_width, page_height, page_center_left, page_center_top;
  +#ifndef HAS_LIBGDGEDA
  +  GdkPixbuf *pixbuf;
  +  char *filetype;
  +#endif
  +  float prop;
  +
  +  width = w_current->image_width;
  +  height = w_current->image_height;
  +
  +  save_width = w_current->width;
  +  save_height = w_current->height;
  +
  +  w_current->width = width;
  +  w_current->height = height;
  +
  +  save_page_left = w_current->page_current->left;
  +  save_page_right = w_current->page_current->right;
  +  save_page_top = w_current->page_current->top;
  +  save_page_bottom = w_current->page_current->bottom;
  +  
  +  page_width = save_page_right - save_page_left;
  +  page_height = save_page_bottom - save_page_top;
  +
  +  page_center_left = save_page_left + (page_width / 2);
  +  page_center_top = save_page_top + (page_height / 2);
  +
  +  /* Preserve proportions */
  +  prop = (float)width / height;
  +  if(page_width > page_height) {
  +    page_height = (page_width / prop);
  +  }else{
  +    page_width = (page_height * prop);
  +  }
  +
  +  /* need to do this every time you change width / height */
  +  set_window(w_current, w_current->page_current,
  +             page_center_left - (page_width / 2),
  +             page_center_left + (page_width / 2),
  +             page_center_top - (page_height / 2),
  +             page_center_top + (page_height / 2));
  +
  +  /* de select everything first */
  +  o_select_run_hooks(w_current, NULL, 2); 
  +  o_selection_remove_most(w_current,
  +                          w_current->page_current->
  +                          selection2_head);
  +		
  +
  +#ifdef HAS_LIBGDGEDA
  +  /* try to use recalc here */
  +  o_redraw_all(w_current);
  +
  +  f_image_write(w_current, filename, width, height, 
  +                w_current->image_color);
  +#else
  +  pixbuf = x_image_get_pixbuf(w_current);
  +  if (pixbuf != NULL) {
  +    filetype = g_strdup("png");
  +    if (!gdk_pixbuf_save(pixbuf, filename, filetype, NULL, NULL)) {
  +      fprintf(stderr, "x_image_lowlevel: Unable to save PNG file  %s.\n", filename);
  +      s_log_message(_("x_image_lowlevel: Unable to write PNG file.\n"));
  +    }
  +    else {
  +      if (w_current->image_color == TRUE) {
  +	s_log_message(_("Wrote color image to [%s] [%d x %d]\n"), filename, width, height);
  +      } else {
  +	s_log_message(_("Wrote black and white image to [%s] [%d x %d]\n"), filename, width, height);
  +      }
  +    }
  +    if (filetype != NULL)
  +      free(filetype);
  +    if (pixbuf != NULL)
  +	  free(pixbuf); 
  +  }
  +  else {
  +    fprintf(stderr, "x_image_lowlevel: Unable to get pixbuf from gschem's window.\n");
  +    s_log_message(_("x_image_lowlevel: Unable to get pixbuf from gschem's window.\n"));
  +  }
  +#endif
  +
  +  w_current->width = save_width;
  +  w_current->height = save_height;
  +
  +  /* need to do this every time you change width / height */
  +  set_window(w_current, w_current->page_current,
  +             save_page_left,
  +             save_page_right,
  +             save_page_top,
  +             save_page_bottom);
  +
  +  /* try to use recalc here... */
  +  o_redraw_all(w_current);
  +
  +#ifdef HAS_LIBGDGEDA
  +  if (w_current->image_color == TRUE) {
  +    s_log_message(_("Wrote color image to [%s] [%d x %d]\n"), filename, width, height);
  +  } else {
  +    s_log_message(_("Wrote black and white image to [%s] [%d x %d]\n"), filename, width, height);
  +  }
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_image_write(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  const char *filename=NULL;
  +
  +  filename = gtk_entry_get_text(GTK_ENTRY(w_current->ifilename_entry));
  +  if (filename[0] != '\0') {
  +    x_image_lowlevel(w_current, filename);
  +  }
  +
  +  gtk_widget_destroy(w_current->iwindow);
  +  w_current->iwindow=NULL;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_image_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  /* gtk_grab_remove(w_current->iwindow);*/
  +  gtk_widget_destroy(w_current->iwindow);
  +  w_current->iwindow=NULL;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int x_image_keypress(GtkWidget * widget, GdkEventKey * event, 
  +		     TOPLEVEL * w_current)
  +{
  +  if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +    x_image_cancel(NULL, w_current);	
  +    return TRUE;
  +  }
  +
  +  return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_image_setup (TOPLEVEL *w_current, char *filename)
  +{
  +  GtkWidget *label;
  +  GtkWidget *separator;
  +  GtkWidget *box;
  +  GtkWidget *buttonwrite;
  +  GtkWidget *buttoncancel;
  +  GtkWidget *optionmenu;
  +  GtkWidget *vbox, *action_area;
  +
  +  /* freeze the window_current pointer so that it doesn't change */
  +
  +  if (!w_current->iwindow) {
  +
  +    w_current->iwindow = x_create_dialog_box(&vbox, &action_area); 
  +
  +    gtk_window_position (GTK_WINDOW (w_current->iwindow),
  +                         GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect (GTK_OBJECT (w_current->iwindow), "destroy",
  +			GTK_SIGNAL_FUNC(destroy_window),
  +			&w_current->iwindow);
  +
  +#if 0 /* this was causing the dialog box to not die */
  +    gtk_signal_connect (GTK_OBJECT (w_current->iwindow), "delete_event",
  +			GTK_SIGNAL_FUNC(destroy_window),
  +			&w_current->iwindow);
  +#endif
  +
  +    gtk_window_set_title (GTK_WINDOW (w_current->iwindow), _("Write Image..."));
  +
  +#ifdef HAS_GTK12
  +    buttonwrite = gtk_button_new_with_label (_("Write"));
  +#else
  +    buttonwrite = gtk_button_new_from_stock (GTK_STOCK_OK);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonwrite, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start (GTK_BOX (action_area),
  +			buttonwrite, TRUE, TRUE, 0);
  +    gtk_signal_connect (GTK_OBJECT (buttonwrite), "clicked",
  +			GTK_SIGNAL_FUNC(x_image_write), w_current);
  +    gtk_widget_show (buttonwrite);
  +    gtk_widget_grab_default (buttonwrite);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Close"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start (GTK_BOX (action_area),
  +			buttoncancel, TRUE, TRUE, 0);
  +    gtk_signal_connect ( GTK_OBJECT(buttoncancel),
  +                         "clicked", GTK_SIGNAL_FUNC(x_image_cancel),
  +                         w_current);
  +    gtk_widget_show (buttoncancel);
  +
  +#if 0
  +    separator = gtk_hseparator_new ();
  +    gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, TRUE, 0);
  +    gtk_widget_show (separator);
  +#endif
  +
  +    box = gtk_vbox_new(FALSE, 0);
  +    gtk_container_border_width(GTK_CONTAINER(box), 5);
  +    gtk_container_add(GTK_CONTAINER(vbox), box);
  +    gtk_widget_show(box);
  +
  +#if 0
  +    label = gtk_label_new (_("Width"));
  +    gtk_misc_set_alignment( GTK_MISC (label), 0, 0);
  +    gtk_misc_set_padding (GTK_MISC (label), 0, 0);
  +    gtk_box_pack_start (GTK_BOX (box),
  +                        label, FALSE, FALSE, 0);
  +    gtk_widget_show (label);
  +
  +    w_current->iwidth_entry = gtk_entry_new_with_max_length (5);
  +    gtk_editable_select_region (GTK_EDITABLE (w_current->iwidth_entry), 0, -1);
  +    gtk_box_pack_start (GTK_BOX (box),
  +                        w_current->iwidth_entry, TRUE, TRUE, 10);
  +    /*
  +      gtk_signal_connect(GTK_OBJECT(w_current->width_entry),
  +      "activate",
  +      GTK_SIGNAL_FUNC(x_image_write),
  +      w_current);
  +    */
  +    gtk_widget_show (w_current->iwidth_entry);
  +
  +    label = gtk_label_new (_("Height"));
  +    gtk_misc_set_alignment( GTK_MISC (label), 0, 0);
  +    gtk_misc_set_padding (GTK_MISC (label), 0, 0);
  +    gtk_box_pack_start (GTK_BOX (box),
  +                        label, FALSE, FALSE, 0);
  +    gtk_widget_show (label);
  +
  +    w_current->iheight_entry = gtk_entry_new_with_max_length (5);
  +    gtk_editable_select_region (GTK_EDITABLE (w_current->iheight_entry), 0, -1);
  +    gtk_box_pack_start (GTK_BOX (box),
  +                        w_current->iheight_entry, TRUE, TRUE, 10);
  +    /*
  +      gtk_signal_connect(GTK_OBJECT(w_current->height_entry),
  +      "activate",
  +      GTK_SIGNAL_FUNC(x_image_write),
  +      w_current);
  +    */
  +    gtk_widget_show (w_current->iheight_entry);
  +#endif
  +    label = gtk_label_new (_("Width x Height"));
  +    gtk_misc_set_alignment( GTK_MISC (label), 0, 0);
  +    gtk_misc_set_padding (GTK_MISC (label), 0, 0);
  +    gtk_box_pack_start (GTK_BOX (box),
  +                        label, FALSE, FALSE, 0);
  +    gtk_widget_show (label);
  +
  +    optionmenu = gtk_option_menu_new ();
  +    gtk_option_menu_set_menu (GTK_OPTION_MENU (optionmenu), create_menu_size (w_current));
  +    gtk_option_menu_set_history (GTK_OPTION_MENU (optionmenu), 2);
  +    gtk_box_pack_start (GTK_BOX (box), optionmenu, TRUE, TRUE, 0);
  +    gtk_widget_show (optionmenu);
  +
  +    label = gtk_label_new (_("Filename"));
  +    gtk_misc_set_alignment( GTK_MISC (label), 0, 0);
  +    gtk_misc_set_padding (GTK_MISC (label), 0, 0);
  +    gtk_box_pack_start (GTK_BOX (box),
  +                        label, FALSE, FALSE, 0);
  +    gtk_widget_show (label);
  +
  +    w_current->ifilename_entry = gtk_entry_new_with_max_length (200);
  +    gtk_editable_select_region (GTK_EDITABLE (w_current->ifilename_entry), 0, -1);
  +    gtk_box_pack_start (GTK_BOX (box),
  +                        w_current->ifilename_entry, TRUE, TRUE, 10);
  +    gtk_signal_connect(GTK_OBJECT(w_current->ifilename_entry),
  +                       "activate",
  +                       GTK_SIGNAL_FUNC(x_image_write),
  +                       w_current);
  +    gtk_widget_show (w_current->ifilename_entry);
  +
  +    separator = gtk_hseparator_new ();
  +    gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, TRUE, 0);
  +    gtk_widget_show (separator);
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->iwindow), "key_press_event",
  +                       (GtkSignalFunc) x_image_keypress, w_current);
  +  }
  + 
  +  if (!GTK_WIDGET_VISIBLE (w_current->iwindow)) {
  +    gtk_entry_set_text(GTK_ENTRY(w_current->ifilename_entry), filename);
  +    /* gtk_entry_set_text(GTK_ENTRY(w_current->iwidth_entry), "800");
  +       gtk_entry_set_text(GTK_ENTRY(w_current->iheight_entry), "600");*/
  +
  +    /*gtk_entry_select_region(GTK_ENTRY(w_current->ifilename_entry), 0, strlen(filename)); 	*/
  +    w_current->image_width = 800;
  +    w_current->image_height = 600;
  +    gtk_widget_show (w_current->iwindow);
  +    gdk_window_raise(w_current->iwindow->window);
  +    /* gtk_grab_add (w_current->iwindow);*/
  +  } else {
  +    /* window should already be mapped */
  +    /* otherwise this will core */
  +    gdk_window_raise(w_current->iwindow->window);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void x_image_convert_to_greyscale(GdkPixbuf *pixbuf)
  +{
  +  int width, height, rowstride, n_channels;
  +  guchar *pixels, *p, new_value;
  +  int i, j;
  +
  +  n_channels = gdk_pixbuf_get_n_channels (pixbuf);
  +  
  +  if (n_channels != 3)
  +  {
  +    return;
  +  }
  + 
  +  if (gdk_pixbuf_get_colorspace (pixbuf) != GDK_COLORSPACE_RGB)
  +  {
  +    return;
  +  }
  +
  +  if (gdk_pixbuf_get_bits_per_sample (pixbuf) != 8)
  +  {
  +    return;
  +  }
  +
  +  width = gdk_pixbuf_get_width (pixbuf);
  +  height = gdk_pixbuf_get_height (pixbuf);
  +
  +  rowstride = gdk_pixbuf_get_rowstride (pixbuf);
  +  pixels = gdk_pixbuf_get_pixels (pixbuf);
  +
  +  for (j = 0; j < height; j++)
  +  {
  +    for (i = 0; i < width; i++)
  +    {
  +      p = pixels + j * rowstride + i * n_channels;
  +
  +      new_value = 0.3 * p[0] + 0.59 * p[1] + 0.11 * p[2];
  +      p[0] = new_value;
  +      p[1] = new_value;
  +      p[2] = new_value;
  +    }
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +GdkPixbuf *x_image_get_pixbuf (TOPLEVEL *w_current)
  +{
  +  GdkPixbuf *pixbuf;
  +  int origin_x, origin_y, bottom, right;
  +  int size_x, size_y, s_right, s_left, s_top,s_bottom;
  +  TOPLEVEL toplevel;
  +  OBJECT *aux;
  +  char object_found = 0;
  +
  +  /* Do a copy of the toplevel struct and work with it */
  +  memcpy(&toplevel, w_current, sizeof(TOPLEVEL));
  +
  +  WORLDtoSCREEN(&toplevel, 
  +		w_current->page_current->right,
  +		w_current->page_current->left,
  +		&s_right,
  +		&s_left);
  +  WORLDtoSCREEN(&toplevel, 
  +		w_current->page_current->bottom,
  +		w_current->page_current->top,
  +		&s_bottom,
  +		&s_top);
  +
  +  size_x = s_left - s_right;
  +  size_y = s_bottom - s_top;
  +
  +  size_x = toplevel.image_width;
  +  size_y = toplevel.image_height;
  +
  +  toplevel.window = gdk_pixmap_new(w_current->window, size_x, size_y, -1);
  +  toplevel.backingstore = gdk_pixmap_new(w_current->window, size_x, size_y, -1);
  +  toplevel.grid = 0;
  +  toplevel.text_origin_marker = FALSE;
  +
  +  toplevel.display_width = toplevel.image_width;
  +  toplevel.display_height = toplevel.image_height;
  +
  +  toplevel.win_width = toplevel.image_width;
  +  toplevel.win_height = toplevel.image_height;
  +
  +  if (toplevel.image_color == FALSE)
  +  {
  +    /* We are going to be doing black&white (grayscale) output, so change the */
  +    /* color of all objects to a nice and dark color, say black */
  +    toplevel.override_color = BLACK;  
  +
  +    /* also reset the background to white */
  +    toplevel.background_color = WHITE;
  +  }
  +
  +  origin_x = origin_y = 0;
  +  right = size_x;
  +  bottom = size_y;
  +  /* ------------------  Begin optional code ------------------------ */
  +  /* If the the code in this region is commented, the PNG returned will
  +     be the same as the one returned using libgdgeda.
  +     I mean: there will be some border all around the schematic.
  +     This code is used to adjust the schematic to the border of the image */
  +
  +  /* Do a zoom extents to get fit all the schematic in the window */
  +  /* Commented so the image returned will be the same as with libgdgeda */  
  +  a_zoom_extents (&toplevel,
  +		  toplevel.page_current->object_head,
  +		  A_PAN_DONT_REDRAW);
  +
  +  
  +  /* See if there are objects */
  +  
  +  aux = w_current->page_current->object_head;
  +  while (aux != NULL) {
  +    if (aux->type != -1) {
  +      object_found = 1;
  +      break;
  +    }
  +    aux = aux->next;
  +  }
  +
  +  
  +  /* If there are no objects, can't use zoom_extents */
  +  if (object_found) {
  +    o_redraw_all (&toplevel); 
  +    get_complex_bounds(&toplevel, 
  +		       toplevel.page_current->object_head, 
  +		       &origin_x, &origin_y, 
  +		       &right, &bottom);
  +  }
  +  /* ------------------  End optional code ------------------------ */
  +  
  +  o_redraw_all (&toplevel); 
  +
  +  /* Get the pixbuf */
  +  pixbuf=gdk_pixbuf_get_from_drawable(NULL,toplevel.backingstore, NULL, 
  +				      origin_x, origin_y, 0, 0,           
  +				      right-origin_x, 
  +				      bottom-origin_y);
  +
  +  if (toplevel.image_color == FALSE)
  +  {
  +    x_image_convert_to_greyscale(pixbuf); 
  +  }
  +
  +  if (toplevel.window != NULL) {
  +    free(toplevel.window);
  +  }
  +  if (toplevel.backingstore != NULL) {
  +    free(toplevel.backingstore);
  +  }
  +
  +  return(pixbuf);
  +}
  
  
  
  1.17      +225 -179  eda/geda/gaf/gschem/src/x_log.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_log.c
  ===================================================================
  RCS file: x_log.c
  diff -N x_log.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_log.c	14 Jul 2006 02:23:55 -0000	1.17
  @@ -0,0 +1,278 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#include <sys/types.h>
  +#include <sys/stat.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +#ifdef HAVE_FCNTL_H
  +#include <fcntl.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#include "../include/x_log.h"
  +
  +static void x_log_callback_response (GtkDialog *dialog,
  +                                     gint arg1,
  +                                     gpointer user_data);
  +
  +static GtkWidget *log_dialog = NULL;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void x_log_open ()
  +{
  +  if (log_dialog == NULL) {
  +    gchar *contents;
  +    
  +    log_dialog = GTK_WIDGET (g_object_new (TYPE_LOG,
  +                                           NULL));
  +
  +    g_signal_connect (log_dialog,
  +                      "response",
  +                      G_CALLBACK (x_log_callback_response),
  +                      NULL);
  +
  +    /* make it read the content of the current log file */
  +    /* and add its contents to the dialog */
  +    contents = s_log_read ();
  +
  +    /* s_log_read can return NULL if the log file cannot be written to */
  +    if (contents == NULL)
  +    {
  +      return;
  +    }
  +
  +    log_message (LOG (log_dialog), contents);
  +    g_free (contents);
  +
  +    x_log_update_func = (void*)x_log_message;
  +   
  +    if( auto_place_mode )
  +	gtk_widget_set_uposition( log_dialog, 10, 10); 
  +    gtk_widget_show (log_dialog);
  +  } else {
  +    g_assert (IS_LOG (log_dialog));
  +    gtk_window_present ((GtkWindow*)log_dialog);
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void x_log_close ()
  +{
  +  if (log_dialog) {
  +    g_assert (IS_LOG (log_dialog));
  +    gtk_widget_destroy (log_dialog);
  +    x_log_update_func = NULL;
  +    log_dialog = NULL;
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void x_log_message (const gchar *message)
  +{
  +  g_return_if_fail (log_dialog != NULL);
  +  
  +  g_assert (IS_LOG (log_dialog));
  +  log_message ((Log*)log_dialog, message);
  +    
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +static void x_log_callback_response (GtkDialog *dialog,
  +				     gint arg1,
  +				     gpointer user_data)
  +{
  +  switch (arg1) {
  +    case GTK_RESPONSE_DELETE_EVENT:
  +    case LOG_RESPONSE_CLOSE:
  +    g_assert (GTK_WIDGET (dialog) == log_dialog);
  +    x_log_close ();
  +    break;
  +    default:
  +    g_assert_not_reached ();
  +  }
  +  
  +}
  +
  +static void log_class_init (LogClass *class);
  +static void log_init       (Log *log);
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +void log_message (Log *log, const gchar *message)
  +{
  +  GtkTextBuffer *buffer;
  +  GtkTextIter iter;
  +  
  +  g_return_if_fail (IS_LOG (log));
  +
  +  buffer = gtk_text_view_get_buffer (log->textview);
  +  gtk_text_buffer_insert_at_cursor (buffer, message, strlen (message));
  +  
  +  gtk_text_buffer_get_end_iter (buffer, &iter);
  +  gtk_text_view_scroll_to_iter (log->textview, &iter, 0, TRUE, 0, 1);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +GType log_get_type ()
  +{
  +  static GType log_type = 0;
  +  
  +  if (!log_type) {
  +    static const GTypeInfo log_info = {
  +      sizeof(LogClass),
  +      NULL, /* base_init */
  +      NULL, /* base_finalize */
  +      (GClassInitFunc) log_class_init,
  +      NULL, /* class_finalize */
  +      NULL, /* class_data */
  +      sizeof(Log),
  +      0,    /* n_preallocs */
  +      (GInstanceInitFunc) log_init,
  +    };
  +		
  +    log_type = g_type_register_static (GTK_TYPE_DIALOG,
  +                                       "Log",
  +                                       &log_info, 0);
  +  }
  +  
  +  return log_type;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +static void log_class_init (LogClass *klass)
  +{
  +/*   GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
  +	
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + * 
  + */
  +static void log_init (Log *log)
  +{
  +  GtkWidget *scrolled_win, *text_view;
  +  GtkTextBuffer *text_buffer;
  +  GtkTextMark *mark;
  +
  +  /* dialog initialization */
  +  g_object_set (G_OBJECT (log),
  +                /* GtkContainer */
  +                "border-width",    0,
  +                /* GtkWindow */
  +                "type",            GTK_WINDOW_TOPLEVEL,
  +                "title",           _("Status"),
  +                "default-width",   600,
  +                "default-height",  200,
  +                "modal",           FALSE,
  +                "window-position", GTK_WIN_POS_NONE,
  +                "type-hint",       GDK_WINDOW_TYPE_HINT_NORMAL,
  +                /* GtkDialog */
  +                "has-separator",   TRUE,
  +                NULL);
  +
  +  /* create a scrolled window for the textview */
  +  scrolled_win = GTK_WIDGET (
  +    g_object_new (GTK_TYPE_SCROLLED_WINDOW,
  +                  /* GtkContainer */
  +                  "border-width",      5,
  +                  /* GtkScrolledWindow */
  +                  "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
  +                  "vscrollbar-policy", GTK_POLICY_AUTOMATIC,
  +                  "shadow-type",       GTK_SHADOW_ETCHED_IN,
  +                  NULL));
  +  /* create the text buffer */
  +  text_buffer = GTK_TEXT_BUFFER (g_object_new (GTK_TYPE_TEXT_BUFFER,
  +                                               NULL));
  +  /* create the text view and attach the buffer to it */
  +  text_view = GTK_WIDGET (g_object_new (GTK_TYPE_TEXT_VIEW,
  +                                        /* GtkTextView */
  +/* unknown property in GTK 2.2, use gtk_text_view_set_buffer() instead */
  +/*                                         "buffer",   text_buffer, */
  +                                        "editable", FALSE,
  +                                        NULL));
  +  gtk_text_view_set_buffer (GTK_TEXT_VIEW (text_view), text_buffer);
  +
  +  /* add the text view to the scrolled window */
  +  gtk_container_add (GTK_CONTAINER (scrolled_win), text_view);
  +  /* set textview of log */
  +  log->textview = GTK_TEXT_VIEW (text_view);
  +
  +  /* add the scrolled window to the dialog vbox */
  +  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (log)->vbox), scrolled_win,
  +                      TRUE, TRUE, 0);
  +  gtk_widget_show_all (scrolled_win);
  +
  +  /* now add the close button to the action area */
  +  gtk_dialog_add_button (GTK_DIALOG (log),
  +                         GTK_STOCK_CLOSE, LOG_RESPONSE_CLOSE);
  +
  +  /* scroll to the end of the buffer */
  +  mark = gtk_text_buffer_get_insert (text_buffer);
  +  gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (text_view), mark, 0.0, TRUE, 0.0, 1.0);
  +}
  
  
  
  1.35      +330 -215  eda/geda/gaf/gschem/src/x_menus.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_menus.c
  ===================================================================
  RCS file: x_menus.c
  diff -N x_menus.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_menus.c	14 Jul 2006 02:23:55 -0000	1.35
  @@ -0,0 +1,393 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +static GtkItemFactoryEntry popup_items[] = {
  +  { N_("/Add Net"), 	      NULL, i_callback_add_net,           0, NULL},
  +  { N_("/Add Attribute..."),  NULL, i_callback_add_attribute,     0, NULL},
  +  { N_("/Add Component..."),  NULL, i_callback_add_component,     0, NULL},
  +  { N_("/Add Bus"), 	      NULL, i_callback_add_bus,           0, NULL},
  +  { N_("/Add Text"), 	      NULL, i_callback_add_text,          0, NULL},
  +  { "/sep1", NULL, NULL, 0, "<Separator>"},
  +  { N_("/Zoom In"),       NULL, i_callback_view_zoom_in,      0, NULL},
  +  { N_("/Zoom Out"),      NULL, i_callback_view_zoom_out,     0, NULL},
  +  { N_("/Zoom Box"),      NULL, i_callback_view_zoom_box,     0, NULL},
  +  { N_("/Zoom Extents"),  NULL, i_callback_view_zoom_extents, 0, NULL},
  +  { "/sep1", NULL, NULL, 0, "<Separator>"},
  +  { N_("/Select"), 	  NULL, i_callback_edit_select,       0, NULL},
  +  { N_("/Edit..."), 	  NULL, i_callback_edit_edit,         0, NULL},
  +  { N_("/Copy"),          NULL, i_callback_edit_copy,         0, NULL},
  +  { N_("/Move"),          NULL, i_callback_edit_move,         0, NULL},
  +  { N_("/Delete"),        NULL, i_callback_edit_delete,       0, NULL},
  +  /* Menu items for hierarchy added by SDB 1.9.2005.  */
  +  {"/sep1", NULL, NULL, 0, "<Separator>"},
  +  {N_("/Down Schematic"), NULL, i_callback_hierarchy_down_schematic, 0, NULL},
  +  {N_("/Down Symbol"),    NULL, i_callback_hierarchy_down_symbol,    0, NULL},
  +  {N_("/Up"),             NULL, i_callback_hierarchy_up,             0, NULL},
  +};  
  +
  +int npopup_items = sizeof(popup_items) / sizeof(popup_items[0]);
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void g_menu_execute(char *func)
  +{
  +  gchar *guile_string;
  +  
  +  guile_string = g_strdup_printf("(%s)", func);
  +#if DEBUG
  +  printf("%s\n", guile_string);
  +#endif
  +  scm_c_eval_string (guile_string);
  +  g_free(guile_string);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void get_main_menu(TOPLEVEL * w_current, GtkWidget ** menubar)
  +{
  +  char *buf;
  +  GtkWidget *menu_item;
  +  GtkWidget *root_menu;
  +  GtkWidget *menu_bar;
  +  GtkWidget *menu;
  +  int scm_items_len;
  +  SCM scm_items;
  +  SCM scm_item;
  +  SCM scm_item_name;
  +  SCM scm_item_func;
  +  SCM scm_item_hotkey_func;
  +  SCM scm_index;
  +  SCM scm_keys;
  +  char *menu_name;
  +  char **raw_menu_name = malloc (sizeof(char *));
  +  char *menu_item_name;
  +  char *raw_menu_item_name;
  +  char *menu_item_func;
  +  char *menu_item_hotkey_func;
  +  char *menu_item_keys;
  +  char *spaces;
  +  char *help_string;
  +  int i, j;
  +  int name_len, key_len, pad;
  +  int sum, diff, max_size, space_size;
  +#ifdef HAS_GTK22
  +  PangoLayout *layout;
  +  int name_width, keys_width;
  +#else
  +  GtkStyle *style;
  +  GdkFont *font=NULL;
  +#endif 
  +
  +  menu_bar = gtk_menu_bar_new ();
  +  for (i = 0 ; i < s_menu_return_num(); i++) {
  +    
  +    scm_items = s_menu_return_entry(i, raw_menu_name);   
  +    if (*raw_menu_name == NULL) {
  +      fprintf(stderr, "Oops.. got a NULL menu name in get_main_menu()\n");
  +      exit(-1);
  +    }
  +
  +    menu = gtk_menu_new();
  +
  +    menu_item = gtk_tearoff_menu_item_new ();
  +    gtk_menu_append(GTK_MENU(menu), menu_item);
  +    gtk_widget_show(menu_item);
  +
  +#ifdef HAS_GTK12
  +    /* get info for style/font */
  +    style = gtk_rc_get_style(w_current->main_window);
  +    if (style) {
  +       font = style->font;
  +    } else {
  +       font = GTK_WIDGET (w_current->main_window)->style->font;
  +    }
  +
  +    space_size = gdk_string_width(font, " ");
  +    max_size = gdk_string_width(font, "123456789012345678901234567890");
  +
  +#else
  +
  +    layout = gtk_widget_create_pango_layout(menu, " ");
  +    pango_layout_get_pixel_size(layout, &space_size, NULL);
  +    g_object_unref(layout);
  +
  +    layout = gtk_widget_create_pango_layout(menu, 
  +	                                    "123456789012345678901234567890");
  +    pango_layout_get_pixel_size(layout, &max_size, NULL);
  +    g_object_unref(layout);
  +
  +#endif
  +
  +    scm_items_len = (int) scm_ilength (scm_items);
  +    for (j = 0 ; j < scm_items_len; j++) {
  +
  +      scm_index = SCM_MAKINUM (j);
  +      scm_item = scm_list_ref (scm_items, scm_index);
  +      scm_item_name = SCM_CAR (scm_item);
  +      scm_item_func = SCM_CADR (scm_item);
  +      scm_item_hotkey_func = SCM_CADDR (scm_item);
  +      SCM_ASSERT(SCM_STRINGP(scm_item_name), scm_item_name, SCM_ARGn, "get_main_menu item_name");
  +      SCM_ASSERT(SCM_SYMBOLP(scm_item_func), scm_item_func, SCM_ARGn, "get_main_menu item_func");
  +      SCM_ASSERT(SCM_SYMBOLP(scm_item_hotkey_func), scm_item_hotkey_func, SCM_ARGn, "get_main_menu hotkey_func");
  +
  +      raw_menu_item_name = SCM_STRING_CHARS (scm_item_name);
  +      menu_item_func = SCM_SYMBOL_CHARS (scm_item_func);
  +      menu_item_hotkey_func = SCM_SYMBOL_CHARS (scm_item_hotkey_func);
  +
  +      menu_item_name = (char *) gettext(raw_menu_item_name);
  +
  +      if (strcmp(menu_item_name, "SEPARATOR") == 0) {
  +        menu_item = gtk_menu_item_new();
  +        gtk_menu_append(GTK_MENU(menu), menu_item);
  +      } else { 
  +        buf = g_strdup_printf("(find-key '%s)", menu_item_hotkey_func);
  +        scm_keys = scm_c_eval_string (buf);
  +	free(buf);
  +        if (scm_keys == SCM_BOOL_F) {
  +          menu_item_keys = malloc(sizeof(char)*2);
  +          menu_item_keys[0] = ' ';
  +          menu_item_keys[1] = '\0';
  +        } else {
  +          menu_item_keys = g_strdup (SCM_STRING_CHARS (scm_keys));
  +        }      
  +
  +        name_len = strlen(menu_item_name);
  +        key_len = strlen(menu_item_keys);
  +
  +#ifdef HAS_GTK22
  +        layout = gtk_widget_create_pango_layout(menu, menu_item_name);
  +        pango_layout_get_pixel_size(layout, &name_width, NULL);
  +        g_object_unref(layout);
  +
  +        layout = gtk_widget_create_pango_layout(menu, menu_item_keys);
  +        pango_layout_get_pixel_size(layout, &keys_width, NULL);
  +        g_object_unref(layout);
  +
  +        sum = name_width + keys_width;
  +#else
  +        sum = gdk_string_width(font, menu_item_name) + 
  +              gdk_string_width(font, menu_item_keys);
  +#endif
  +
  +	diff = max_size - sum;
  +	pad = diff/space_size;
  +	if (pad < 0) { 
  +           pad = 1;
  +	} 
  +
  +        spaces = malloc(sizeof(char)*(pad+1));
  +        memset(spaces, ' ', pad);
  +        spaces[pad] = '\0';
  +        buf = g_strdup_printf("%s%s%s", menu_item_name, spaces, menu_item_keys);
  +
  +#if DEBUG
  +        printf("%s :\n %d %d %d = %d\n", buf, name_len, pad, key_len,
  +               name_len + pad + key_len);
  +#endif
  +      
  +        menu_item = gtk_menu_item_new_with_label(buf);
  +	free(buf);
  +        gtk_menu_append(GTK_MENU(menu), menu_item);
  +        gtk_signal_connect_object(GTK_OBJECT(menu_item), "activate",
  +                                  GTK_SIGNAL_FUNC(g_menu_execute),
  +                                  (gpointer) g_strdup (menu_item_func));
  +        /* The g_strdup is a memory leak, but this is okay. I think. */
  +        free(spaces);
  +        free(menu_item_keys);
  +      }
  +      
  +      gtk_widget_show(menu_item);
  +
  +      /* add a handle to the menu_bar object to get access to widget objects */
  +      /* This string should NOT be internationalized */
  +      buf = g_strdup_printf("%s/%s", *raw_menu_name, raw_menu_item_name);
  +      gtk_object_set_data(GTK_OBJECT(menu_bar), buf, menu_item);
  +      free(buf);
  +      
  +    }
  +    
  +    menu_name = (char *) gettext(*raw_menu_name);
  +    root_menu = gtk_menu_item_new_with_label (menu_name);
  +    /* do not free *raw_menu_name */
  +
  +    help_string = gettext("Help");
  +    if (strcmp(menu_name, help_string) == 0) {
  +      gtk_menu_item_right_justify (GTK_MENU_ITEM(root_menu));
  +    }
  +    gtk_widget_show (root_menu);
  +    gtk_menu_item_set_submenu (GTK_MENU_ITEM (root_menu), menu);
  +    gtk_menu_bar_append (GTK_MENU_BAR (menu_bar), root_menu);
  +  }
  +  
  +  free(raw_menu_name);
  +  *menubar = menu_bar;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +GtkWidget *get_main_popup(TOPLEVEL *w_current)
  +{
  +  static GtkItemFactory *item_factory;
  +  GtkAccelGroup *accel_group;
  +  GtkWidget *menu;
  +
  +  accel_group = gtk_accel_group_new();
  +
  +  /* This function initializes the item factory.
  +     Param 1: The type of menu - can be GTK_TYPE_MENU_BAR, GTK_TYPE_MENU, or GTK_TYPE_OPTION_MENU.
  +     Param 2: The path of the menu.
  +     Param 3: A pointer to a gtk_accel_group.  The item factory sets up
  +     the accelerator table while generating menus.
  +  */
  +  item_factory = gtk_item_factory_new(GTK_TYPE_MENU, "<popup>",
  +                                      accel_group);
  +  gtk_item_factory_set_translate_func (item_factory,
  +                                       (GtkTranslateFunc)gettext,
  +                                       NULL, NULL);
  +  /* This function creates the pop-up menu itself & attaches it to the
  +     GtkItemFactory. Pass the item factory,
  +     the number of items in the array, the array itself, and any
  +     callback data for the the menu items. Note that npopup_items is 
  +     a static var declared in this file above; popup_items is also a
  +     static var declared above.
  +  */
  +  gtk_item_factory_create_items(item_factory, npopup_items, popup_items, w_current);
  +
  +#ifdef HAS_GTK12
  +  /* Attach the new accelerator group to the window. */
  +  gtk_accel_group_attach (accel_group, GTK_OBJECT (w_current->main_window));
  +#endif
  +
  +  /* Finally, return the actual menu created by the item factory. */
  +  menu = (GtkWidget *) gtk_item_factory_get_widget(item_factory, "<popup>");
  +  return (menu);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  need to look at this... here and the setup
  + */
  +gint do_popup (TOPLEVEL *w_current, GdkEventButton *event)
  +{
  +  GtkWidget *menu;   /* =NULL; */ /* was static */
  +
  +  menu = NULL;  /* Why do I need to do this? */
  +  if (!menu)
  +    menu = (GtkWidget *) w_current->popup_menu;
  +
  +  if (menu == NULL) {
  +    printf("null menu\n");
  +  }
  +
  +  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
  +                  event->button, event->time);
  +
  +  return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_menus_sensitivity (TOPLEVEL* w_current, const char *buf, int flag)
  +{
  +  GtkWidget* item=NULL;
  +  
  +  if (!buf) {
  +    return;
  +  }
  +
  +  if (!w_current->menubar) {
  +    return;
  +  }
  +  
  +  item = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(w_current->menubar), buf);
  +
  +  if (item) {
  +    gtk_widget_set_sensitive(GTK_WIDGET(item), flag);
  +    /* free(item); */ /* Why doesn't this need to be freed?  */
  +  } else {
  +    s_log_message(_("Tried to set the sensitivity on a non-existent menu item\n")); 
  +  }
  + 
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  This function sets the sensitivity of the items in the right button
  + *  popup.
  + *
  + *  \note
  + *  1.9.2005 -- SDB.
  + */
  +void x_menus_popup_sensitivity (TOPLEVEL* w_current, const char *buf, int flag)
  +{
  +  GtkWidget *menu_item;
  +  GtkItemFactory *menu_item_factory;
  +  
  +  if (!buf) {
  +    return;
  +  }
  +
  +  if (!w_current->popup_menu) {
  +    s_log_message(_("Popup_menu_item_factory doesn't exist!\n")); 
  +    return;
  +  }
  +
  +  /* 
  +   * first get entire item factory from popup, then get the individual 
  +   * menu item indexed by buf.
  +   */
  +  menu_item_factory = (GtkItemFactory *)gtk_item_factory_from_widget(w_current->popup_menu);  
  +  menu_item = (GtkWidget *) gtk_item_factory_get_widget(menu_item_factory, buf);
  +  if (menu_item) {
  +    gtk_widget_set_sensitive(GTK_WIDGET(menu_item), flag);
  +  } else {
  +    s_log_message(_("Tried to set the sensitivity on a non-existent popup menu_item\n")); 
  +  }
  +}
  
  
  
  1.1                  eda/geda/gaf/gschem/src/x_multiattrib.c
  
  Index: x_multiattrib.c
  ===================================================================
  /* gEDA - GPL Electronic Design Automation
   * gschem - gEDA Schematic Capture
   * Copyright (C) 1998-2000 Ales V. Hvezda
   *
   * 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 USA
   */
  #include <config.h>
  
  #include <stdio.h>
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
  #endif
  #ifdef HAVE_STRING_H
  #include <string.h>
  #endif
  
  #include <libgeda/libgeda.h>
  
  #include "../include/i_vars.h"
  #include "../include/globals.h"
  #include "../include/prototype.h"
  
  #ifdef HAVE_LIBDMALLOC
  #include <dmalloc.h>
  #endif
  
  #include <gdk/gdkkeysyms.h>
  #include "../include/x_multiattrib.h"
  
  /*! \brief Open multiple attribute editor dialog.
   *  \par Function Description
   *  Opens the multiple attribute editor dialog for <B>object</B> in the
   *  context of <B>toplevel</B>.
   *
   *  The dialog is modal and this function does not return until the user
   *  closes the dialog.
   *
   *  \param [in] toplevel  The TOPLEVEL object.
   *  \param [in] object    OBJECT to edit attributes on.
   */
  void x_multiattrib_open (TOPLEVEL *toplevel, OBJECT *object)
  {
    GtkWidget *dialog;
  
    dialog = GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB,
                                       "toplevel", toplevel,
                                       "object", object,
                                       NULL));
    gtk_widget_show (dialog);
    switch (gtk_dialog_run ((GtkDialog*)dialog)) {
        case MULTIATTRIB_RESPONSE_CLOSE:
        case GTK_RESPONSE_DELETE_EVENT:
          /* resets state and update message in toolbar */
          i_set_state (toplevel, SELECT);
          i_update_toolbar (toplevel);
          break;
        default:
          g_assert_not_reached ();
    }
    gtk_widget_destroy (dialog);
    
  }
  
  /*! \section celltextview-widget Cell TextView Widget Code.
   * This widget makes a 'GtkTextView' widget implements the 'GtkCellEditable'
   * interface. It can then be used to renderer multi-line texts inside
   * tree views ('GtkTreeView').
   */
  static void celltextview_class_init (CellTextViewClass *klass);
  static void celltextview_init       (CellTextView *self);
  static void celltextview_cell_editable_init (GtkCellEditableIface *iface);
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static gboolean celltextview_key_press_event (GtkWidget   *widget,
  					      GdkEventKey *event,
  					      gpointer     data)
  {
    CellTextView *celltextview = (CellTextView*)widget;
  
    /* ends editing of cell if one of these keys are pressed */
    if (
      /* the Escape key */
      event->keyval == GDK_Escape ||
      /* the Enter key without the Control modifier */
      (!(event->state & GDK_CONTROL_MASK) &&
       (event->keyval == GDK_Return ||
        event->keyval == GDK_KP_Enter))) {
      gtk_cell_editable_editing_done  (GTK_CELL_EDITABLE (celltextview));
      gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (celltextview));
      return TRUE;
    }
  
    return FALSE;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void celltextview_start_editing (GtkCellEditable *cell_editable,
  					GdkEvent        *event)
  {
    g_signal_connect (cell_editable,
                      "key_press_event",
                      G_CALLBACK (celltextview_key_press_event),
                      NULL);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  GType celltextview_get_type()
  {
    static GType celltextview_type = 0;
    
    if (!celltextview_type) {
      static const GTypeInfo celltextview_info = {
        sizeof(CellTextViewClass),
        NULL, /* base_init */
        NULL, /* base_finalize */
        (GClassInitFunc) celltextview_class_init,
        NULL, /* class_finalize */
        NULL, /* class_data */
        sizeof(CellTextView),
        0,    /* n_preallocs */
        (GInstanceInitFunc) celltextview_init,
      };
  
      static const GInterfaceInfo cell_editable_info = {
        (GInterfaceInitFunc) celltextview_cell_editable_init,
        NULL, /* interface_finalize */
        NULL  /* interface_data */
      };
  		
      celltextview_type = g_type_register_static(GTK_TYPE_TEXT_VIEW,
  					       "CellTextView",
  					       &celltextview_info, 0);
      g_type_add_interface_static(celltextview_type,
  				GTK_TYPE_CELL_EDITABLE,
  				&cell_editable_info);
    }
    
    return celltextview_type;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void celltextview_class_init(CellTextViewClass *klass)
  {
  /*   GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void celltextview_init(CellTextView *self)
  {
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void celltextview_cell_editable_init(GtkCellEditableIface *iface)
  {
    iface->start_editing = celltextview_start_editing;
  }
  
  /*! \section multi-line-text-cell-renderer Multi-line Text Cell Renderer
   * GTK has no multi-line text cell renderer. This code adds one to be used
   * in gschem code. It is inspired by the 'GtkCellRendererCombo' renderer
   * of GTK 2.4 (LGPL).
   */
  static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass *klass);
  static void cellrenderermultilinetext_init (CellRendererMultiLineText *self);
  
  static void cellrenderermultilinetext_editing_done (GtkCellEditable *cell_editable,
                                                      gpointer         user_data);
  static gboolean cellrenderermultilinetext_focus_out_event (GtkWidget *widget,
                                                             GdkEvent  *event,
                                                             gpointer   user_data);
  
  
  #define CELL_RENDERER_MULTI_LINE_TEXT_PATH "cell-renderer-multi-line-text-path"
  
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static GtkCellEditable* cellrenderermultilinetext_start_editing(GtkCellRenderer      *cell,
  								GdkEvent             *event,
  								GtkWidget            *widget,
  								const gchar          *path,
  								GdkRectangle         *background_area,
  								GdkRectangle         *cell_area,
  								GtkCellRendererState  flags)
  {
    GtkCellRendererText *cell_text;
    CellRendererMultiLineText *cell_mlt;
    GtkWidget *textview;
    GtkTextBuffer *textbuffer;
    
    cell_text = GTK_CELL_RENDERER_TEXT (cell);
    if (cell_text->editable == FALSE) {
      return NULL;
    }
  
    cell_mlt  = CELL_RENDERER_MULTI_LINE_TEXT (cell);
  
    textbuffer = GTK_TEXT_BUFFER (g_object_new (GTK_TYPE_TEXT_BUFFER,
                                                NULL));
    gtk_text_buffer_set_text (textbuffer,
                              cell_text->text,
                              strlen (cell_text->text));
    
    textview = GTK_WIDGET (g_object_new (TYPE_CELL_TEXT_VIEW,
                                         /* GtkTextView */
  				       /* unknown property in GTK 2.2, use
  					* gtk_text_view_set_buffer() instead */
  				       /* "buffer",   textbuffer, */
                                         "editable", TRUE,
                                         NULL));
    gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), textbuffer);
    g_object_set_data_full (G_OBJECT (textview),
                            CELL_RENDERER_MULTI_LINE_TEXT_PATH,
                            g_strdup (path), g_free);
  
    gtk_widget_show (textview);
  
    g_signal_connect (GTK_CELL_EDITABLE (textview),
                      "editing_done",
                      G_CALLBACK (cellrenderermultilinetext_editing_done),
                      cell_mlt);
    cell_mlt->focus_out_id =
    g_signal_connect (textview,
                      "focus_out_event",
                      G_CALLBACK (cellrenderermultilinetext_focus_out_event),
                      cell_mlt);
  
    return GTK_CELL_EDITABLE (textview);
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void cellrenderermultilinetext_editing_done(GtkCellEditable *cell_editable,
  						   gpointer         user_data)
  {
    CellRendererMultiLineText *cell = CELL_RENDERER_MULTI_LINE_TEXT (user_data);
    GtkTextBuffer *buffer;
    GtkTextIter start, end;
    gchar *new_text;
    const gchar *path;
  
    if (cell->focus_out_id > 0) {
      g_signal_handler_disconnect (cell_editable,
                                   cell->focus_out_id);
      cell->focus_out_id = 0;
    }
  
    buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (cell_editable));
    gtk_text_buffer_get_start_iter (buffer, &start);
    gtk_text_buffer_get_end_iter   (buffer, &end);
    new_text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
    
    path = g_object_get_data (G_OBJECT (cell_editable),
                              CELL_RENDERER_MULTI_LINE_TEXT_PATH);
    g_signal_emit_by_name (cell, "edited", path, new_text);
  
    g_free (new_text);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static gboolean cellrenderermultilinetext_focus_out_event(GtkWidget *widget,
  							  GdkEvent *event,
  							  gpointer user_data)
  {
    cellrenderermultilinetext_editing_done (GTK_CELL_EDITABLE (widget),
                                            user_data);
  
    return FALSE;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  GType cellrenderermultilinetext_get_type()
  {
    static GType cellrenderermultilinetext_type = 0;
    
    if (!cellrenderermultilinetext_type) {
      static const GTypeInfo cellrenderermultilinetext_info = {
        sizeof(CellRendererMultiLineTextClass),
        NULL, /* base_init */
        NULL, /* base_finalize */
        (GClassInitFunc) cellrenderermultilinetext_class_init,
        NULL, /* class_finalize */
        NULL, /* class_data */
        sizeof(CellRendererMultiLineText),
        0,    /* n_preallocs */
        (GInstanceInitFunc) cellrenderermultilinetext_init,
      };
  		
      cellrenderermultilinetext_type = g_type_register_static (
        GTK_TYPE_CELL_RENDERER_TEXT,
        "CellRendererMultiLineText",
        &cellrenderermultilinetext_info, 0);
    }
    
    return cellrenderermultilinetext_type;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void cellrenderermultilinetext_class_init(CellRendererMultiLineTextClass *klass)
  {
  /*   GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
    GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
  
    cell_class->start_editing = cellrenderermultilinetext_start_editing;
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void cellrenderermultilinetext_init(CellRendererMultiLineText *self)
  {
  }
  
  
  enum {
    PROP_TOPLEVEL=1,
    PROP_OBJECT
  };
  
  enum {
    COLUMN_ATTRIBUTE,
    NUM_COLUMNS
  };
  
  
  static void multiattrib_class_init (MultiattribClass *class);
  static void multiattrib_init       (Multiattrib *multiattrib);
  static void multiattrib_set_property (GObject *object,
                                        guint property_id,
                                        const GValue *value,
                                        GParamSpec *pspec);
  static void multiattrib_get_property (GObject *object,
                                        guint property_id,
                                        GValue *value,
                                        GParamSpec *pspec);
  
  static void multiattrib_popup_menu (Multiattrib *multiattrib,
                                      GdkEventButton *event);
  
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_action_add_attribute(TOPLEVEL *toplevel,
  					     OBJECT *object,
  					     const gchar *name,
  					     const gchar *value,
  					     gint visible,
  					     gint show_name_value) 
  {
    OBJECT *o_attrib;
    gchar *newtext;
    
    newtext = g_strdup_printf ("%s=%s", name, value);
  
    /* create a new attribute and link it */
    o_attrib = o_attrib_add_attrib (toplevel, newtext,
                                    visible, show_name_value, object);
  
    toplevel->page_current->CHANGED = 1;
    o_undo_savestate (toplevel, UNDO_ALL);
  
    g_free (newtext);
  
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_action_duplicate_attribute(TOPLEVEL *toplevel,
  						   OBJECT *object,
  						   OBJECT *o_attrib) 
  {
    OBJECT *o_new;
    
    o_new = o_attrib_add_attrib (toplevel,
                                 o_attrib->text->string,
                                 o_attrib->visibility,
                                 o_attrib->show_name_value,
                                 object);
    toplevel->page_current->CHANGED = 1;
    o_undo_savestate (toplevel, UNDO_ALL);
  
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_action_delete_attribute(TOPLEVEL *toplevel,
  						OBJECT *o_attrib) 
  {
    /* actually deletes the attribute */
    o_selection_remove (toplevel->page_current->selection2_head, o_attrib);
    o_delete_text (toplevel, o_attrib);
    toplevel->page_current->CHANGED=1;
    o_undo_savestate (toplevel, UNDO_ALL);
  
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_column_set_data_name(GtkTreeViewColumn *tree_column,
  					     GtkCellRenderer *cell,
  					     GtkTreeModel *tree_model,
  					     GtkTreeIter *iter,
  					     gpointer data)
  {
    OBJECT *o_attrib;
    gchar *name, *value;
  
    gtk_tree_model_get (tree_model, iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
    
    o_attrib_get_name_value (o_attrib->text->string, &name, &value);
    g_object_set (cell,
                  "text", name,
                  NULL);
    g_free (name);
    g_free (value);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_column_set_data_value(GtkTreeViewColumn *tree_column,
  					      GtkCellRenderer *cell,
  					      GtkTreeModel *tree_model,
  					      GtkTreeIter *iter,
  					      gpointer data)           
  {
    OBJECT *o_attrib;
    gchar *name, *value;
  
    gtk_tree_model_get (tree_model, iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
    
    o_attrib_get_name_value (o_attrib->text->string, &name, &value);
    g_object_set (cell,
                  "text", value,
                  NULL);
    g_free (name);
    g_free (value);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_column_set_data_visible(GtkTreeViewColumn *tree_column,
  						GtkCellRenderer *cell,
  						GtkTreeModel *tree_model,
  						GtkTreeIter *iter,
  						gpointer data)
  {
    OBJECT *o_attrib;
  
    gtk_tree_model_get (tree_model, iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
    
    g_object_set (cell,
                  "active", (o_attrib->visibility == VISIBLE),
                  NULL);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_column_set_data_show_name(GtkTreeViewColumn *tree_column,
  						  GtkCellRenderer *cell,
  						  GtkTreeModel *tree_model,
  						  GtkTreeIter *iter,
  						  gpointer data)
  {
    OBJECT *o_attrib;
  
    gtk_tree_model_get (tree_model, iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
    
    g_object_set (cell,
                  "active", (o_attrib->show_name_value == SHOW_NAME_VALUE ||
                             o_attrib->show_name_value == SHOW_NAME),
                  NULL);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_column_set_data_show_value(GtkTreeViewColumn *tree_column,
  						   GtkCellRenderer *cell,
  						   GtkTreeModel *tree_model,
  						   GtkTreeIter *iter,
  						   gpointer data)
  {
    OBJECT *o_attrib;
  
    gtk_tree_model_get (tree_model, iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
    
    g_object_set (cell,
                  "active", (o_attrib->show_name_value == SHOW_NAME_VALUE ||
                             o_attrib->show_name_value == SHOW_VALUE),
                  NULL);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_callback_edited_name(GtkCellRendererText *cellrenderertext,
  					     gchar *arg1,
  					     gchar *arg2,
  					     gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    GtkTreeModel *model;
    GtkTreeIter iter;
    OBJECT *o_attrib;
    TOPLEVEL *toplevel;
    gchar *name, *value, *newtext;
  
    model = gtk_tree_view_get_model (multiattrib->treeview);
    toplevel = multiattrib->toplevel;
  
    if (!gtk_tree_model_get_iter_from_string (model, &iter, arg1)) {
      return;
    }
  
    if (g_ascii_strcasecmp (arg2, "") == 0) {
      GtkWidget *dialog = gtk_message_dialog_new (
        GTK_WINDOW (multiattrib),
        GTK_DIALOG_MODAL,
        GTK_MESSAGE_ERROR,
        GTK_BUTTONS_OK,
        _("Attributes with empty name are not allowed. Please set a name."));
      gtk_dialog_run (GTK_DIALOG (dialog));
      gtk_widget_destroy (dialog);
      return;
    }
    
    gtk_tree_model_get (model, &iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
  
    o_attrib_get_name_value (o_attrib->text->string, &name, &value);
    newtext = g_strdup_printf ("%s=%s", arg2, value);
    
    /* actually modifies the attribute */
    o_text_change (toplevel, o_attrib,
                   newtext, o_attrib->visibility, o_attrib->show_name_value);
  
    g_free (name);
    g_free (value);
    g_free (newtext);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_callback_edited_value(GtkCellRendererText *cell_renderer,
  					      gchar *arg1,
  					      gchar *arg2,
  					      gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    GtkTreeModel *model;
    GtkTreePath *path;
    GtkTreeIter iter;
    OBJECT *o_attrib;
    TOPLEVEL *toplevel;
    gchar *name, *value, *newtext;
  
    model = gtk_tree_view_get_model (multiattrib->treeview);
    toplevel = multiattrib->toplevel;
  
    path = gtk_tree_path_new_from_string (arg1);
    
    if (!gtk_tree_model_get_iter (model, &iter, path)) {
      return;
    }
  
    gtk_tree_model_get (model, &iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
  
    o_attrib_get_name_value (o_attrib->text->string, &name, &value);
    newtext = g_strdup_printf ("%s=%s", name, arg2);
    
    /* actually modifies the attribute */
    o_text_change (toplevel, o_attrib,
                   newtext, o_attrib->visibility, o_attrib->show_name_value);
    
    /* signals the modification of the row */
    gtk_tree_model_row_changed (model, path, &iter);
    
    g_free (name);
    g_free (value);
    g_free (newtext);
    gtk_tree_path_free (path);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_callback_toggled_visible(GtkCellRendererToggle *cell_renderer,
  						 gchar *path,
  						 gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    GtkTreeModel *model;
    GtkTreeIter iter;
    OBJECT *o_attrib;
    TOPLEVEL *toplevel;
    gint visibility;
  
    model = gtk_tree_view_get_model (multiattrib->treeview);
    toplevel = multiattrib->toplevel;
  
    if (!gtk_tree_model_get_iter_from_string (model, &iter, path)) {
      return;
    }
  
    gtk_tree_model_get (model, &iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
    o_text_erase (toplevel, o_attrib);
  
    visibility = o_attrib->visibility == VISIBLE ? INVISIBLE : VISIBLE;
  
    /* actually modifies the attribute */
    o_attrib->visibility = visibility;
    o_text_recreate (toplevel, o_attrib);
    o_text_draw (toplevel, o_attrib);
    o_undo_savestate (toplevel, UNDO_ALL);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_callback_toggled_show_name(GtkCellRendererToggle *cell_renderer,
  						   gchar *path,
  						   gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    GtkTreeModel *model;
    GtkTreeIter iter;
    OBJECT *o_attrib;
    TOPLEVEL *toplevel;
    gint new_snv;
  
    model = gtk_tree_view_get_model (multiattrib->treeview);
    toplevel = multiattrib->toplevel;
  
    if (!gtk_tree_model_get_iter_from_string (model, &iter, path)) {
      return;
    }
  
    gtk_tree_model_get (model, &iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
    o_text_erase (toplevel, o_attrib);
  
    switch (o_attrib->show_name_value) {
        case SHOW_NAME_VALUE: new_snv = SHOW_VALUE;      break;
        case SHOW_NAME:       new_snv = SHOW_VALUE;      break;
        case SHOW_VALUE:      new_snv = SHOW_NAME_VALUE; break;
        default:
          g_assert_not_reached ();
          new_snv = SHOW_NAME_VALUE;
    }
  
    /* actually modifies the attribute */
    o_attrib->show_name_value = new_snv;
    o_text_recreate (toplevel, o_attrib);
    o_text_draw (toplevel, o_attrib);
    o_undo_savestate (toplevel, UNDO_ALL);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_callback_toggled_show_value(GtkCellRendererToggle *cell_renderer,
  						    gchar *path,
  						    gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    GtkTreeModel *model;
    GtkTreeIter iter;
    OBJECT *o_attrib;
    TOPLEVEL *toplevel;
    gint new_snv;
  
    model = gtk_tree_view_get_model (multiattrib->treeview);
    toplevel = multiattrib->toplevel;
  
    if (!gtk_tree_model_get_iter_from_string (model, &iter, path)) {
      return;
    }
  
    gtk_tree_model_get (model, &iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
    o_text_erase (toplevel, o_attrib);
  
    switch (o_attrib->show_name_value) {
        case SHOW_NAME_VALUE: new_snv = SHOW_NAME;       break;
        case SHOW_NAME:       new_snv = SHOW_NAME_VALUE; break;
        case SHOW_VALUE:      new_snv = SHOW_NAME;       break;
        default:
          g_assert_not_reached ();
          new_snv = SHOW_NAME_VALUE;
    }
  
    /* actually modifies the attribute */
    o_attrib->show_name_value = new_snv;
    o_text_recreate (toplevel, o_attrib);
    o_text_draw (toplevel, o_attrib);
    o_undo_savestate (toplevel, UNDO_ALL);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static gboolean multiattrib_callback_key_pressed(GtkWidget *widget,
  						 GdkEventKey *event,
  						 gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
  
    if (event->state == 0 &&
        (event->keyval == GDK_Delete || event->keyval == GDK_KP_Delete)) {
      GtkTreeModel *model;
      GtkTreeIter iter;
      OBJECT *o_attrib;
      /* delete the currently selected attribute */
  
      if (!gtk_tree_selection_get_selected (
            gtk_tree_view_get_selection (multiattrib->treeview),
            &model, &iter)) {
        /* nothing selected, nothing to do */
        return FALSE;
      }
      
      gtk_tree_model_get (model, &iter,
                          COLUMN_ATTRIBUTE, &o_attrib,
                          -1);
      g_assert (o_attrib->type == OBJ_TEXT);
      
      multiattrib_action_delete_attribute (multiattrib->toplevel,
                                           o_attrib);
      
      /* update the treeview contents */
      multiattrib_update (multiattrib);
    }
  
    return FALSE;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static gboolean multiattrib_callback_button_pressed(GtkWidget *widget,
  						    GdkEventButton *event,
  						    gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    gboolean ret = FALSE;
  
    if (event->type == GDK_BUTTON_PRESS  &&  event->button == 3) {
      multiattrib_popup_menu (multiattrib, event);
      ret = TRUE;
    }
  
    return ret;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static gboolean multiattrib_callback_popup_menu(GtkWidget *widget,
  						gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
  
    multiattrib_popup_menu (multiattrib, NULL);
    
    return TRUE;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_callback_popup_duplicate(GtkMenuItem *menuitem,
  						 gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    GtkTreeModel *model;
    GtkTreeIter iter;
    TOPLEVEL *toplevel;
    OBJECT *object, *o_attrib;
    
    if (!gtk_tree_selection_get_selected (
          gtk_tree_view_get_selection (multiattrib->treeview),
          &model, &iter)) {
      /* nothing selected, nothing to do */
      return;
    }
  
    toplevel = multiattrib->toplevel;
    object   = multiattrib->object;
    
    gtk_tree_model_get (model, &iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
  
    multiattrib_action_duplicate_attribute (toplevel, object, o_attrib);
  
    /* update the treeview contents */
    multiattrib_update (multiattrib);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_callback_popup_delete(GtkMenuItem *menuitem,
  					      gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    GtkTreeModel *model;
    GtkTreeIter iter;
    TOPLEVEL *toplevel;
    OBJECT *o_attrib;
    
    if (!gtk_tree_selection_get_selected (
          gtk_tree_view_get_selection (multiattrib->treeview),
          &model, &iter)) {
      /* nothing selected, nothing to do */
      return;
    }
  
    toplevel = multiattrib->toplevel;
    
    gtk_tree_model_get (model, &iter,
                        COLUMN_ATTRIBUTE, &o_attrib,
                        -1);
    g_assert (o_attrib->type == OBJ_TEXT);
  
    multiattrib_action_delete_attribute (toplevel, o_attrib);
  
    /* update the treeview contents */
    multiattrib_update (multiattrib);
    
  }
  
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static gboolean multiattrib_callback_dialog_key_pressed(GtkWidget *widget,
  							GdkEventKey *event,
  							gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)widget;
    gboolean retval = FALSE;
  
    /* close the dialog if the Escape key is pressed */
    if (event->keyval == GDK_Escape) {
      gtk_dialog_response ((GtkDialog*)multiattrib,
                           MULTIATTRIB_RESPONSE_CLOSE);
      retval = TRUE;
    }
  
    return retval;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static gboolean multiattrib_callback_value_key_pressed(GtkWidget *widget,
  						       GdkEventKey *event,
  						       gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)widget;
    gboolean retval = FALSE;
  
    /* ends editing of cell if one of these keys are pressed: */
    /*  - the Return key without the Control modifier */
    /*  - the Tab key without the Control modifier */
    if ((event->keyval == GDK_Return || event->keyval == GDK_KP_Enter) ||
        (event->keyval == GDK_Tab    || event->keyval == GDK_KP_Tab)) {
      /* Control modifier activated? */
      if (event->state & GDK_CONTROL_MASK) {
        /* yes the modifier in event structure and let event propagate */
        event->state ^= GDK_CONTROL_MASK;
        retval = FALSE;
      } else {
        /* change focus and stop propagation */
        g_signal_emit_by_name (multiattrib,
                               "move_focus",
                               (event->state & GDK_SHIFT_MASK) ?
                               GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD);
        retval = TRUE;
      }
    }
  
    return retval;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_callback_button_add(GtkButton *button,
  					    gpointer user_data)
  {
    Multiattrib *multiattrib = (Multiattrib*)user_data;
    GtkTextBuffer *buffer;
    GtkTextIter start, end;
    const gchar *name;
    gchar *value;
    TOPLEVEL *toplevel;
    OBJECT *object;
    gboolean visible;
    gint shownv;
  
    toplevel = multiattrib->toplevel;
    object   = multiattrib->object;
    buffer   = gtk_text_view_get_buffer (multiattrib->textview_value);
    
    /* retrieve information from the Add/Edit frame */
    /*   - attribute's name */
    name = gtk_entry_get_text (
      GTK_ENTRY (GTK_COMBO (multiattrib->combo_name)->entry));
    /*   - attribute's value */
    gtk_text_buffer_get_bounds (buffer, &start, &end);
    value = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
    /*   - attribute's visibility status */
    visible = gtk_toggle_button_get_active (
      (GtkToggleButton*)multiattrib->button_visible);
    /*   - visibility type */
    shownv = (gint)gtk_option_menu_get_history (multiattrib->optionmenu_shownv);
  
    if (name[0] == '\0' || name[0] == ' ') {
      /* name not allowed for an attribute */
      g_free (value);
      return;
    }
  
    multiattrib_action_add_attribute (toplevel, object,
                                      name, value,
                                      visible, shownv);
    g_free (value);
    
    /* clear fields of lower frame */
    /*   - resets entry for name */
    gtk_list_select_item (GTK_LIST (multiattrib->combo_name->list), 0);
    /*   - resets entry for value */
    gtk_text_buffer_set_text (buffer, "", 0);
    /*   - resets entry for visibility */
    g_object_set (multiattrib->button_visible,
                  "active", TRUE,
                  NULL);
    /*   - resets entry for show name/value */
    gtk_option_menu_set_history (multiattrib->optionmenu_shownv,
                                 0);
    
    multiattrib_update (multiattrib);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_init_attrib_names(GtkCombo *combo)
  {
    GList *items = NULL;
    const gchar *string;
    gint i;
    
    for (i = 0, string = s_attrib_get (i);
         string != NULL;
         i++, string = s_attrib_get (i)) {
      items = g_list_append (items, (gpointer)string);
    }
  
    gtk_combo_set_popdown_strings (GTK_COMBO (combo), items);
  
    g_list_free (items);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_init_visible_types(GtkOptionMenu *optionmenu)
  {
    GtkWidget *menu, *item;
  
    menu = gtk_menu_new ();
    item = gtk_menu_item_new_with_label (_("Show Name & Value"));
    gtk_menu_append (menu, item);
    item = gtk_menu_item_new_with_label (_("Show Value only"));
    gtk_menu_append (menu, item);
    item = gtk_menu_item_new_with_label (_("Show Name only"));
    gtk_menu_append (menu, item);
  
    gtk_option_menu_set_menu (optionmenu, menu);
    
  }
  
  /*! \brief Popup a context-sensitive menu.
   *  \par Function Description
   *  Pops up a context-sensitive menu.
   *  <B>event</B> can be NULL if the popup is triggered by a key binding
   *  instead of a mouse click.
   *
   *  \param [in] multiattrib  The Multiattrib object.
   *  \param [in] event        Mouse event.
   */
  static void multiattrib_popup_menu(Multiattrib *multiattrib,
  				   GdkEventButton *event)
  {
    GtkTreePath *path;
    GtkWidget *menu;
    struct menuitem_t {
      gchar *label;
      void (*callback)(void);
    };
    struct menuitem_t menuitems[] = {
      { N_("Duplicate"), G_CALLBACK (multiattrib_callback_popup_duplicate) },
      { N_("Delete"),    G_CALLBACK (multiattrib_callback_popup_delete)    },
      { NULL,            NULL                                              } };
    struct menuitem_t *tmp;
    
    if (event != NULL &&
        gtk_tree_view_get_path_at_pos (multiattrib->treeview,
                                       (gint)event->x, 
                                       (gint)event->y,
                                       &path, NULL, NULL, NULL)) {
      GtkTreeSelection *selection;
      selection = gtk_tree_view_get_selection (multiattrib->treeview);
      gtk_tree_selection_unselect_all (selection);
      gtk_tree_selection_select_path (selection, path);
      gtk_tree_path_free (path);
    }
  
    /* create the context menu */
    menu = gtk_menu_new();
    for (tmp = menuitems; tmp->label != NULL; tmp++) {
      GtkWidget *menuitem;
      if (g_strcasecmp (tmp->label, "-") == 0) {
        menuitem = gtk_separator_menu_item_new ();
      } else {
        menuitem = gtk_menu_item_new_with_label (_(tmp->label));
        g_signal_connect (menuitem,
                          "activate",
                          tmp->callback,
                          multiattrib);
      }
      gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
    }
    gtk_widget_show_all (menu);
    /* make menu a popup menu */
    gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
                    (event != NULL) ? event->button : 0,
                    gdk_event_get_time ((GdkEvent*)event));
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  GType multiattrib_get_type()
  {
    static GType multiattrib_type = 0;
    
    if (!multiattrib_type) {
      static const GTypeInfo multiattrib_info = {
        sizeof(MultiattribClass),
        NULL, /* base_init */
        NULL, /* base_finalize */
        (GClassInitFunc) multiattrib_class_init,
        NULL, /* class_finalize */
        NULL, /* class_data */
        sizeof(Multiattrib),
        0,    /* n_preallocs */
        (GInstanceInitFunc) multiattrib_init,
      };
  		
      multiattrib_type = g_type_register_static (GTK_TYPE_DIALOG,
                                                 "Multiattrib",
                                                 &multiattrib_info, 0);
    }
    
    return multiattrib_type;
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_class_init(MultiattribClass *klass)
  {
    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  
    gobject_class->set_property = multiattrib_set_property;
    gobject_class->get_property = multiattrib_get_property;
  
    g_object_class_install_property (
      gobject_class, PROP_TOPLEVEL,
      g_param_spec_pointer ("toplevel",
                            "",
                            "",
                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
    g_object_class_install_property (
      gobject_class, PROP_OBJECT,
      g_param_spec_pointer ("object",
                            "",
                            "",
                            G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
  	
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_init(Multiattrib *multiattrib)
  {
    GtkWidget *frame, *label, *scrolled_win, *treeview;
    GtkWidget *table, *textview, *combo, *optionm, *button;
    GtkTreeModel *store;
    GtkCellRenderer *renderer;
    GtkTreeViewColumn *column;
    GtkTreeSelection *selection;
    
    /* dialog initialization */
    g_object_set (G_OBJECT (multiattrib),
                  /* GtkContainer */
                  "border-width",    0,
                  /* GtkWindow */
                  "type",            GTK_WINDOW_TOPLEVEL,
                  "title",           _("Edit Attributes"),
                  "default-width",   320,
                  "default-height",  350,
                  "modal",           TRUE,
                  "window-position", GTK_WIN_POS_MOUSE,
                  "allow-grow",      TRUE,
                  "allow-shrink",    FALSE,
                  /* GtkDialog */
                  "has-separator",   TRUE,
                  NULL);
  
    multiattrib->toplevel = NULL;
    multiattrib->object   = NULL;
  
    /* connect to the key-press-event of dialog */
    g_signal_connect (multiattrib,
                      "key-press-event",
                      G_CALLBACK (multiattrib_callback_dialog_key_pressed),
                      multiattrib);
    
    /* create the attribute list frame */
    frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
  				    /* GtkFrame */
  				    "label", _("Attributes"),
  				    NULL));
    /*   - create the model for the treeview */
    store = (GtkTreeModel*)gtk_list_store_new (NUM_COLUMNS,
  					     G_TYPE_POINTER); /* attribute */
    /*   - create a scrolled window for the treeview */
    scrolled_win = GTK_WIDGET (
  			     g_object_new (GTK_TYPE_SCROLLED_WINDOW,
  					   /* GtkContainer */
  					   "border-width",      3,
  					   /* GtkScrolledWindow */
  					   "hscrollbar-policy",
  					   GTK_POLICY_AUTOMATIC,
  					   "vscrollbar-policy",
  					   GTK_POLICY_AUTOMATIC,
  					   "shadow-type",
  					   GTK_SHADOW_ETCHED_IN,
  					   NULL));
    /*   - create the treeview */
    treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
  				       /* GtkTreeView */
  				       "model",      store,
  				       "rules-hint", TRUE,
  				       NULL));
    g_signal_connect (treeview,
  		    "key-press-event",
  		    G_CALLBACK (multiattrib_callback_key_pressed),
  		    multiattrib);
    g_signal_connect (treeview,
  		    "button-press-event",
  		    G_CALLBACK (multiattrib_callback_button_pressed),
  		    multiattrib);
    g_signal_connect (treeview,
  		    "popup-menu",
  		    G_CALLBACK (multiattrib_callback_popup_menu),
  		    multiattrib);
    selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
    gtk_tree_selection_set_mode (selection,
  			       GTK_SELECTION_SINGLE);
  
    /*   - and now the columns of the treeview */
    /*       - column 1: attribute name */
    renderer = GTK_CELL_RENDERER (
  				g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
  					      /* GtkCellRendererText */
  					      "editable",  TRUE,
  					      /* unknown in GTK 2.4 */
  					      /* "ellipsize",
  					       * PANGO_ELLIPSIZE_END, */
  					      NULL));
    g_signal_connect (renderer,
  		    "edited",
  		    G_CALLBACK (multiattrib_callback_edited_name),
  		    multiattrib);
    column = GTK_TREE_VIEW_COLUMN (
  				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
  					       /* GtkTreeViewColumn */
  					       "title", _("Name"),
  					       "min-width", 100,
  					       "resizable", TRUE,
  					       NULL));
    gtk_tree_view_column_pack_start (column, renderer, TRUE);
    gtk_tree_view_column_set_cell_data_func (column, renderer,
  					   multiattrib_column_set_data_name,
  					   NULL, NULL);
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
    /*       - column 2: attribute value */
    renderer = GTK_CELL_RENDERER (
  				g_object_new (TYPE_CELL_RENDERER_MULTI_LINE_TEXT,
  					      /* GtkCellRendererText */
  					      "editable",  TRUE,
  					      /* unknown in GTK 2.4 */
  					      /* "ellipsize",
  						 PANGO_ELLIPSIZE_END, */
  					      NULL));
    g_signal_connect (renderer,
  		    "edited",
  		    G_CALLBACK (multiattrib_callback_edited_value),
  		    multiattrib);
    column = GTK_TREE_VIEW_COLUMN (
  				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
  					       /* GtkTreeViewColumn */
  					       "title", _("Value"),
  					       "min-width", 140,
  					       "resizable", TRUE,
  					       NULL));
    gtk_tree_view_column_pack_start (column, renderer, TRUE);
    gtk_tree_view_column_set_cell_data_func (column, renderer,
  					   multiattrib_column_set_data_value,
  					   NULL, NULL);
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
    /*       - column 3: visibility */
    renderer = GTK_CELL_RENDERER (
  				g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
  					      /* GtkCellRendererToggle */
  					      "activatable", TRUE,
  					      NULL));
    g_signal_connect (renderer,
  		    "toggled",
  		    G_CALLBACK (multiattrib_callback_toggled_visible),
  		    multiattrib);
    column = GTK_TREE_VIEW_COLUMN (
  				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
  					       /* GtkTreeViewColumn */
  					       "title", _("Vis?"),
  					       NULL));
    gtk_tree_view_column_pack_start (column, renderer, TRUE);
    gtk_tree_view_column_set_cell_data_func (column, renderer,
  					   multiattrib_column_set_data_visible,
  					   NULL, NULL);
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
    /*       - column 4: show name */
    renderer = GTK_CELL_RENDERER (
  				g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
  					      /* GtkCellRendererToggle */
  					      "activatable", TRUE,
  					      NULL));
    g_signal_connect (renderer,
  		    "toggled",
  		    G_CALLBACK (multiattrib_callback_toggled_show_name),
  		    multiattrib);
    column = GTK_TREE_VIEW_COLUMN (
  				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
  					       /* GtkTreeViewColumn */
  					       "title", _("N"),
  					       NULL));
    gtk_tree_view_column_pack_start (column, renderer, TRUE);
    gtk_tree_view_column_set_cell_data_func (column, renderer,
  					   multiattrib_column_set_data_show_name,
  					   NULL, NULL);
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
    /*       - column 5: show value */
    renderer = GTK_CELL_RENDERER (
  				g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
  					      /* GtkCellRendererToggle */
  					      "activatable", TRUE,
  					      NULL));
    g_signal_connect (renderer,
  		    "toggled",
  		    G_CALLBACK (multiattrib_callback_toggled_show_value),
  		    multiattrib);
    column = GTK_TREE_VIEW_COLUMN (
  				 g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
  					       /* GtkTreeViewColumn */
  					       "title", _("V"),
  					       NULL));
    gtk_tree_view_column_pack_start (column, renderer, TRUE);
    gtk_tree_view_column_set_cell_data_func (column, renderer,
  					   multiattrib_column_set_data_show_value,
  					   NULL, NULL);
    gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
    
    /* add the treeview to the scrolled window */
    gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
    /* set treeview of multiattrib */
    multiattrib->treeview = GTK_TREE_VIEW (treeview);
    /* add the scrolled window to frame */
    gtk_container_add (GTK_CONTAINER (frame), scrolled_win);
    /* pack the frame */
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib)->vbox), frame,
  		      TRUE, TRUE, 1);
    gtk_widget_show_all (frame);
    
    /* create the add/edit frame */
    frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
  				    "label", _("Add Attribute"),
  				    NULL));
    table = GTK_WIDGET (g_object_new (GTK_TYPE_TABLE,
  				    /* GtkTable */
  				    "n-rows",      4,
  				    "n-columns",   2,
  				    "homogeneous", FALSE,
  				    NULL));
    
    /*   - the name entry: a GtkComboBoxEntry */
    label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
  				    /* GtkMisc */
  				    "xalign", 0.0,
  				    "yalign", 0.5,
  				    /* GtkLabel */
  				    "label",  _("Name:"),
  				    NULL));
    combo = GTK_WIDGET (g_object_new (GTK_TYPE_COMBO,
  				    /* GtkCombo */
  				    "value-in-list", FALSE,
  				    NULL));
    multiattrib_init_attrib_names (GTK_COMBO (combo));
    multiattrib->combo_name = GTK_COMBO (combo);
    gtk_table_attach (GTK_TABLE (table), label,
  		    0, 1, 0, 1, 0, 0, 0, 0);
    gtk_table_attach (GTK_TABLE (table), combo,
  		    1, 2, 0, 1, GTK_EXPAND | GTK_FILL, 0, 6, 3);
    
    /*   - the value entry: a GtkEntry */
    label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
  				    /* GtkMisc */
  				    "xalign", 0.0,
  				    "yalign", 0.5,
  				    /* GtkLabel */
  				    "label",  _("Value:"),
  				    NULL));
    scrolled_win = GTK_WIDGET (
  			     g_object_new (GTK_TYPE_SCROLLED_WINDOW,
  					   /* GtkScrolledWindow */
  					   "hscrollbar-policy",
  					   GTK_POLICY_NEVER,
  					   "vscrollbar-policy",
  					   GTK_POLICY_AUTOMATIC,
  					   "shadow-type",
  					   GTK_SHADOW_IN,
  					   NULL));
    textview = GTK_WIDGET (g_object_new (GTK_TYPE_TEXT_VIEW,
  				       NULL));
    g_signal_connect (textview,
  		    "key_press_event",
  		    G_CALLBACK (multiattrib_callback_value_key_pressed),
  		    multiattrib);
    gtk_container_add (GTK_CONTAINER (scrolled_win), textview);
    multiattrib->textview_value = GTK_TEXT_VIEW (textview);
    gtk_table_attach (GTK_TABLE (table), label,
  		    0, 1, 1, 2, 0, 0, 0, 0);
    gtk_table_attach (GTK_TABLE (table), scrolled_win,
  		    1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 6, 3);
    
    /*   - the visible status */
    button = GTK_WIDGET (g_object_new (GTK_TYPE_CHECK_BUTTON,
  				     /* GtkButton */
  				     "label", _("Visible"),
  				     "active", TRUE,
  				     NULL));
    multiattrib->button_visible = GTK_CHECK_BUTTON (button);
    gtk_table_attach (GTK_TABLE (table), button,
  		    0, 1, 2, 3, GTK_FILL, 0, 3, 0);
    
    /*   - the visibility type */
    optionm = GTK_WIDGET (g_object_new (GTK_TYPE_OPTION_MENU,
  				      NULL));
    multiattrib_init_visible_types (GTK_OPTION_MENU (optionm));
    multiattrib->optionmenu_shownv = GTK_OPTION_MENU (optionm);
    gtk_table_attach (GTK_TABLE (table), optionm,
  		    1, 2, 2, 3, GTK_EXPAND | GTK_FILL, 0, 6, 3);
    gtk_widget_show_all (table);
    
    /* create the add button */
    button = gtk_button_new_from_stock (GTK_STOCK_ADD);
    g_signal_connect (button,
  		    "clicked",
  		    G_CALLBACK (multiattrib_callback_button_add),
  		    multiattrib);
    gtk_table_attach (GTK_TABLE (table), button,
  		    2, 3, 0, 3, 0, 0, 6, 3);
    
    /* add the table to the frame */
    gtk_container_add (GTK_CONTAINER (frame), table);
    /* pack the frame in the dialog */
    gtk_box_pack_start (GTK_BOX (GTK_DIALOG (multiattrib)->vbox), frame,
  		      FALSE, TRUE, 4);
    gtk_widget_show_all (frame);
    
    
    /* now add the close button to the action area */
    gtk_dialog_add_button (GTK_DIALOG (multiattrib),
                           GTK_STOCK_CLOSE,   MULTIATTRIB_RESPONSE_CLOSE);
    
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_set_property (GObject *object,
  				      guint property_id,
  				      const GValue *value,
  				      GParamSpec *pspec)
  {
    Multiattrib *multiattrib = MULTIATTRIB (object);
  
    switch(property_id) {
        case PROP_TOPLEVEL:
          multiattrib->toplevel = (TOPLEVEL*)g_value_get_pointer (value);
          break;
        case PROP_OBJECT:
          multiattrib->object = (OBJECT*)g_value_get_pointer (value);
          multiattrib_update (multiattrib);
          break;
        default:
          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
  
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  static void multiattrib_get_property (GObject *object,
  				      guint property_id,
  				      GValue *value,
  				      GParamSpec *pspec)
  {
    Multiattrib *multiattrib = MULTIATTRIB (object);
  
    switch(property_id) {
        case PROP_TOPLEVEL:
          g_value_set_pointer (value, (gpointer)multiattrib->toplevel);
          break;
        case PROP_OBJECT:
          g_value_set_pointer (value, (gpointer)multiattrib->object);
          break;
        default:
          G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
    }
  
  }
  
  /*! \todo Finish function documentation
   *  \brief
   *  \par Function Description
   *
   */
  void multiattrib_update (Multiattrib *multiattrib)
  {
    GtkListStore *liststore;
    GtkTreeIter iter;
    OBJECT **object_attribs, *o_current;
    gint i;
    
    if (multiattrib->toplevel == NULL ||
        multiattrib->object   == NULL) {
      /* we can not do anything until both toplevel and object are set */
      return;
    }
  
    liststore = (GtkListStore*)gtk_tree_view_get_model (multiattrib->treeview);
  
    /* clear the list of attributes */
    gtk_list_store_clear (liststore);
   
    /* get list of attributes */
    object_attribs = o_attrib_return_attribs (
      multiattrib->toplevel->page_current->object_head,
      multiattrib->object);
    /* populate the store with attributes */
    if (object_attribs) {
      for (i = 0, o_current = object_attribs[i];
           o_current != NULL;
           i++, o_current = object_attribs[i]) {
        gtk_list_store_append (liststore, &iter);
        gtk_list_store_set (liststore, &iter,
                            COLUMN_ATTRIBUTE, o_current,
                            -1);
      }
    }
    /* delete the list of attribute objects */
    o_attrib_free_returned (object_attribs);
    
  }
  
  
  
  1.13      +609 -350  eda/geda/gaf/gschem/src/x_pagesel.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_pagesel.c
  ===================================================================
  RCS file: x_pagesel.c
  diff -N x_pagesel.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_pagesel.c	14 Jul 2006 02:23:55 -0000	1.13
  @@ -0,0 +1,685 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +#include "../include/x_pagesel.h"
  +
  +
  +static void x_pagesel_callback_response (GtkDialog *dialog,
  +                                         gint arg1,
  +                                         gpointer user_data);
  +
  +
  +
  +/*! \brief Open the page manager dialog.
  + *  \par Function Description
  + *  Opens the page manager dialog for <B>toplevel</B> if it is not already.
  + *  In this last case, it raises the dialog.
  + *
  + *  \param [in] toplevel  The TOPLEVEL object to open page manager for.
  + */
  +void x_pagesel_open (TOPLEVEL *toplevel)
  +{
  +  if (toplevel->pswindow == NULL) {
  +    toplevel->pswindow = GTK_WIDGET (g_object_new (TYPE_PAGESEL,
  +                                                   "toplevel", toplevel,
  +                                                   NULL));
  +
  +    g_signal_connect (toplevel->pswindow,
  +                      "response",
  +                      G_CALLBACK (x_pagesel_callback_response),
  +                      toplevel);
  +    
  +    gtk_widget_show (toplevel->pswindow);
  +  } else {
  +    gdk_window_raise (toplevel->pswindow->window);
  +  }
  +
  +}
  +
  +/*! \brief Close the page manager dialog.
  + *  \par Function Description
  + *  Closes the page manager dialog associated with <B>toplevel</B>.
  + *
  + *  \param [in] toplevel  The TOPLEVEL object to close page manager for.
  + */
  +void x_pagesel_close (TOPLEVEL *toplevel)
  +{
  +  if (toplevel->pswindow) {
  +    g_assert (IS_PAGESEL (toplevel->pswindow));
  +    gtk_widget_destroy (toplevel->pswindow);
  +    toplevel->pswindow = NULL;
  +  }
  +  
  +}
  +
  +/*! \brief Update the list and status of <B>toplevel</B>'s pages.
  + *  \par Function Description
  + *  Updates the list and status of <B>toplevel</B>\'s pages if the page
  + *  manager dialog is opened.
  + *
  + *  \param [in] toplevel  The TOPLEVEL object to update.
  + */
  +void x_pagesel_update (TOPLEVEL *toplevel)
  +{
  +  if (toplevel->pswindow) {
  +    g_assert (IS_PAGESEL (toplevel->pswindow));
  +    pagesel_update (PAGESEL (toplevel->pswindow));
  +  }
  +  
  +}
  +
  +/*! \brief Callback for page manager response.
  + *  \par Function Description
  + *  Handles response <B>arg1</B> of the page manager dialog <B>dialog</B>.
  + *
  + *  \param [in] dialog     GtkDialog that issues callback.
  + *  \param [in] arg1       Response argument of page manager dialog.
  + *  \param [in] user_data  Pointer to relevant TOPLEVEL structure.
  + */
  +static void x_pagesel_callback_response (GtkDialog *dialog,
  +					 gint arg1,
  +					 gpointer user_data)
  +{
  +  TOPLEVEL *toplevel = (TOPLEVEL*)user_data;
  +
  +  switch (arg1) {
  +      case PAGESEL_RESPONSE_UPDATE:
  +        pagesel_update (PAGESEL (dialog));
  +        break;
  +      case GTK_RESPONSE_DELETE_EVENT:
  +      case PAGESEL_RESPONSE_CLOSE:
  +        g_assert (GTK_WIDGET (dialog) == toplevel->pswindow);
  +        gtk_widget_destroy (GTK_WIDGET (dialog));
  +        toplevel->pswindow = NULL;
  +        break;
  +      default:
  +        g_assert_not_reached ();
  +  }
  +  
  +}
  +
  +enum {
  +  PROP_TOPLEVEL=1,
  +};
  +
  +enum {
  +  COLUMN_PAGE,
  +  COLUMN_NAME,
  +  COLUMN_CHANGED,
  +  NUM_COLUMNS
  +};
  +
  +
  +static void pagesel_class_init (PageselClass *class);
  +static void pagesel_init       (Pagesel *pagesel);
  +static void pagesel_set_property (GObject *object,
  +                                  guint property_id,
  +                                  const GValue *value,
  +                                  GParamSpec *pspec);
  +static void pagesel_get_property (GObject *object,
  +                                  guint property_id,
  +                                  GValue *value,
  +                                  GParamSpec *pspec);
  +
  +static void pagesel_popup_menu (Pagesel *pagesel,
  +                                GdkEventButton *event);
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void pagesel_callback_selection_changed (GtkTreeSelection *selection,
  +						gpointer user_data)
  +{
  +  GtkTreeModel *model;
  +  GtkTreeIter iter;
  +  Pagesel *pagesel = (Pagesel*)user_data;
  +  TOPLEVEL *toplevel;
  +  PAGE *page;
  +
  +  if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
  +    return;
  +  }
  +
  +  toplevel = pagesel->toplevel;
  +  gtk_tree_model_get (model, &iter,
  +                      COLUMN_PAGE, &page,
  +                      -1);
  +
  +  /* temp */
  +  s_page_goto (toplevel, page);
  +  i_set_filename (toplevel, toplevel->page_current->page_filename);
  +  x_scrollbars_update (toplevel);
  +  o_redraw_all (toplevel);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static gboolean pagesel_callback_button_pressed (GtkWidget *widget,
  +						 GdkEventButton *event,
  +						 gpointer user_data)
  +{
  +  Pagesel *pagesel = (Pagesel*)user_data;
  +  gboolean ret = FALSE;
  +
  +  if (event->type == GDK_BUTTON_PRESS  &&  event->button == 3) {
  +    pagesel_popup_menu (pagesel, event);
  +    ret = TRUE;
  +  }
  +
  +  return ret;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static gboolean pagesel_callback_popup_menu (GtkWidget *widget,
  +					     gpointer user_data)
  +{
  +  Pagesel *pagesel = (Pagesel*)user_data;
  +
  +  pagesel_popup_menu (pagesel, NULL);
  +  
  +  return TRUE;
  +}
  +
  +#define DEFINE_POPUP_CALLBACK(name, action)                       \
  +static void                                                       \
  +pagesel_callback_popup_ ## name (GtkMenuItem *menuitem,           \
  +                                 gpointer user_data)              \
  +{                                                                 \
  +  i_callback_ ## action (PAGESEL (user_data)->toplevel, 0, NULL); \
  +}
  +
  +DEFINE_POPUP_CALLBACK (new_page,     file_new);
  +DEFINE_POPUP_CALLBACK (open_page,    file_open);
  +DEFINE_POPUP_CALLBACK (save_page,    file_save);
  +DEFINE_POPUP_CALLBACK (close_page,   page_close);
  +DEFINE_POPUP_CALLBACK (discard_page, page_discard);
  +
  +
  +/*! \brief Popup context-sensitive menu.
  + *  \par Function Description
  + *  Pops up a context-sensitive menu.
  + *
  + *  <B>event</B> can be NULL if the popup is triggered by a key binding
  + *  instead of a mouse click.
  + *
  + *  \param [in] pagesel  The Pagesel object.
  + *  \param [in] event    Mouse click event info.
  + */
  +static void pagesel_popup_menu (Pagesel *pagesel,
  +				GdkEventButton *event)
  +{
  +  GtkTreePath *path;
  +  GtkWidget *menu;
  +  struct menuitem_t {
  +    gchar *label;
  +    void (*callback)(void);
  +  };
  +  struct menuitem_t menuitems[] = {
  +    { N_("New Page"),     G_CALLBACK (pagesel_callback_popup_new_page)     },
  +    { N_("Open Page..."), G_CALLBACK (pagesel_callback_popup_open_page)    },
  +    { "-",                NULL                                             },
  +    { N_("Save Page"),    G_CALLBACK (pagesel_callback_popup_save_page)    },
  +    { N_("Close Page"),   G_CALLBACK (pagesel_callback_popup_close_page)   },
  +    { N_("Discard Page"), G_CALLBACK (pagesel_callback_popup_discard_page) },
  +    { NULL,               NULL                                             } };
  +  struct menuitem_t *tmp;
  +  
  +  if (event != NULL &&
  +      gtk_tree_view_get_path_at_pos (pagesel->treeview,
  +                                     (gint)event->x, 
  +                                     (gint)event->y,
  +                                     &path, NULL, NULL, NULL)) {
  +    GtkTreeSelection *selection;
  +    selection = gtk_tree_view_get_selection (pagesel->treeview);
  +    gtk_tree_selection_unselect_all (selection);
  +    gtk_tree_selection_select_path (selection, path);
  +    gtk_tree_path_free (path);
  +  }
  +
  +  /* create the context menu */
  +  menu = gtk_menu_new();
  +  for (tmp = menuitems; tmp->label != NULL; tmp++) {
  +    GtkWidget *menuitem;
  +    if (g_strcasecmp (tmp->label, "-") == 0) {
  +      menuitem = gtk_separator_menu_item_new ();
  +    } else {
  +      menuitem = gtk_menu_item_new_with_label (_(tmp->label));
  +      g_signal_connect (menuitem,
  +                        "activate",
  +                        tmp->callback,
  +                        pagesel);
  +    }
  +    gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
  +  }
  +  gtk_widget_show_all (menu);
  +  /* make menu a popup menu */
  +  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
  +                  (event != NULL) ? event->button : 0,
  +                  gdk_event_get_time ((GdkEvent*)event));
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +GType pagesel_get_type()
  +{
  +  static GType pagesel_type = 0;
  +  
  +  if (!pagesel_type) {
  +    static const GTypeInfo pagesel_info = {
  +      sizeof(PageselClass),
  +      NULL, /* base_init */
  +      NULL, /* base_finalize */
  +      (GClassInitFunc) pagesel_class_init,
  +      NULL, /* class_finalize */
  +      NULL, /* class_data */
  +      sizeof(Pagesel),
  +      0,    /* n_preallocs */
  +      (GInstanceInitFunc) pagesel_init,
  +    };
  +		
  +    pagesel_type = g_type_register_static (GTK_TYPE_DIALOG,
  +                                           "Pagesel",
  +                                           &pagesel_info, 0);
  +  }
  +  
  +  return pagesel_type;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void pagesel_class_init (PageselClass *klass)
  +{
  +  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  +
  +  gobject_class->set_property = pagesel_set_property;
  +  gobject_class->get_property = pagesel_get_property;
  +
  +  g_object_class_install_property (
  +    gobject_class, PROP_TOPLEVEL,
  +    g_param_spec_pointer ("toplevel",
  +                          "",
  +                          "",
  +                          G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
  +	
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void pagesel_init (Pagesel *pagesel)
  +{
  +  GtkWidget *scrolled_win, *treeview, *label;
  +  GtkTreeModel *store;
  +  GtkCellRenderer *renderer;
  +  GtkTreeViewColumn *column;
  +  GtkTreeSelection *selection;
  +
  +  /* dialog initialization */
  +  g_object_set (G_OBJECT (pagesel),
  +                /* GtkContainer */
  +                "border-width",    0,
  +                /* GtkWindow */
  +                "type",            GTK_WINDOW_TOPLEVEL,
  +                "title",           _("Page Manager"),
  +                "default-height",  180,
  +                "default-width",   515,
  +                "modal",           FALSE,
  +                "window-position", GTK_WIN_POS_NONE,
  +                "type-hint",       GDK_WINDOW_TYPE_HINT_NORMAL,
  +                /* GtkDialog */
  +                "has-separator",   TRUE,
  +                NULL);
  +
  +  /* create the model for the treeview */
  +  store = (GtkTreeModel*)gtk_tree_store_new (NUM_COLUMNS,
  +                                             G_TYPE_POINTER,  /* page */
  +                                             G_TYPE_STRING,   /* name */
  +                                             G_TYPE_BOOLEAN); /* changed */
  +
  +  /* create a scrolled window for the treeview */
  +  scrolled_win = GTK_WIDGET (
  +    g_object_new (GTK_TYPE_SCROLLED_WINDOW,
  +                  /* GtkContainer */
  +                  "border-width",      5,
  +                  /* GtkScrolledWindow */
  +                  "hscrollbar-policy", GTK_POLICY_AUTOMATIC,
  +                  "vscrollbar-policy", GTK_POLICY_ALWAYS,
  +                  "shadow-type",       GTK_SHADOW_ETCHED_IN,
  +                  NULL));
  +  /* create the treeview */
  +  treeview = GTK_WIDGET (g_object_new (GTK_TYPE_TREE_VIEW,
  +                                       /* GtkTreeView */
  +                                       "model",      store,
  +                                       "rules-hint", TRUE,
  +                                       NULL));
  +  g_signal_connect (treeview,
  +                    "button-press-event",
  +                    G_CALLBACK (pagesel_callback_button_pressed),
  +                    pagesel);
  +  g_signal_connect (treeview,
  +                    "popup-menu",
  +                    G_CALLBACK (pagesel_callback_popup_menu),
  +                    pagesel);
  +  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
  +  gtk_tree_selection_set_mode (selection,
  +                               GTK_SELECTION_SINGLE);
  +  g_signal_connect (selection,
  +                    "changed",
  +                    G_CALLBACK (pagesel_callback_selection_changed),
  +                    pagesel); 
  +  /*   - first column: page name */
  +  renderer = GTK_CELL_RENDERER (
  +    g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
  +                  /* GtkCellRendererText */
  +                  "editable", FALSE,
  +                  NULL));
  +  column = GTK_TREE_VIEW_COLUMN (
  +    g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
  +                  /* GtkTreeViewColumn */
  +                  "title", _("Filename"),
  +                  "min-width", 400,
  +                  "resizable", TRUE,
  +                  NULL));
  +  gtk_tree_view_column_pack_start (column, renderer, TRUE);
  +  gtk_tree_view_column_add_attribute (column, renderer, "text", COLUMN_NAME);
  +  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
  +  /*   - second column: changed */
  +  renderer = GTK_CELL_RENDERER (
  +    g_object_new (GTK_TYPE_CELL_RENDERER_TOGGLE,
  +                  /* GtkCellRendererToggle */
  +                  "activatable", FALSE,
  +                  NULL));
  +  column = GTK_TREE_VIEW_COLUMN (
  +    g_object_new (GTK_TYPE_TREE_VIEW_COLUMN,
  +                  /* GtkTreeViewColumn */
  +                  "title", _("Changed"),
  +                  "sizing", GTK_TREE_VIEW_COLUMN_FIXED,
  +                  NULL));
  +  gtk_tree_view_column_pack_start (column, renderer, TRUE);
  +  gtk_tree_view_column_add_attribute (column, renderer, "active", COLUMN_CHANGED);
  +  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
  +      
  +  /* add the treeview to the scrolled window */
  +  gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
  +  /* set treeview of pagesel */
  +  pagesel->treeview = GTK_TREE_VIEW (treeview);
  +
  +  /* add the scrolled window to the dialog vbox */
  +  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (pagesel)->vbox), scrolled_win,
  +                      TRUE, TRUE, 0);
  +  gtk_widget_show_all (scrolled_win);
  +
  +  /* add a label below the scrolled window */
  +  label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
  +                                    /* GtkLabel */
  +                                    "label", _("Right click on the filename for more options..."),
  +                                    NULL));
  +  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (pagesel)->vbox), label,
  +                      FALSE, TRUE, 5);
  +  gtk_widget_show (label);
  +
  +  /* now add buttons in the action area */
  +  gtk_dialog_add_buttons (GTK_DIALOG (pagesel),
  +                          /*  - update button */
  +                          GTK_STOCK_REFRESH, PAGESEL_RESPONSE_UPDATE,
  +                          /*  - close button */
  +                          GTK_STOCK_CLOSE,   PAGESEL_RESPONSE_CLOSE,
  +                          NULL);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void pagesel_set_property (GObject *object,
  +				  guint property_id,
  +				  const GValue *value,
  +				  GParamSpec *pspec)
  +{
  +  Pagesel *pagesel = PAGESEL (object);
  +
  +  switch(property_id) {
  +      case PROP_TOPLEVEL:
  +        pagesel->toplevel = (TOPLEVEL*)g_value_get_pointer (value);
  +        pagesel_update (pagesel);
  +        break;
  +      default:
  +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static void pagesel_get_property (GObject *object,
  +				  guint property_id,
  +				  GValue *value,
  +				  GParamSpec *pspec)
  +{
  +  Pagesel *pagesel = PAGESEL (object);
  +
  +  switch(property_id) {
  +      case PROP_TOPLEVEL:
  +        g_value_set_pointer (value, (gpointer)pagesel->toplevel);
  +        break;
  +      default:
  +        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
  +  }
  +
  +}
  +
  +/*! \brief Update tree model of <B>pagesel</B>'s treeview.
  + *  \par Function Description
  + *  Updates the tree model of <B>pagesel</B>\'s treeview.
  + *
  + *  Right now, each time it is called, it rebuilds all the model from the
  + *  list of page in the toplevel.
  + *  It is a recursive function to populate the tree store
  + *
  + *  \param [in] model   GtkTreeModel to update.
  + *  \param [in] parent  GtkTreeIter pointer to tree root.
  + *  \param [in] page    The PAGE object to update tree model from.
  + */
  +static void add_page (GtkTreeModel *model, GtkTreeIter *parent,
  +		      PAGE *page)
  +{
  +  GtkTreeIter iter;
  +  PAGE *p_current;
  +
  +  /* add the page to the store */
  +  gtk_tree_store_append (GTK_TREE_STORE (model),
  +                         &iter,
  +                         parent);
  +  gtk_tree_store_set (GTK_TREE_STORE (model),
  +                      &iter,
  +                      COLUMN_PAGE, page,
  +                      COLUMN_NAME, page->page_filename,
  +                      COLUMN_CHANGED, page->CHANGED,
  +                      -1);
  +  
  +  /* search a page that has a up field == p_current->pid */
  +  for (p_current = page->next;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    if (p_current->up == page->pid) {
  +      add_page (model, &iter, p_current);
  +    }
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *  Recursive function to select the current page in the treeview
  + *
  + */
  +static void select_page(GtkTreeView *treeview,
  +			GtkTreeIter *parent, PAGE *page)
  +{
  +  GtkTreeModel *treemodel = gtk_tree_view_get_model (treeview);
  +  GtkTreeIter iter;
  +  PAGE *p_current;
  +
  +  if (!gtk_tree_model_iter_children (treemodel, &iter, parent)) {
  +    return;
  +  }
  +
  +  do {
  +    gtk_tree_model_get (treemodel, &iter,
  +                        COLUMN_PAGE, &p_current,
  +                        -1);
  +    if (p_current == page) {
  +      gtk_tree_view_expand_all (treeview);
  +      gtk_tree_selection_select_iter (
  +        gtk_tree_view_get_selection (treeview),
  +        &iter);
  +      return;
  +    }
  +
  +    select_page (treeview, &iter, page);
  +    
  +  } while (gtk_tree_model_iter_next (treemodel, &iter));
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void pagesel_update (Pagesel *pagesel)
  +{
  +  GtkTreeModel *model;
  +  TOPLEVEL *toplevel;
  +  PAGE *p_current;
  +
  +  g_assert (IS_PAGESEL (pagesel));
  +
  +  g_return_if_fail (pagesel->toplevel);
  +
  +  toplevel = pagesel->toplevel;
  +  model    = gtk_tree_view_get_model (pagesel->treeview);
  +
  +  /* wipe out every thing in the store */
  +  gtk_tree_store_clear (GTK_TREE_STORE (model));
  +  /* now rebuild */
  +  for (p_current = toplevel->page_head->next;
  +       p_current != NULL;
  +       p_current = p_current->next) {
  +    /* find every page that is not a hierarchy-down of another page */
  +    if (p_current->up < 0 ||
  +        s_hierarchy_find_page (toplevel->page_head->next,
  +                               p_current->up) == NULL) {
  +      add_page (model, NULL, p_current);
  +    }
  +  }
  +
  +  /* select the current page in the treeview */
  +  select_page (pagesel->treeview, NULL, toplevel->page_current);  
  +}
  +
  +/*! \deprecated
  + *  This function was in the noweb file, but was not referenced.
  + *  Create a gtk button with a custom label <B>text</B> and a stock
  + *  icon <B>stock</B>.
  + *  <B>text</B>: The mnemonic text for the label.
  + *  <B>stock</B>: The name of the stock item to get the icon from.
  + *
  + *  Return value: The widget.
  + *  Taken from evolution code:
  + *  http://lists.ximian.com/archives/public/evolution-patches/2003-April/000088.html
  + */
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +/*
  +GtkWidget *e_gtk_button_new_with_icon(const char *text, const char *stock)
  +{
  +	GtkWidget *button, *label;
  +	GtkStockItem item;
  +
  +	button = gtk_button_new();
  +	label = gtk_label_new_with_mnemonic(text);
  +	gtk_label_set_mnemonic_widget((GtkLabel *)label, button);
  +
  +	if (gtk_stock_lookup(stock, &item)) {
  +		GtkWidget *image, *hbox, *align;
  +
  +		image = gtk_image_new_from_stock(stock, GTK_ICON_SIZE_BUTTON);
  +		hbox = gtk_hbox_new(FALSE, 2);
  +		align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
  +		gtk_box_pack_start((GtkBox *)hbox, image, FALSE, FALSE, 0);
  +		gtk_box_pack_end((GtkBox *)hbox, label, FALSE, FALSE, 0);
  +		gtk_container_add((GtkContainer *)align, hbox);
  +		gtk_container_add((GtkContainer *)button, align);
  +		gtk_widget_show_all(align);
  +	} else {
  +		gtk_misc_set_alignment((GtkMisc *)label, 0.5, 0.5);
  +		gtk_container_add((GtkContainer *)button, label);
  +		gtk_widget_show(label);
  +	}
  +
  +	return button;
  +}
  +*/
  
  
  
  1.11      +282 -233  eda/geda/gaf/gschem/src/x_preview.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_preview.c
  ===================================================================
  RCS file: x_preview.c
  diff -N x_preview.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_preview.c	14 Jul 2006 02:23:55 -0000	1.11
  @@ -0,0 +1,385 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +#ifdef HAVE_UNISTD_H
  +#include <unistd.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +extern int mouse_x, mouse_y;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_preview_update(TOPLEVEL *preview,
  +		      const gchar *directory, const gchar *filename) 
  +{
  +  gchar *cwd, *temp;
  +  PAGE *page;
  +
  +  /* Since f_open now changes the directory, we need to 
  +   * use this to reset the cwd at end of fcn */
  +  cwd = g_get_current_dir ();
  +
  +#ifdef __MINGW32__
  +  if (u_basic_has_trailing (directory, G_DIR_SEPARATOR)) {
  +     temp = g_strconcat (directory, filename, NULL);
  +  } else {
  +#endif
  +     temp = g_strconcat (directory, G_DIR_SEPARATOR_S, filename, NULL);
  +#ifdef __MINGW32__
  +  }
  +#endif
  +  s_page_delete (preview, preview->page_current);
  +
  +  page = s_page_new (preview, temp);
  +  s_page_goto (preview, page);
  +
  +  /* open up file for preview */
  +  f_open (preview, temp);
  +
  +  a_zoom_extents (preview,
  +                  page->object_head,
  +                  A_PAN_DONT_REDRAW);
  +
  +  o_redraw_all (preview);
  +
  +  chdir (cwd); /* Go back to original directory */
  +  g_free (cwd);
  +  g_free (temp);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_preview_update_gtk24 (GtkFileChooser *file_chooser, gpointer data)
  +{
  +#if ((GTK_MAJOR_VERSION > 2) || \
  +     ((GTK_MAJOR_VERSION == 2) && (GTK_MINOR_VERSION >= 4)) )
  +  FILEDIALOG *f_current;
  +  char *filename = NULL;
  +  GdkPixbuf *pixbuf;
  +  gboolean have_preview=FALSE;
  +
  +  f_current =  (FILEDIALOG *) data;
  +  printf("x_preview_update_gtk24: Getting filename.\n");
  +  filename = gtk_file_chooser_get_preview_filename (file_chooser);
  +  printf("x_preview_update_gtk24: Filename: %s.\n", filename);
  +
  +  /* If no file is selected, then don't set the preview and exit */
  +  if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
  +    gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
  +    return;
  +  }
  +
  +  /* open up file for preview */
  +  f_open (f_current->preview, filename);
  +
  +  pixbuf = x_image_get_pixbuf (f_current->preview);
  +  have_preview = (pixbuf != NULL);
  +  if (pixbuf != NULL) {
  +    printf("x_preview_update_gtk24: setting pixbuf.\n");
  +    gtk_image_set_from_pixbuf (GTK_IMAGE(gtk_file_chooser_get_preview_widget(file_chooser)),
  +			       pixbuf);
  +    if (pixbuf)
  +      gdk_pixbuf_unref (pixbuf);
  +  }
  +  else {
  +    fprintf (stderr, "x_preview_update_gtk24: Can't get pixbuf from preview struct.\n");
  +    s_log_message(
  +      _("x_preview_update_gtk24: Can't get pixbuf from preview struct.\n"));
  +  }
  +
  +  g_free (filename);
  +  
  +  gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
  +#endif
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_preview_close (TOPLEVEL *w_current)
  +{
  +  o_attrib_free_current (w_current);
  +  o_complex_free_filename (w_current);
  +
  +  if (w_current->backingstore) {
  +    gdk_pixmap_unref (w_current->backingstore);
  +  }
  +
  +  x_window_free_gc (w_current);
  +  
  +  s_toplevel_delete (w_current);  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_preview_expose(GtkWidget *widget, GdkEventExpose *event,
  +		      TOPLEVEL *w_current)
  +{
  +  exit_if_null(w_current);
  +
  +#if DEBUG
  +  printf("yeah expose: %d %d\n", event->area.width, event->area.height);
  +#endif
  +
  +  gdk_draw_pixmap(widget->window,
  +                  widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
  +                  w_current->backingstore,
  +                  event->area.x, event->area.y,
  +                  event->area.x, event->area.y,
  +                  event->area.width, event->area.height);
  +
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_preview_button_pressed(GtkWidget *widget, GdkEventButton *event,
  +			      TOPLEVEL *w_current)
  +{
  +  exit_if_null(w_current);
  +
  +  global_window_current = w_current;
  +
  +#if DEBUG
  +  printf("preview pressed\n");
  +#endif
  +
  +  if (event->button == 1) { 
  +    i_callback_view_zoom_in_hotkey(w_current, 0, NULL);
  +  } else if (event->button == 2) {
  +    i_callback_view_pan_hotkey(w_current, 0, NULL);
  +  } else if (event->button == 3) {
  +    i_callback_view_zoom_out_hotkey(w_current, 0, NULL);
  +  }
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_preview_motion(GtkWidget *widget, GdkEventMotion *event,
  +		      TOPLEVEL *w_current)
  +{
  +  mouse_x = (int) event->x;
  +  mouse_y = (int) event->y;
  +
  +#if DEBUG
  +  printf("preview motion\n");
  +#endif
  +  return(0);
  +}
  +
  +#if 0
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_preview_button_released(GtkWidget *widget, GdkEventButton *event,
  +			       TOPLEVEL *w_current)
  +{
  +  exit_if_null(w_current);
  +
  +  global_window_current = w_current;
  +  printf("preview released\n");
  +}
  +#endif
  +
  +#if 0
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_preview_key_press (GtkWidget *widget, GdkEventKey *event,
  +			  TOPLEVEL *w_current)
  +{
  +  exit_if_null(w_current);
  +  global_window_current = w_current;
  +
  +  if (event->keyval == 0) {
  +    return;
  +  }
  +
  +}
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_preview_create_drawing(GtkWidget *drawbox, TOPLEVEL *w_current)
  +{
  +  /* drawing next */
  +  w_current->drawing_area = gtk_drawing_area_new ();
  +  /* Set the size here.  Be sure that it has an aspect ratio of 1.333
  +   * We could calculate this based on root window size, but for now
  +   * lets just set it to:
  +   * Width = root_width*3/4   Height = Width/1.3333333333
  +   * 1.3333333 is the desired aspect ratio!
  +   */
  +
  +  gtk_drawing_area_size (GTK_DRAWING_AREA (w_current->drawing_area),
  +                         w_current->win_width,
  +                         w_current->win_height);
  +
  +  gtk_box_pack_start (GTK_BOX (drawbox), w_current->drawing_area,
  +                      FALSE, FALSE, 0);
  +  gtk_widget_show (w_current->drawing_area);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_preview_setup_rest (TOPLEVEL *preview)
  +{
  +  PAGE *preview_page;
  +
  +  preview->window = preview->drawing_area->window;
  +  gtk_widget_grab_focus (preview->drawing_area);
  +
  +  preview->backingstore = gdk_pixmap_new (
  +    preview->window,
  +    preview->drawing_area->allocation.width,
  +    preview->drawing_area->allocation.height, -1);
  +
  +  x_window_setup_gc (preview);
  +
  +  preview_page = s_page_new (preview, "unknown");
  +  s_page_goto (preview, preview_page);
  +
  +  i_vars_set (preview);
  +
  +  /* i_vars_set will set auto_save_interval, so disable it 
  +     We don't want to autosave previews!! */
  +  preview->auto_save_interval = 0;
  +
  +  /* be sure to turn off the grid */
  +  preview->grid = FALSE;
  +
  +  /* preview windows don't have toolbars */
  +  preview->handleboxes = FALSE; 
  +  preview->toolbars    = FALSE;
  +
  +  x_repaint_background(preview);
  +	
  +#if 0	
  +  world_get_complex_bounds(preview, 
  +                           preview_page->object_head, 
  +                           &left, &top, &right, &bottom);
  +  set_window(preview, preview->current_page, left, right, top, bottom);
  +#endif
  +
  +  preview->DONT_RECALC = 0;
  +  preview->DONT_RESIZE = 0;
  +  preview->DONT_REDRAW = 0;
  +
  +  a_zoom_extents(preview,
  +                 preview_page->object_head,
  +                 A_PAN_DONT_REDRAW);
  +
  +  o_redraw_all(preview);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +TOPLEVEL *x_preview_setup(GtkWidget *xfwindow, GtkWidget *drawbox) 
  +{
  +  struct event_reg_t {
  +    gchar *detailed_signal;
  +    void (*c_handler)(void);
  +  } drawing_area_events[] = {
  +    { "expose_event",         G_CALLBACK (x_preview_expose)          },
  +    { "button_press_event",   G_CALLBACK (x_preview_button_pressed)  },
  +#if 0
  +    { "button_release_event", G_CALLBACK (x_preview_button_released) },
  +    { "key_press_event",      G_CALLBACK (x_preview_key_press)       },
  +#endif
  +    { "motion_notify_event",  G_CALLBACK (x_preview_motion)          },
  +    { NULL,                   NULL                                   }
  +  }, *tmp;
  +  TOPLEVEL *preview_toplevel;
  +
  +  preview_toplevel = s_toplevel_new ();
  +
  +  preview_toplevel->init_left   = 0;
  +  preview_toplevel->init_top    = 0;
  +  preview_toplevel->init_right  = WIDTH_C;
  +  preview_toplevel->init_bottom = HEIGHT_C;
  +  preview_toplevel->width  = 160;
  +  preview_toplevel->height = 120;
  +  preview_toplevel->win_width  = preview_toplevel->width;
  +  preview_toplevel->win_height = preview_toplevel->height;
  +  /* be sure to turn off scrollbars */
  +  preview_toplevel->scrollbars_flag = FALSE;
  +
  +  x_preview_create_drawing (drawbox, preview_toplevel);
  +
  +  gtk_widget_set_events (preview_toplevel->drawing_area, 
  +                         GDK_EXPOSURE_MASK | 
  +                         GDK_POINTER_MOTION_MASK |
  +                         GDK_BUTTON_PRESS_MASK);
  +  for (tmp = drawing_area_events; tmp->detailed_signal != NULL; tmp++) {
  +    g_signal_connect (preview_toplevel->drawing_area,
  +                      tmp->detailed_signal,
  +                      tmp->c_handler,
  +                      preview_toplevel);
  +  }
  +  return preview_toplevel;
  +}
  
  
  
  1.19      +467 -353  eda/geda/gaf/gschem/src/x_print.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_print.c
  ===================================================================
  RCS file: x_print.c
  diff -N x_print.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_print.c	14 Jul 2006 02:23:55 -0000	1.19
  @@ -0,0 +1,545 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +static const gchar *list_item_data_key = "list_item_data";
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint print_landscape(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->print_orientation = LANDSCAPE;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint print_portrait(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  w_current->print_orientation = PORTRAIT;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_print_set_window(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  f_print_set_type(w_current, WINDOW);
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_print_set_extents(GtkWidget *w, TOPLEVEL *w_current )
  +{
  +  f_print_set_type(w_current, EXTENTS);
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_print_set_nomargins(GtkWidget *w, TOPLEVEL *w_current )
  +{
  +  f_print_set_type(w_current, EXTENTS_NOMARGINS);
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is from gtktest.c and only used in this file,
  + *  there are other create_menus...
  + */
  +static GtkWidget *create_menu_orient (TOPLEVEL *w_current)
  +{
  +  GtkWidget *menu;
  +  GtkWidget *menuitem;
  +  GSList *group;
  +  char *buf;
  +
  +  menu = gtk_menu_new ();
  +  group = NULL;
  +
  +  buf = g_strdup_printf(_("Landscape"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) print_landscape,
  +                     w_current);
  +
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf(_("Portrait"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) print_portrait,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  if (w_current->print_orientation == PORTRAIT) {
  +    gtk_menu_set_active(GTK_MENU (menu),1);
  +    print_portrait (NULL, w_current);
  +  } else {
  +    print_landscape (NULL, w_current);
  +  }
  +
  +  return menu;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is from gtktest.c and only used in this file,
  + *  there are other create_menus...
  + */
  +static GtkWidget *create_menu_type (TOPLEVEL *w_current)
  +{
  +  GtkWidget *menu;
  +  GtkWidget *menuitem;
  +  GSList *group;
  +  char *buf;
  +
  +  menu = gtk_menu_new ();
  +  group = NULL;
  +
  +  buf = g_strdup_printf(_("Extents with margins"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) x_print_set_extents,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  buf = g_strdup_printf(_("Extents no margins"));
  +  menuitem = gtk_radio_menu_item_new_with_label(group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group(GTK_RADIO_MENU_ITEM(menuitem));
  +  gtk_menu_append(GTK_MENU(menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT(menuitem), "activate",
  +                   (GtkSignalFunc) x_print_set_nomargins, w_current);
  +  gtk_widget_show(menuitem);
  +
  +  buf = g_strdup_printf(_("Current Window"));
  +  menuitem = gtk_radio_menu_item_new_with_label (group, buf);
  +  free(buf);
  +  group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  +  gtk_menu_append (GTK_MENU (menu), menuitem);
  +  gtk_signal_connect(GTK_OBJECT (menuitem), "activate",
  +                     (GtkSignalFunc) x_print_set_window,
  +                     w_current);
  +  gtk_widget_show (menuitem);
  +
  +  switch (w_current->print_output_type)
  +  {
  +    case(EXTENTS):
  +      gtk_menu_set_active(GTK_MENU (menu),0);
  +      f_print_set_type(w_current, EXTENTS);
  +      break;
  +
  +    case(EXTENTS_NOMARGINS):
  +      gtk_menu_set_active(GTK_MENU (menu),1);
  +      f_print_set_type(w_current, EXTENTS_NOMARGINS);
  +      break;
  +
  +    case(WINDOW):
  +      gtk_menu_set_active(GTK_MENU (menu),2);
  +      f_print_set_type(w_current, WINDOW);
  +      break;
  +  }
  +
  +  return menu;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_print_change_size (GtkWidget *gtklist, TOPLEVEL *w_current)
  +{
  +  GList		*dlist;
  +  GtkObject       *listitem;
  +  gchar           *item_data_string;
  +
  +  dlist = GTK_LIST(w_current->plib_list)->selection;
  +
  +  if (!dlist) {
  +    /* g_print("Selection cleared\n");*/
  +    return(0);
  +  }
  +
  +  listitem = GTK_OBJECT(dlist->data);
  +  item_data_string=gtk_object_get_data(listitem, list_item_data_key);
  +
  +#if DEBUG
  +  printf("paper_size string: %s\n", item_data_string);
  +  len = strlen(item_data_string);
  +  /* strcpy(current_attr_name, item_data_string);*/
  +#endif
  +
  +  s_papersizes_get_size(item_data_string,
  +                        &w_current->paper_width,
  +                        &w_current->paper_height);
  +
  +#if 0
  +  gtk_entry_set_text(GTK_ENTRY(w_current->asentry_name),
  +                     item_data_string);
  +  gtk_entry_select_region(GTK_ENTRY(w_current->asentry_name), 0, len);
  +#endif
  +
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +gint x_print_print(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  int status;
  +  const char *filename =
  +  gtk_entry_get_text(GTK_ENTRY(w_current->pfilename_entry));
  +
  +  if (filename[0] != '\0') {
  +
  +    /* de select everything first */
  +    o_select_run_hooks(w_current, NULL, 2); 
  +    o_selection_remove_most(w_current,
  +                            w_current->page_current->
  +                            selection2_head);
  +
  +    status = f_print(w_current, filename);
  +
  +    if (status) {
  +      s_log_message(_("Cannot print current schematic to [%s]\n"), filename);
  +    } else {
  +      s_log_message(_("Printed current schematic to [%s]\n"), filename);
  +    }
  +  }
  +
  +  gtk_widget_destroy(w_current->pwindow);
  +  w_current->pwindow = NULL;
  +  return(0);
  +}
  +
  +gint x_print_cancel(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +#if 0
  +  gtk_grab_remove(w_current->pwindow);
  +#endif
  +  gtk_widget_destroy(w_current->pwindow);
  +  w_current->pwindow = NULL;
  +  return(0);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +int x_print_keypress(GtkWidget * widget, GdkEventKey * event, 
  +		     TOPLEVEL * w_current)
  +{
  +  if (strcmp(gdk_keyval_name(event->keyval), "Escape") == 0) {
  +    x_print_cancel(NULL, w_current);	
  +    return TRUE;
  +  }
  +
  +  return FALSE;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_print_setup (TOPLEVEL *w_current, char *filename)
  +{
  +  GtkWidget *label;
  +  GtkWidget *separator;
  +  GtkWidget *box;
  +  GtkWidget *box2;
  +  GtkWidget *buttonprint;
  +  GtkWidget *buttoncancel;
  +  GtkWidget *scrolled_win;
  +  GtkWidget *list_item;
  +  GtkWidget *optionmenu;
  +  GtkWidget *orient_menu;
  +  GtkWidget *type_menu;
  +  GtkWidget *vbox, *action_area;
  +  char *string = NULL;
  +  int i;
  +
  +  /* freeze the window_current pointer so that it doesn't change */
  +
  +  if (!w_current->pwindow) {
  +
  +    w_current->pwindow = x_create_dialog_box(&vbox, &action_area); 
  +    gtk_container_border_width(GTK_CONTAINER(w_current->pwindow), 5);
  +
  +    gtk_window_position(GTK_WINDOW (w_current->pwindow),
  +                        GTK_WIN_POS_MOUSE);
  +
  +    gtk_signal_connect(GTK_OBJECT (w_current->pwindow),
  +                       "destroy",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->pwindow);
  +
  +#if 0 /* this was causing the dialog box to not die */
  +    gtk_signal_connect(GTK_OBJECT (w_current->pwindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->pwindow);
  +#endif
  +
  +    gtk_window_set_title(GTK_WINDOW(w_current->pwindow),
  +                         _("Print..."));
  +
  +#ifdef HAS_GTK12    
  +    buttonprint = gtk_button_new_with_label (_("Print"));
  +#else
  +    buttonprint = gtk_button_new_from_stock (GTK_STOCK_PRINT);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttonprint, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area),
  +                       buttonprint, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttonprint), "clicked",
  +                       GTK_SIGNAL_FUNC(x_print_print), w_current);
  +    gtk_widget_show (buttonprint);
  +    gtk_widget_grab_default (buttonprint);
  +
  +#ifdef HAS_GTK12
  +    buttoncancel = gtk_button_new_with_label (_("Cancel"));
  +#else
  +    buttoncancel = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
  +#endif
  +    GTK_WIDGET_SET_FLAGS (buttoncancel, GTK_CAN_DEFAULT);
  +    gtk_box_pack_start(GTK_BOX(action_area),
  +                       buttoncancel, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(buttoncancel),
  +                       "clicked", GTK_SIGNAL_FUNC(x_print_cancel),
  +                       w_current);
  +    gtk_widget_show (buttoncancel);
  +
  +    label = gtk_label_new (_("Output paper size"));
  +    gtk_misc_set_padding (GTK_MISC (label), 5, 5);
  +    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
  +
  +    gtk_widget_show (label);
  +
  +    scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  +
  +    gtk_scrolled_window_set_policy(
  +                                   GTK_SCROLLED_WINDOW(scrolled_win),
  +                                   GTK_POLICY_AUTOMATIC,
  +                                   GTK_POLICY_AUTOMATIC);
  +    gtk_box_pack_start(GTK_BOX(vbox), scrolled_win, TRUE, TRUE, 10);
  +    gtk_widget_set_usize(GTK_WIDGET(scrolled_win), 150, 100);
  +    gtk_widget_show (scrolled_win);
  +    box2 = gtk_vbox_new (FALSE, 0);
  +    gtk_scrolled_window_add_with_viewport(
  +                                          GTK_SCROLLED_WINDOW (scrolled_win), box2);
  +    gtk_widget_show(box2);
  +
  +    separator = gtk_hseparator_new ();
  +    gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, TRUE, 0);
  +    gtk_widget_show (separator);
  +
  +    w_current->plib_list = gtk_list_new ();
  +
  +    gtk_container_add(GTK_CONTAINER (box2), w_current->plib_list);
  +    gtk_widget_show (w_current->plib_list);
  +
  +    i = 0;
  +    string = (char *) s_papersizes_get(i);
  +    while (string != NULL) {
  +      GtkWidget *label = gtk_label_new(string);
  +
  +      gtk_misc_set_alignment(GTK_MISC (label), 0, 0);
  +
  +      list_item = gtk_list_item_new();
  +      gtk_container_add(GTK_CONTAINER(list_item), label);
  +      gtk_widget_show(label);
  +      gtk_container_add(GTK_CONTAINER(w_current->plib_list),
  +                        list_item);
  +      gtk_widget_show (list_item);
  +      gtk_label_get(GTK_LABEL(label), &string);
  +      gtk_object_set_data(GTK_OBJECT(list_item),
  +                          list_item_data_key,
  +                          string);
  +      i++;
  +      string = (char *) s_papersizes_get(i);
  +    }
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->plib_list),
  +                       "selection_changed",
  +                       GTK_SIGNAL_FUNC(x_print_change_size),
  +                       w_current);
  +
  +    box = gtk_hbox_new(FALSE, 0);
  +    gtk_container_border_width(GTK_CONTAINER(box), 0);
  +    gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, TRUE, 5);
  +    gtk_box_set_spacing(GTK_BOX(box), 10);
  +    gtk_widget_show(box);
  +
  +    label = gtk_label_new (_("Filename"));
  +    gtk_misc_set_alignment( GTK_MISC (label), 0, 0);
  +    gtk_misc_set_padding (GTK_MISC (label), 0, 0);
  +    gtk_box_pack_start (GTK_BOX (box),
  +                        label, FALSE, FALSE, 0);
  +
  +    gtk_widget_show (label);
  +
  +    w_current->pfilename_entry =
  +      gtk_entry_new_with_max_length(200);
  +    gtk_editable_select_region(
  +                               GTK_EDITABLE(w_current->pfilename_entry), 0, -1);
  +    gtk_box_pack_start(GTK_BOX (box),
  +                       w_current->pfilename_entry, TRUE, TRUE, 0);
  +    gtk_signal_connect(GTK_OBJECT(w_current->pfilename_entry),
  +                       "activate",
  +                       GTK_SIGNAL_FUNC(x_print_print),
  +                       w_current);
  +    gtk_widget_show (w_current->pfilename_entry);
  +
  +    separator = gtk_hseparator_new ();
  +    gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, TRUE, 0);
  +    gtk_widget_show (separator);
  +
  +    label = gtk_label_new (_("Type"));
  +    gtk_misc_set_padding (GTK_MISC (label), 5, 5);
  +    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
  +    gtk_widget_show (label);
  +    optionmenu = gtk_option_menu_new ();
  +    type_menu = create_menu_type (w_current);
  +    gtk_option_menu_set_menu(GTK_OPTION_MENU(optionmenu), 
  +                             type_menu);
  +    gtk_option_menu_set_history(GTK_OPTION_MENU (optionmenu), 4);
  +    gtk_box_pack_start(GTK_BOX(vbox), optionmenu, FALSE, TRUE, 0);
  +    gtk_widget_show(optionmenu);
  +
  +    label = gtk_label_new (_("Orientation"));
  +    gtk_misc_set_padding (GTK_MISC (label), 5, 5);
  +    gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 0);
  +
  +    gtk_widget_show (label);
  +    optionmenu = gtk_option_menu_new ();
  +    orient_menu = create_menu_orient (w_current);
  +    gtk_option_menu_set_menu(GTK_OPTION_MENU (optionmenu), 
  +                             orient_menu);
  +    gtk_option_menu_set_history(GTK_OPTION_MENU (optionmenu), 4);
  +    gtk_box_pack_start(GTK_BOX(vbox), optionmenu, FALSE, TRUE, 0);
  +    gtk_widget_show (optionmenu);
  +
  +    /* set some defaults */
  +    switch (w_current->print_output_type)
  +    {
  +      case(EXTENTS):
  +        gtk_menu_set_active(GTK_MENU (type_menu),0);
  +        f_print_set_type(w_current, EXTENTS);
  +        break;
  +        
  +      case(EXTENTS_NOMARGINS):
  +        gtk_menu_set_active(GTK_MENU (type_menu),1);
  +        f_print_set_type(w_current, EXTENTS_NOMARGINS);
  +        break;
  +        
  +      case(WINDOW):
  +        gtk_menu_set_active(GTK_MENU (type_menu),2);
  +        f_print_set_type(w_current, WINDOW);
  +        break;
  +    }
  +    
  +    if (w_current->print_orientation == PORTRAIT) {
  +      gtk_menu_set_active(GTK_MENU (orient_menu),1);
  +      print_portrait (NULL, w_current);
  +    } else {
  +      gtk_menu_set_active(GTK_MENU (orient_menu),0);
  +      print_landscape (NULL, w_current);
  +    }
  +
  +    gtk_signal_connect(GTK_OBJECT(w_current->pwindow), "key_press_event",
  +                         (GtkSignalFunc) x_print_keypress, w_current);
  +  }
  +
  +
  +  
  +  if (!GTK_WIDGET_VISIBLE (w_current->pwindow)) {
  +    gtk_entry_set_text(GTK_ENTRY(w_current->pfilename_entry),
  +                       filename);
  +#if 0
  +    gtk_entry_select_region(GTK_ENTRY(w_current->pfilename_entry),
  +                            0, strlen(filename));
  +#endif
  +
  +    gtk_widget_show (w_current->pwindow);
  +    gdk_window_raise(w_current->pwindow->window);
  +#if 0
  +    gtk_grab_add (w_current->pwindow);
  +#endif
  +  } else {
  +    /* window should already be mapped, otherwise this
  +     * will core */
  +    gdk_window_raise(w_current->pwindow->window);
  +  }
  +}
  
  
  
  1.11      +86 -70    eda/geda/gaf/gschem/src/x_script.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_script.c
  ===================================================================
  RCS file: x_script.c
  diff -N x_script.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_script.c	14 Jul 2006 02:23:55 -0000	1.11
  @@ -0,0 +1,127 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +/*! \todo CLEAN up line length in this file */
  +#include <config.h>
  +
  +#include <stdio.h>
  +#ifdef HAVE_STDLIB_H
  +#include <stdlib.h>
  +#endif
  +#ifdef HAVE_STRING_H
  +#include <string.h>
  +#endif
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void script_selection_ok(GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  int len;
  +  const char *string;
  +
  +  /* who frees this? */
  +  string = gtk_file_selection_get_filename(
  +                                           GTK_FILE_SELECTION(w_current->sowindow));
  +
  +  if(string != NULL) {
  +    len = strlen(string);
  +
  +    if (string[len - 1] != G_DIR_SEPARATOR) {
  +      s_log_message(_("Executing guile script [%s]\n"), string);
  +      g_read_file(string);
  +    }
  +  }
  +  /* would like to move this earlier! */
  +  gtk_grab_remove(w_current->sowindow);
  +  gtk_widget_destroy(GTK_WIDGET (w_current->sowindow));
  +  w_current->sowindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void script_selection_cancel (GtkWidget *w, TOPLEVEL *w_current)
  +{
  +  gtk_grab_remove(w_current->sowindow);
  +  gtk_widget_destroy (GTK_WIDGET (w_current->sowindow));
  +  w_current->sowindow = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void setup_script_selector (TOPLEVEL *w_current)
  +{
  +  if (!w_current->sowindow) {
  +    w_current->sowindow =
  +    gtk_file_selection_new(_("Script Execute..."));
  +    gtk_window_position(GTK_WINDOW(w_current->sowindow),
  +                        GTK_WIN_POS_MOUSE);
  +    /* added 4/6/98 */
  +    gtk_file_selection_hide_fileop_buttons(
  +                                           GTK_FILE_SELECTION(w_current->sowindow));
  +    gtk_signal_connect(GTK_OBJECT (w_current->sowindow),
  +                       "destroy",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->sowindow);
  +
  +#if 0 /* this was causing the dialog box to not die */
  +    gtk_signal_connect(GTK_OBJECT(w_current->sowindow),
  +                       "delete_event",
  +                       GTK_SIGNAL_FUNC(destroy_window),
  +                       &w_current->sowindow);
  +#endif
  +
  +    /*! \todo consistant function names for connect
  +     * connect_object */
  +    gtk_signal_connect (GTK_OBJECT (
  +                                    GTK_FILE_SELECTION (w_current->sowindow)->ok_button),
  +                        "clicked",
  +                        GTK_SIGNAL_FUNC(script_selection_ok),
  +                        w_current);
  +
  +    gtk_signal_connect(GTK_OBJECT(
  +                                  GTK_FILE_SELECTION(w_current->sowindow)->
  +                                  cancel_button),
  +                       "clicked",
  +                       GTK_SIGNAL_FUNC(script_selection_cancel),
  +                       w_current);
  +
  +  }
  +
  +  if (!GTK_WIDGET_VISIBLE (w_current->sowindow)) {
  +    gtk_widget_show (w_current->sowindow);
  +    gtk_grab_add (w_current->sowindow);
  +  }
  +}
  
  
  
  1.11      +85 -63    eda/geda/gaf/gschem/src/x_stroke.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_stroke.c
  ===================================================================
  RCS file: x_stroke.c
  diff -N x_stroke.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_stroke.c	14 Jul 2006 02:23:55 -0000	1.11
  @@ -0,0 +1,151 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <math.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/x_states.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +typedef struct st_stroke_point STROKE_POINT;
  +
  +struct st_stroke_point {
  +        int x, y;
  +        STROKE_POINT *next;
  +};
  +
  +static STROKE_POINT *stroke_points = NULL;
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_stroke_add_point(TOPLEVEL *w_current, int x, int y)
  +{
  +  STROKE_POINT *new_point;
  +
  +  new_point = (STROKE_POINT *) malloc (sizeof(STROKE_POINT));
  +
  +  new_point->x = x;
  +  new_point->y = y;
  +
  +  if (stroke_points == NULL) {
  +    stroke_points = new_point;
  +    stroke_points->next = NULL;
  +  } else {
  +    new_point->next = stroke_points;
  +    stroke_points = new_point;
  +  }
  +
  +  /* having this xored was causing some grief; when you zoomed
  +   * or changed the display, there would be point droppings, so
  +   * that's why this isn't xor */
  +#if 0
  +  gdk_gc_set_foreground(w_current->xor_gc,
  +                        x_get_color(w_current->stroke_color));
  +#endif
  +
  +  gdk_gc_set_foreground(w_current->gc,
  +                        x_get_color(w_current->stroke_color));
  +
  +  gdk_draw_point(w_current->window, w_current->gc, x, y);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  traverse list as well as free each point as you go along
  + */
  +void x_stroke_erase_all(TOPLEVEL *w_current)
  +{
  +  STROKE_POINT *temp;
  +
  +  while(stroke_points != NULL) {
  +
  +#if DEBUG
  +    printf("%d %d\n", stroke_points->x, stroke_points->y);
  +#endif
  +
  +    /* was xor, wasn't working out... see above note */
  +    gdk_gc_set_foreground(
  +                          w_current->gc,
  +                          x_get_color(w_current->background_color));
  +
  +    gdk_draw_point(w_current->window, w_current->gc,
  +                   stroke_points->x, stroke_points->y);
  +
  +    temp = stroke_points;
  +    stroke_points = stroke_points->next;
  +    free (temp);
  +  }
  +
  +  stroke_points = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_stroke_free_all(void)
  +{
  +  STROKE_POINT *temp;
  +
  +  while(stroke_points != NULL) {
  +#if DEBUG
  +    printf("%d %d\n", stroke_points->x, stroke_points->y);
  +#endif
  +
  +    temp = stroke_points;
  +    stroke_points = stroke_points->next;
  +    free (temp);
  +  }
  +
  +  stroke_points = NULL;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *  \note
  + *  this is the function that does the actual work of the strokes
  + *  by executing the right guile function which is associated with the stroke
  + */
  +int x_stroke_search_execute(char *sequence)
  +{
  +  gchar *guile_string; 
  +  SCM eval;
  +
  +  guile_string = g_strdup_printf("(eval-stroke \"%s\")", sequence);
  +
  +  eval = scm_c_eval_string (guile_string);
  +  g_free(guile_string);
  +
  +  return (SCM_FALSEP (eval)) ? 0 : 1;
  +}
  
  
  
  1.29      +972 -836  eda/geda/gaf/gschem/src/x_window.c
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: x_window.c
  ===================================================================
  RCS file: x_window.c
  diff -N x_window.c
  --- /dev/null	1 Jan 1970 00:00:00 -0000
  +++ x_window.c	14 Jul 2006 02:23:55 -0000	1.29
  @@ -0,0 +1,1095 @@
  +/* gEDA - GPL Electronic Design Automation
  + * gschem - gEDA Schematic Capture
  + * Copyright (C) 1998-2000 Ales V. Hvezda
  + *
  + * 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 USA
  + */
  +#include <config.h>
  +
  +#include <stdio.h>
  +
  +#include <libgeda/libgeda.h>
  +
  +#include "../include/x_event.h"
  +#include "../include/i_vars.h"
  +#include "../include/globals.h"
  +#include "../include/prototype.h"
  +
  +#ifdef HAVE_LIBDMALLOC
  +#include <dmalloc.h>
  +#endif
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_setup (TOPLEVEL *toplevel)
  +{
  +  PAGE *page;
  +  
  +  /* x_window_setup_rest() - BEGIN */
  +  toplevel->num_untitled=0;
  +
  +  toplevel->start_x = -1;
  +  toplevel->start_y = -1;
  +  toplevel->save_x = -1;
  +  toplevel->save_y = -1;
  +  toplevel->last_x = -1;
  +  toplevel->last_y = -1;
  +  toplevel->loc_x = -1;
  +  toplevel->loc_y = -1;
  +  toplevel->distance = -1;
  +  toplevel->event_state = SELECT;
  +  toplevel->inside_action = 0;
  +  toplevel->snap = 1;
  +  toplevel->grid = 1;
  +
  +  toplevel->show_hidden_text = 0;
  +  
  +  toplevel->complex_rotate = 0;
  +
  +  toplevel->current_attribute = NULL;
  +  toplevel->current_visible = -1; /* not sure on these */
  +  toplevel->current_show = -1;
  +
  +  toplevel->internal_basename=NULL;
  +  toplevel->internal_clib=NULL;
  +
  +  toplevel->series_name = NULL;
  +  toplevel->untitled_name = NULL;
  +  toplevel->font_directory = NULL;
  +  toplevel->scheme_directory = NULL;
  +  toplevel->bitmap_directory = NULL;
  +  toplevel->bus_ripper_symname = NULL;
  +
  +  toplevel->override_color = -1;
  +  toplevel->inside_redraw=0;
  +
  +  toplevel->FORCE_CONN_UPDATE=0;
  +  toplevel->ADDING_SEL=0;
  +  toplevel->REMOVING_SEL=0;
  +
  +  toplevel->drawbounding_action_mode=FREE;
  +  toplevel->last_drawb_mode = -1;
  +  toplevel->CONTROLKEY=0;
  +  toplevel->SHIFTKEY=0;
  +  toplevel->last_callback=NULL;
  +
  +  toplevel->major_changed_refdes = NULL;
  +
  +  toplevel->status_label = NULL;
  +  toplevel->middle_label = NULL;
  +  toplevel->filename_label = NULL;
  +
  +  toplevel->cswindow = NULL;
  +  toplevel->aswindow = NULL;
  +  toplevel->fowindow = NULL;
  +  toplevel->sowindow = NULL;
  +  toplevel->fswindow = NULL;
  +
  +  toplevel->tiwindow = NULL;
  +  toplevel->tewindow = NULL;
  +  toplevel->exwindow = NULL;
  +  toplevel->aawindow = NULL;
  +  toplevel->mawindow = NULL;
  +  toplevel->aewindow = NULL;
  +  toplevel->trwindow = NULL;
  +  toplevel->tswindow = NULL;
  +  toplevel->pswindow = NULL;
  +  toplevel->pwindow = NULL;
  +  toplevel->iwindow = NULL;
  +  toplevel->abwindow = NULL;
  +  toplevel->hkwindow = NULL;
  +  toplevel->cowindow = NULL;
  +  toplevel->clwindow = NULL;
  +  toplevel->ltwindow = NULL;
  +  toplevel->ftwindow = NULL;
  +  toplevel->sewindow = NULL;
  +  toplevel->fileselect[FILESELECT].xfwindow = NULL;
  +  toplevel->fileselect[FILESELECT].directory = NULL;
  +  toplevel->fileselect[FILESELECT].filename = NULL;
  +  x_fileselect_init_list_buffers(&toplevel->fileselect[FILESELECT]);
  +  toplevel->fileselect[COMPSELECT].xfwindow = NULL;
  +  toplevel->fileselect[COMPSELECT].directory = NULL;
  +  toplevel->fileselect[COMPSELECT].filename = NULL;
  +  x_fileselect_init_list_buffers(&toplevel->fileselect[COMPSELECT]);
  +
  +  toplevel->coord_world = NULL;
  +  toplevel->coord_screen = NULL;
  +  toplevel->doing_pan=FALSE;
  +  /* toplevel->preview = NULL;experimental widget */
  +
  +  toplevel->buffer_number=0;
  +  /* x_window_setup_rest() - END */
  +
  +  /* immediately setup user params */
  +  i_vars_set (toplevel);
  +
  +  /* make sure none of these events happen till we are done */
  +  toplevel->DONT_DRAW_CONN = 1;
  +  toplevel->DONT_RESIZE    = 1;
  +  toplevel->DONT_EXPOSE    = 1;
  +  toplevel->DONT_RECALC    = 1;
  +
  +  /* X related stuff */
  +  toplevel->display_height = gdk_screen_height ();
  +  toplevel->display_width  = gdk_screen_width ();
  +
  +  /* x_window_setup_world() - BEGIN */
  +  toplevel->init_left = -45;
  +  toplevel->init_top  = -45;
  +  /* init_right and _bottom are set before this function is called */
  +  toplevel->min_zoom  = 0;
  +  toplevel->max_zoom  = 256;  /* was 128 */
  +
  +  toplevel->width  = default_width;
  +  toplevel->height = default_height;
  +
  +  toplevel->starting_width = toplevel->width;
  +
  +  toplevel->win_width  = toplevel->width;
  +  toplevel->win_height = toplevel->height;
  +  /* x_window_setup_world() - END */
  +
  +  /* X related stuff */
  +  /* do X fill in first */
  +  x_window_create_main (toplevel);
  +
  +  /* Now create a blank page */
  +  page = s_page_new (toplevel, "unknown");
  +  s_page_goto (toplevel, page);
  +
  +  o_undo_savestate(toplevel, UNDO_ALL);
  +  i_update_menus(toplevel);
  +
  +  /* now update the scrollbars */
  +  toplevel->DONT_REDRAW = 1;
  +  x_hscrollbar_update(toplevel);
  +  x_vscrollbar_update(toplevel);
  +  toplevel->DONT_REDRAW = 0;
  +
  +  /* renable the events */
  +  toplevel->DONT_DRAW_CONN=0;
  +  toplevel->DONT_RESIZE=0;
  +  toplevel->DONT_EXPOSE=0;
  +  toplevel->DONT_RECALC=0;
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_setup_colors(void)
  +{
  +  gdk_color_parse ("black", &black);
  +  if (!gdk_colormap_alloc_color (colormap,
  +                                 &black,
  +                                 FALSE,
  +                                 TRUE)) {
  +    fprintf (stderr, _("Could not allocate the color %s!\n"), _("black"));
  +    exit (-1);
  +  }
  +
  +  gdk_color_parse ("white", &white);
  +  if (!gdk_colormap_alloc_color (colormap,
  +                                 &white,
  +                                 FALSE,
  +                                 TRUE)) {
  +    fprintf (stderr, _("Could not allocate the color %s!\n"), _("white"));
  +    exit (-1);
  +  }
  +
  +  x_color_allocate_all ();
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_free_colors(TOPLEVEL *w_current)
  +{
  +  GdkColor *colors[] = { &black, &white };
  +  
  +  gdk_colormap_free_colors (colormap, *colors, 2);
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_setup_gc(TOPLEVEL *w_current)
  +{
  +  GdkGCValues     values;
  +  GdkGCValuesMask  values_mask;
  +
  +  w_current->gc = gdk_gc_new(w_current->window);
  +
  +  if (w_current->gc == NULL) {
  +    fprintf(stderr, _("Couldn't allocate gc\n"));
  +    exit(-1);
  +  }
  +
  +  values.foreground = white;
  +  values.background = black;
  +
  +  values.function = GDK_XOR;
  +  values_mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_FUNCTION;
  +  w_current->xor_gc = gdk_gc_new_with_values(w_current->window,
  +                                             &values, values_mask);
  +
  +  if (w_current->xor_gc == NULL) {
  +    fprintf(stderr, _("Couldn't allocate xor_gc\n"));
  +    exit(-1);
  +  }
  +
  +  values.foreground = white;
  +  values.background = black;
  +
  +  values.function = GDK_XOR;
  +  values_mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND | GDK_GC_FUNCTION;
  +  w_current->outline_xor_gc = gdk_gc_new_with_values(w_current->window,
  +                                                     &values, values_mask);
  +
  +  if (w_current->outline_xor_gc == NULL) {
  +    fprintf(stderr, _("Couldn't allocate outline_xor_gc\n"));
  +    exit(-1);
  +  }
  +
  +  values.foreground = white;
  +  values.background = black;
  +
  +  values.function = GDK_XOR;
  +  values.line_style = GDK_LINE_ON_OFF_DASH;
  +  values_mask = GDK_GC_FOREGROUND | GDK_GC_BACKGROUND |
  +  GDK_GC_LINE_STYLE | GDK_GC_FUNCTION;
  +
  +  w_current->bounding_xor_gc = gdk_gc_new_with_values(w_current->window,
  +                                                      &values, values_mask);
  +
  +  if (w_current->bounding_xor_gc == NULL) {
  +    fprintf(stderr, _("Couldn't allocate bounding_xor_gc\n"));
  +    exit(-1);
  +  }
  +
  +  w_current->bus_gc = gdk_gc_new(w_current->window);
  +
  +  if (w_current->bus_gc == NULL) {
  +    fprintf(stderr, _("Couldn't allocate bus_gc\n"));
  +    exit(-1);
  +  }
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_free_gc(TOPLEVEL *w_current)
  +{
  +  gdk_gc_unref(w_current->gc);
  +  gdk_gc_unref(w_current->xor_gc);
  +  gdk_gc_unref(w_current->bounding_xor_gc);
  +  gdk_gc_unref(w_current->outline_xor_gc);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_create_drawing(GtkWidget *drawbox, TOPLEVEL *w_current)
  +{
  +  /* drawing next */
  +  w_current->drawing_area = gtk_drawing_area_new ();
  +  /* Set the size here.  Be sure that it has an aspect ratio of 1.333
  +   * We could calculate this based on root window size, but for now
  +   * lets just set it to:
  +   * Width = root_width*3/4   Height = Width/1.3333333333
  +   * 1.3333333 is the desired aspect ratio!
  +   */
  +
  +  gtk_drawing_area_size (GTK_DRAWING_AREA (w_current->drawing_area),
  +                         w_current->win_width,
  +                         w_current->win_height);
  +
  +  gtk_box_pack_start (GTK_BOX (drawbox), w_current->drawing_area,
  +                      TRUE, TRUE, 0);
  +  gtk_widget_show (w_current->drawing_area);
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_setup_draw_events(TOPLEVEL *w_current)
  +{
  +  struct event_reg_t {
  +    gchar *detailed_signal;
  +    void (*c_handler)(void);
  +  };
  +
  +  struct event_reg_t drawing_area_events[] = {
  +    { "expose_event",         G_CALLBACK(x_event_expose)          },
  +    { "button_press_event",   G_CALLBACK(x_event_button_pressed)  },
  +    { "button_release_event", G_CALLBACK(x_event_button_released) },
  +    { "motion_notify_event",  G_CALLBACK(x_event_motion)          },
  +    { "configure_event",      G_CALLBACK(x_event_configure)       },
  +    { NULL,                   NULL                                } };
  +  struct event_reg_t main_window_events[] = {
  +    { "enter_notify_event",   G_CALLBACK(x_event_enter)           },
  +    { "key_press_event",      G_CALLBACK(x_event_key_press)       },
  +#ifdef HAS_GTK22
  +    { "scroll_event",         G_CALLBACK(x_event_scroll)          },
  +#endif
  +    { NULL,                   NULL                                } };
  +  struct event_reg_t *tmp;
  +
  +  /* is the configure event type missing here? hack */
  +  gtk_widget_set_events (w_current->drawing_area,
  +                         GDK_EXPOSURE_MASK |
  +                         GDK_POINTER_MOTION_MASK |
  +                         GDK_BUTTON_PRESS_MASK   |
  +                         GDK_ENTER_NOTIFY_MASK |
  +                         GDK_KEY_PRESS_MASK |
  +                         GDK_BUTTON_RELEASE_MASK);
  +  for (tmp = drawing_area_events; tmp->detailed_signal != NULL; tmp++) {
  +    g_signal_connect (w_current->drawing_area,
  +                      tmp->detailed_signal,
  +                      tmp->c_handler,
  +                      w_current);
  +  }
  +
  +  for (tmp = main_window_events; tmp->detailed_signal != NULL; tmp++) {
  +    g_signal_connect (w_current->main_window,
  +                      tmp->detailed_signal,
  +                      tmp->c_handler,
  +                      w_current);
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +static GtkWidget *x_window_new_pixmap(const char *filename,
  +				      GdkWindow *window, GdkColor *background)
  +{
  +  GtkWidget *wpixmap;
  +  GdkPixmap *pixmap;
  +  GdkBitmap *mask;
  +
  +  pixmap = gdk_pixmap_create_from_xpm (window, &mask,
  +                                       background,
  +                                       filename);
  +#ifdef HAS_GTK22 
  +  wpixmap = gtk_image_new_from_pixmap (pixmap, mask);
  +#else
  +  wpixmap = gtk_pixmap_new (pixmap, mask);
  +#endif
  +
  +  return wpixmap;
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_create_main(TOPLEVEL *w_current)
  +{
  +  GtkWidget *label=NULL;
  +  GtkWidget *main_box=NULL;
  +  GtkWidget *menubar=NULL;
  +  GtkWidget *drawbox=NULL;
  +  GtkWidget *bottom_box=NULL;
  +  GtkWidget *toolbar=NULL;
  +  GtkWidget *handlebox=NULL;
  +  char *filename = NULL;
  +
  +  /* used to signify that the window isn't mapped yet */
  +  w_current->window = NULL; 
  +
  +  w_current->main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  +
  +  gtk_widget_set_name (w_current->main_window, "gschem");
  +  gtk_window_set_policy (GTK_WINDOW (w_current->main_window), TRUE, TRUE, TRUE);
  +
  +  /* We want the widgets to flow around the drawing area, so we don't
  +   * set a size of the main window.  The drawing area's size is fixed,
  +   * see below
  +   */
  +
  +   /* 
  +    * normally we let the window manager handle locating and sizing
  +    * the window.  However, for some batch processing of schematics
  +    * (generating a pdf of all schematics for example) we want to
  +    * override this.  Hence "auto_place_mode".
  +    */
  +   if( auto_place_mode )
  +   	gtk_widget_set_uposition (w_current->main_window, 10, 10);
  +
  +  /* I could not get the destroy signal to work. always got a: */
  +  /* Gdk-ERROR **: an x io error occurred */
  +  /* aborting... */
  +  /* message */
  +#if 0
  +  gtk_signal_connect (GTK_OBJECT (w_current->main_window), "destroy",
  +                      GTK_SIGNAL_FUNC(i_callback_destroy_wm),
  +                      w_current);
  +#endif
  +
  +  /* this should work fine */
  +  gtk_signal_connect (GTK_OBJECT (w_current->main_window), "delete_event",
  +                      GTK_SIGNAL_FUNC (i_callback_close_wm),
  +                      w_current);
  +
  +  /* Containers first */
  +  main_box = gtk_vbox_new(FALSE, 1);
  +  gtk_container_border_width(GTK_CONTAINER(main_box), 0);
  +  gtk_container_add(GTK_CONTAINER(w_current->main_window), main_box);
  +  gtk_widget_show(main_box);
  +
  +  get_main_menu(w_current, &menubar);
  +  if (w_current->handleboxes) {
  +  	handlebox = gtk_handle_box_new ();
  +  	gtk_box_pack_start(GTK_BOX(main_box), handlebox, FALSE, FALSE, 0);
  +  	gtk_widget_show(handlebox);
  +  	gtk_container_add (GTK_CONTAINER (handlebox), menubar);
  +  } else {
  +  	gtk_box_pack_start(GTK_BOX(main_box), menubar, FALSE, FALSE, 0);
  +  }
  +
  +  w_current->menubar = menubar;
  +  gtk_widget_show(menubar);
  +  gtk_widget_realize (w_current->main_window);
  +
  +  if (w_current->handleboxes && w_current->toolbars) {
  +  	handlebox = gtk_handle_box_new ();
  +  	gtk_box_pack_start (GTK_BOX (main_box), handlebox, FALSE, FALSE, 0);
  +  }
  + 
  +  if (w_current->toolbars) {
  +#ifdef HAS_GTK22
  +	toolbar = gtk_toolbar_new();
  +	gtk_toolbar_set_orientation (GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL);
  +	gtk_toolbar_set_style (GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
  +#else
  +  	toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, 
  +				   GTK_TOOLBAR_ICONS);
  +  	gtk_container_set_border_width (GTK_CONTAINER (toolbar), 5);
  +  	gtk_toolbar_set_space_size (GTK_TOOLBAR (toolbar), 5);
  +  	gtk_toolbar_set_button_relief (GTK_TOOLBAR (toolbar), GTK_RELIEF_NONE);
  +  	gtk_toolbar_set_space_style (GTK_TOOLBAR (toolbar), 
  +				     GTK_TOOLBAR_SPACE_LINE);
  +#endif
  +
  +  	if (w_current->handleboxes) {
  +  		gtk_container_add (GTK_CONTAINER (handlebox), toolbar);
  +	} else {
  +  		gtk_box_pack_start(GTK_BOX(main_box), toolbar, FALSE, FALSE, 0);
  +	}
  +
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-new.xpm", NULL);
  +  	gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), 
  +		  	   _("New"), 
  +			   _("New file"), 
  +			   "toolbar/new", 
  +  			   x_window_new_pixmap (filename,
  +				       w_current->main_window->window, 
  +	      			       &w_current->main_window->style->
  +					bg[GTK_STATE_NORMAL]), 
  +	      		   (GtkSignalFunc) i_callback_toolbar_file_new, 
  +			   w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-open.xpm", NULL);
  +  	gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), 
  +		  	   _("Open"), 
  +			   _("Open file..."), 
  +			   "toolbar/open", 
  +  			   x_window_new_pixmap (filename,
  +				       w_current->main_window->window, 
  +	      			       &w_current->main_window->style->
  +					bg[GTK_STATE_NORMAL]), 
  +	      		   (GtkSignalFunc) i_callback_toolbar_file_open, 
  +			   w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-save.xpm", NULL);
  +  	gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), 
  +		  	   _("Save"), 
  +			   _("Save file"), 
  +			   "toolbar/save", 
  +  			   x_window_new_pixmap (filename,
  +				       w_current->main_window->window, 
  +	      			       &w_current->main_window->style->
  +					bg[GTK_STATE_NORMAL]), 
  +	      		   (GtkSignalFunc) i_callback_toolbar_file_save, 
  +			   w_current);
  +  	gtk_toolbar_append_space (GTK_TOOLBAR(toolbar)); 
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-undo.xpm", NULL);
  +  	gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), 
  +		  	   _("Undo"), 
  +			   _("Undo last operation"), 
  +			   "toolbar/undo", 
  +  			   x_window_new_pixmap (filename,
  +				       w_current->main_window->window, 
  +	      			       &w_current->main_window->style->
  +					bg[GTK_STATE_NORMAL]), 
  +	      		   (GtkSignalFunc) i_callback_toolbar_edit_undo, 
  +			   w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-redo.xpm", NULL);
  +  	gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), 
  +		  	   _("Redo"), 
  +			   _("Redo last undo"), 
  +			   "toolbar/redo", 
  +  			   x_window_new_pixmap (filename,
  +				       w_current->main_window->window, 
  +	      			       &w_current->main_window->style->
  +					bg[GTK_STATE_NORMAL]), 
  +	      		   (GtkSignalFunc) i_callback_toolbar_edit_redo, 
  +			   w_current);
  +  	gtk_toolbar_append_space (GTK_TOOLBAR(toolbar)); 
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-comp.xpm", NULL);
  +  	/* not part of any radio button group */
  +  	gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), 
  +		  	   _("Component"), 
  +			   _("Add component...\nSelect library and component from list, move the mouse into main window, click to place\nRight mouse button to cancel"), 
  +			   "toolbar/component", 
  +  			   x_window_new_pixmap (filename,
  +				       w_current->main_window->window, 
  +	      			       &w_current->main_window->style->
  +					bg[GTK_STATE_NORMAL]), 
  +	      		   (GtkSignalFunc) i_callback_toolbar_add_component, 
  +			   w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-net.xpm", NULL);
  +  	w_current->toolbar_net = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     NULL,
  +                                     _("Nets"),
  +                                     _("Add nets mode\nRight mouse button to cancel"),
  +                                     "toolbar/nets",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		             (GtkSignalFunc) i_callback_toolbar_add_net,
  +			             w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-bus.xpm", NULL);
  +  	w_current->toolbar_bus = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     w_current->toolbar_net,
  +                                     _("Bus"),
  +                                     _("Add buses mode\nRight mouse button to cancel"),
  +                                     "toolbar/bus",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		             (GtkSignalFunc) i_callback_toolbar_add_bus,
  +			             w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-text.xpm", NULL);
  +  	/* not part of any radio button group */
  +  	gtk_toolbar_append_item (GTK_TOOLBAR (toolbar), 
  +		  	   _("Text"), 
  +			   _("Add Text..."), 
  +			   "toolbar/text", 
  +  			   x_window_new_pixmap (filename,
  +				       w_current->main_window->window, 
  +	      			       &w_current->main_window->style->
  +					bg[GTK_STATE_NORMAL]), 
  +	      		   (GtkSignalFunc) i_callback_toolbar_add_text, 
  +			   w_current);
  +
  +  	gtk_toolbar_append_space (GTK_TOOLBAR(toolbar)); 
  +
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-select.xpm", NULL);
  +  	w_current->toolbar_select = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     w_current->toolbar_bus,
  +                                     _("Select"),
  +                                     _("Select mode"),
  +                                     "toolbar/select",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		   	     (GtkSignalFunc) i_callback_toolbar_edit_select, 
  +			             w_current);
  +  	free(filename);
  +
  +#if 0 /* out until they work */
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-edit.xpm", NULL);
  +  	w_current->toolbar_edit = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     w_current->toolbar_select,
  +                                     _("Edit"),
  +                                     _("Edit mode"),
  +                                     "toolbar/edit",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		             (GtkSignalFunc) NULL, 
  +			             w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-move.xpm", NULL);
  +  	w_current->toolbar_edit = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     w_current->toolbar_edit,
  +                                     _("Move"),
  +                                     _("Move mode"),
  +                                     "toolbar/move",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		             (GtkSignalFunc) NULL, 
  +			             w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-copy.xpm", NULL);
  +  	w_current->toolbar_edit = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     w_current->toolbar_edit,
  +                                     _("Copy"),
  +                                     _("Copy mode"),
  +                                     "toolbar/copy",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		             (GtkSignalFunc) NULL, 
  +			             w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-delete.xpm", NULL);
  +  	w_current->toolbar_delete = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     w_current->toolbar_edit,
  +                                     _("Delete"),
  +                                     _("Delete mode"),
  +                                     "toolbar/delete",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		             (GtkSignalFunc) NULL, 
  +			             w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-rotate.xpm", NULL);
  +  	w_current->toolbar_rotate = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     w_current->toolbar_delete,
  +                                     _("Rotate"),
  +                                     _("Rotate mode"),
  +                                     "toolbar/rotate",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		             (GtkSignalFunc) NULL, 
  +			             w_current);
  +  	free(filename);
  +  	filename = g_strconcat(w_current->bitmap_directory, 
  +			       G_DIR_SEPARATOR_S, "gschem-mirror.xpm", NULL);
  +  	w_current->toolbar_mirror = gtk_toolbar_append_element(GTK_TOOLBAR(toolbar),
  +                                     GTK_TOOLBAR_CHILD_RADIOBUTTON,
  +                                     w_current->toolbar_rotate,
  +                                     _("Mirror"),
  +                                     _("Mirror mode"),
  +                                     "toolbar/mirror",
  +	                             x_window_new_pixmap (filename,
  +                                     w_current->main_window->window,
  +                                     &w_current->main_window->style->
  +                                     bg[GTK_STATE_NORMAL]),
  +	      		             (GtkSignalFunc) NULL, 
  +			             w_current);
  +  	free(filename);
  +#endif
  +
  +  	gtk_toolbar_append_space (GTK_TOOLBAR(toolbar)); 
  +  	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w_current->toolbar_select),
  +			       TRUE);
  +  	gtk_widget_show (toolbar);
  +  } 
  +
  +  if (w_current->handleboxes) {
  +  	gtk_widget_show (handlebox);
  +  }
  +
  +  /*  Try to create popup menu (appears in right mouse button  */
  +  w_current->popup_menu = (GtkWidget *) get_main_popup(w_current);
  +
  +  drawbox = gtk_hbox_new(FALSE, 0);
  +  gtk_container_border_width(GTK_CONTAINER(drawbox), 0);
  +  gtk_container_add(GTK_CONTAINER(main_box), drawbox);
  +  gtk_widget_show(drawbox);
  +
  +  x_window_create_drawing(drawbox, w_current);
  +  x_window_setup_draw_events(w_current);
  +
  +  if (w_current->scrollbars_flag == TRUE) {
  +    /* setup scroll bars */
  +    w_current->v_adjustment =
  +      gtk_adjustment_new (w_current->init_bottom,
  +                          0.0, w_current->init_bottom,
  +                          100.0, 100.0, 10.0);
  +
  +    w_current->v_scrollbar = gtk_vscrollbar_new (GTK_ADJUSTMENT (
  +                                                                 w_current->v_adjustment));
  +
  +    gtk_range_set_update_policy (GTK_RANGE (w_current->v_scrollbar),
  +                                 GTK_UPDATE_CONTINUOUS);
  +
  +    gtk_box_pack_start (GTK_BOX (drawbox), w_current->v_scrollbar,
  +                        FALSE, FALSE, 0);
  +
  +    gtk_signal_connect (GTK_OBJECT (w_current->v_adjustment),
  +                        "value_changed",
  +                        GTK_SIGNAL_FUNC (x_event_vschanged),
  +                        w_current);
  +
  +    gtk_widget_show (w_current->v_scrollbar);
  +
  +    w_current->h_adjustment = gtk_adjustment_new (0.0, 0.0,
  +                                                  w_current->init_right,
  +                                                  100.0, 100.0, 10.0);
  +
  +    w_current->h_scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (
  +                                                                 w_current->h_adjustment));
  +
  +    gtk_range_set_update_policy (GTK_RANGE (w_current->h_scrollbar),
  +                                 GTK_UPDATE_CONTINUOUS);
  +
  +    gtk_box_pack_start (GTK_BOX (main_box), w_current->h_scrollbar,
  +                        FALSE, FALSE, 0);
  +
  +    gtk_signal_connect (GTK_OBJECT (w_current->h_adjustment),
  +                        "value_changed",
  +                        GTK_SIGNAL_FUNC (x_event_hschanged),
  +                        w_current);
  +
  +    gtk_widget_show (w_current->h_scrollbar);
  +  }
  +
  +  /* bottom box */
  +  bottom_box = gtk_hbox_new(FALSE, 0);
  +  gtk_container_border_width(GTK_CONTAINER(bottom_box), 1);
  +  gtk_box_pack_start (GTK_BOX (main_box), bottom_box, FALSE, FALSE, 0);
  +  gtk_widget_show(bottom_box);
  +
  +  /*	label = gtk_label_new ("Mouse buttons:");
  +        gtk_box_pack_start (GTK_BOX (bottom_box), label, FALSE, FALSE, 10);
  +        gtk_widget_show (label);
  +  */
  +
  +  label = gtk_label_new (" ");
  +  gtk_box_pack_start (GTK_BOX (bottom_box), label, FALSE, FALSE, 2);
  +  gtk_widget_show (label);
  +
  +  w_current->left_label = gtk_label_new (_("Pick"));
  +  gtk_box_pack_start (GTK_BOX (bottom_box), w_current->left_label,
  +                      FALSE, FALSE, 0);
  +  gtk_widget_show (w_current->left_label);
  +
  +  label = gtk_label_new ("|");
  +  gtk_box_pack_start (GTK_BOX (bottom_box), label, FALSE, FALSE, 5);
  +  gtk_widget_show (label);
  +
  +  if (w_current->middle_button == STROKE) {
  +#ifdef HAS_LIBSTROKE
  +    w_current->middle_label = gtk_label_new (_("Stroke"));
  +#else
  +    w_current->middle_label = gtk_label_new (_("none"));
  +#endif
  +  } else if (w_current->middle_button == ACTION) {
  +    w_current->middle_label = gtk_label_new (_("Action"));
  +  } else {
  +    w_current->middle_label = gtk_label_new (_("Repeat/none"));
  +  }
  +
  +  gtk_box_pack_start (GTK_BOX (bottom_box), w_current->middle_label,
  +                      FALSE, FALSE, 0);
  +  gtk_widget_show (w_current->middle_label);
  +
  +  label = gtk_label_new ("|");
  +  gtk_box_pack_start (GTK_BOX (bottom_box), label, FALSE, FALSE, 5);
  +  gtk_widget_show (label);
  +
  +  if (default_third_button == POPUP_ENABLED) {
  +    w_current->right_label = gtk_label_new (_("Menu/Cancel"));
  +  } else {
  +    w_current->right_label = gtk_label_new (_("Pan/Cancel"));
  +  }
  +  gtk_box_pack_start (GTK_BOX (bottom_box), w_current->right_label,
  +                      FALSE, FALSE, 0);
  +  gtk_widget_show (w_current->right_label);
  +
  +  label = gtk_label_new (" ");
  +  gtk_box_pack_start (GTK_BOX (bottom_box), label, FALSE, FALSE, 5);
  +  gtk_widget_show (label);
  +
  +  w_current->filename_label = gtk_label_new (" ");
  +  gtk_box_pack_start (GTK_BOX (bottom_box), w_current->filename_label,
  +                      FALSE, FALSE, 10);
  +  gtk_widget_show (w_current->filename_label);
  +
  +  w_current->status_label = gtk_label_new (_("Select Mode"));
  +  gtk_box_pack_end (GTK_BOX (bottom_box), w_current->status_label, FALSE,
  +                    FALSE, 10);
  +  gtk_widget_show (w_current->status_label);
  +
  +  gtk_widget_show(w_current->main_window);
  +
  +  w_current->window = w_current->drawing_area->window;
  +
  +  /* draw a black rectangle in drawing area just to make it look nice */
  +  /* don't do this now */
  +  /* gdk_draw_rectangle(window, main_window->style->black_gc, TRUE, 0, 0,
  +   *				win_width, win_height);
  +   *
  +   */
  +
  +  w_current->backingstore = gdk_pixmap_new(w_current->window,
  +                                           w_current->drawing_area->allocation.width,
  +                                           w_current->drawing_area->allocation.height,
  +                                           -1);
  +  x_window_setup_gc(w_current);
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_close(TOPLEVEL *w_current)
  +{
  +  gboolean last_window = FALSE;
  +
  +  if (s_page_check_changed(w_current->page_head)) {
  +    exit_dialog(w_current);
  +    return;
  +  }
  +
  +#if DEBUG
  +  o_conn_print_hash(w_current->page_current->conn_table);
  +#endif
  +
  +  /* close all the dialog boxes */
  +  if (w_current->fowindow)
  +  gtk_widget_destroy(w_current->fowindow);
  +
  +  if (w_current->sowindow)
  +  gtk_widget_destroy(w_current->sowindow);
  +
  +  if (w_current->fswindow)
  +  gtk_widget_destroy(w_current->fswindow);
  +
  +  if (w_current->aswindow)
  +  gtk_widget_destroy(w_current->aswindow);
  +
  +  if (w_current->cswindow)
  +  gtk_widget_destroy(w_current->cswindow);
  +
  +  if (w_current->tiwindow)
  +  gtk_widget_destroy(w_current->tiwindow);
  +
  +  if (w_current->tewindow)
  +  gtk_widget_destroy(w_current->tewindow);
  +
  +  if (w_current->aawindow)
  +  gtk_widget_destroy(w_current->aawindow);
  +
  +  if (w_current->mawindow)
  +  gtk_widget_destroy(w_current->mawindow);
  +
  +  if (w_current->aewindow)
  +  gtk_widget_destroy(w_current->aewindow);
  +
  +  if (w_current->trwindow)
  +  gtk_widget_destroy(w_current->trwindow);
  +
  +  x_pagesel_close (w_current);
  +
  +  if (w_current->exwindow)
  +  gtk_widget_destroy(w_current->exwindow);
  +
  +  if (w_current->tswindow)
  +  gtk_widget_destroy(w_current->tswindow);
  +
  +  if (w_current->abwindow)
  +  gtk_widget_destroy(w_current->abwindow);
  +
  +  if (w_current->iwindow)
  +  gtk_widget_destroy(w_current->iwindow);
  +
  +  if (w_current->pwindow)
  +  gtk_widget_destroy(w_current->pwindow);
  +
  +  if (w_current->hkwindow)
  +  gtk_widget_destroy(w_current->hkwindow);
  +
  +  if (w_current->cowindow)
  +  gtk_widget_destroy(w_current->cowindow);
  +
  +  if (w_current->clwindow)
  +  gtk_widget_destroy(w_current->clwindow);
  +
  +  if (w_current->ltwindow)
  +  gtk_widget_destroy(w_current->ltwindow);
  +
  +  if (w_current->sewindow)
  +  gtk_widget_destroy(w_current->sewindow);
  +
  +  if (w_current->fileselect[FILESELECT].xfwindow) {
  +    gtk_widget_destroy(w_current->fileselect[FILESELECT].xfwindow);
  +  }
  +
  +  if (w_current->fileselect[COMPSELECT].xfwindow) {
  +    gtk_widget_destroy(w_current->fileselect[COMPSELECT].xfwindow);
  +  }
  +
  +  x_fileselect_free_list_buffers(&w_current->fileselect[FILESELECT]);
  +  x_fileselect_free_list_buffers(&w_current->fileselect[COMPSELECT]);
  +
  +  if (w_current->next == NULL && w_current->prev->prev == NULL) {
  +    /* no more window after this one, remember to quit */
  +    last_window = TRUE;
  +  }
  +  
  +  o_attrib_free_current(w_current);
  +  o_complex_free_filename(w_current);
  +
  +  if (w_current->major_changed_refdes) {
  +    GList* current = w_current->major_changed_refdes;
  +    while (current)
  +    {
  +      /* printf("yeah freeing: %s\n", (char*) current->data); */
  +      free(current->data);
  +      current = current->next;
  +    }
  +    g_list_free(w_current->major_changed_refdes);
  +  }
  +
  +  /* stuff that has to be done before we free w_current */
  +  if (last_window) {
  +    /* free all fonts */
  +    o_text_freeallfonts (w_current);
  +    /* close the log file */
  +    s_log_close ();
  +    /* free the buffers */
  +    o_buffer_free (w_current);
  +  }
  +
  +  if (w_current->backingstore) {
  +    gdk_pixmap_unref(w_current->backingstore);
  +  }
  +
  +  x_window_free_gc(w_current);
  +
  +  /* finally close the main window */
  +  gtk_widget_destroy(w_current->main_window);
  +  
  +  s_toplevel_delete (w_current);
  +
  +  /* just closed last window, so quit */
  +  if (last_window) {
  +    gschem_quit();
  +  }
  +  
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + */
  +void x_window_close_all(TOPLEVEL *toplevel)
  +{
  +  TOPLEVEL *last, *current;
  +
  +  /* find last toplevel in toplevel list */
  +  for (last = toplevel; last->next != NULL; last = last->next);
  +
  +  /* now close each toplevel */
  +  for (current = last; current->prev != NULL; current = last) {
  +    /* save a ref to the previous toplevel in the list */
  +    last = current->prev;
  +    /* close current if it is not a preview toplevel */
  +    if (current->main_window != NULL) {
  +      x_window_close (current);
  +    }
  +  }
  +
  +}
  +
  +/*! \todo Finish function documentation!!!
  + *  \brief
  + *  \par Function Description
  + *
  + *
  + *  \todo GROSS! but this is required because clist widgets don't seem to
  + *  allow you pass data to callback functions, so I need to get w_current
  + *  by searching the entire window list for page_clist widget :(  If
  + *  somebody knows a better way of doing this, please let me know!
  + */
  +TOPLEVEL *x_window_search_page_clist(GtkWidget *findme)
  +{
  +  TOPLEVEL *w_current;
  +
  +  /* find the toplevel head */
  +  for (w_current = global_window_current;
  +       w_current->prev != NULL;
  +       w_current = w_current->prev);
  +  /* now examine page_clist of each toplevel */
  +  for (;
  +       w_current != NULL && w_current->page_clist != findme;
  +       w_current = w_current->next);
  +  
  +  return w_current;
  +}
  +
  +
  +
  
  
  


_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs