/* Handle type for GnomeCanvas widget
 *
 * Copyright (C) 1998 Free Software Foundation
 *
 * Developed by Havoc Pennington <hp@pobox.com>
 *
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gnome.h>
#include "gnome-canvas-handle.h"

#include <math.h>
#include <gtk/gtksignal.h>
#include "debug.h"
/****************************************************************************
 * Forward references.
 **/
static void gnome_canvas_handle_class_init (GnomeCanvasHandleClass *class);
static void gnome_canvas_handle_init       (GnomeCanvasHandle      *handle);
static void gnome_canvas_handle_destroy    (GtkObject              *object);
static void gnome_canvas_handle_set_arg    (GtkObject              *object,
					    GtkArg                 *arg,
					    guint                  arg_id);
static void gnome_canvas_handle_get_arg    (GtkObject              *object,
					    GtkArg                 *arg,
					    guint                  arg_id);
static void gnome_canvas_handle_realize    (GnomeCanvasItem        *item);
static void gnome_canvas_handle_unrealize  (GnomeCanvasItem        *item);
static void gnome_canvas_handle_translate  (GnomeCanvasItem        *item, 
					    gdouble                dx, 
					    gdouble                dy);
static gint gnome_canvas_handle_event      (GnomeCanvasItem        *item, 
					    GdkEvent               *event);
static double gnome_canvas_handle_point    (GnomeCanvasItem        *item, 
					    gdouble                x, 
					    gdouble                y, 
					    gint                   cx, 
					    gint                   cy, 
					    GnomeCanvasItem        **act_item);
static void   gnome_canvas_handle_draw     (GnomeCanvasItem        *item, 
					    GdkDrawable            *drawable,
					    gint                   x, 
					    gint                   y, 
					    gint                   width, 
					    gint                   height);
static void gnome_canvas_handle_bounds     (GnomeCanvasItem        *item, 
					    gdouble                *x1, 
					    gdouble                *y1, 
					    gdouble                *x2, 
					    gdouble                *y2);

static void gtk_marshal_NONE__DOUBLE_DOUBLE (GtkObject * object,
					     GtkSignalFunc func,
					     gpointer func_data,
					     GtkArg * args);
/****************************************************************************
 * Local definitions.
 **/
enum {
  ARG_0,
  ARG_PRELIGHT,
  ARG_ANCHOR,
  ARG_SENSITIVE,
  ARG_X, 
  ARG_Y
};

enum {
  MOVED,
  LAST_SIGNAL
};

#define HALF_A_HANDLE 3
static GnomeCanvasItemClass *parent_class;
static gint handle_signals[LAST_SIGNAL] = { 0 };
/**
 *
 * gnome_canvas_handl_get_type:
 *
 * Registers the &GnomeCanvasHandle class if necessary, and returns the 
 * unique type ID associated to it.
 **/
GtkType
gnome_canvas_handle_get_type (void)
{
  static GtkType handle_type = 0;
  D_FUNC_START;
  if (!handle_type) 
    {
      GtkTypeInfo handle_info = {
	"GnomeCanvasHandle",
	sizeof (GnomeCanvasHandle),
	sizeof (GnomeCanvasHandleClass),
	(GtkClassInitFunc) gnome_canvas_handle_class_init,
	(GtkObjectInitFunc) gnome_canvas_handle_init,
	NULL, /* reserved_1 */
	NULL, /* reserved_2 */
	(GtkClassInitFunc) NULL
      };
      
      handle_type = gtk_type_unique (gnome_canvas_item_get_type (), &handle_info);
    }
  D_FUNC_END;
  return handle_type;
}

static void
gnome_canvas_handle_class_init (GnomeCanvasHandleClass *klass)
{
  GtkObjectClass *object_class;
  GnomeCanvasItemClass *item_class;

  D_FUNC_START;
  object_class = (GtkObjectClass *) klass;
  item_class = (GnomeCanvasItemClass *) klass;

  parent_class = gtk_type_class (gnome_canvas_item_get_type ());

  gtk_object_add_arg_type ("GnomeCanvasHandle::prelight", 
			   GTK_TYPE_BOOL, 
			   GTK_ARG_READWRITE, 
			   ARG_PRELIGHT);
  gtk_object_add_arg_type ("GnomeCanvasHandle::sensitive", 
			   GTK_TYPE_BOOL, 
			   GTK_ARG_READWRITE, 
			   ARG_SENSITIVE);
  gtk_object_add_arg_type ("GnomeCanvasHandle::x", 
			   GTK_TYPE_DOUBLE, 
			   GTK_ARG_READWRITE, 
			   ARG_X);
  gtk_object_add_arg_type ("GnomeCanvasHandle::y", 
			   GTK_TYPE_DOUBLE, 
			   GTK_ARG_READWRITE, 
			   ARG_Y);
  gtk_object_add_arg_type ("GnomeCanvasHandle::anchor", 
			   GTK_TYPE_ANCHOR_TYPE, 
			   GTK_ARG_READWRITE, 
			   ARG_ANCHOR);

  handle_signals[MOVED] =
    gtk_signal_new ("moved",
		    GTK_RUN_LAST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GnomeCanvasHandleClass, moved),
		    gtk_marshal_NONE__DOUBLE_DOUBLE,
		    GTK_TYPE_NONE, 2, GTK_TYPE_DOUBLE, GTK_TYPE_DOUBLE);

  gtk_object_class_add_signals (object_class, handle_signals, 
				LAST_SIGNAL);

  klass->moved = NULL;

  item_class->realize     = gnome_canvas_handle_realize;
  //  item_class->reconfigure = gnome_canvas_handle_reconfigure;
  item_class->event       = gnome_canvas_handle_event;
  item_class->point       = gnome_canvas_handle_point;
  item_class->unrealize   = gnome_canvas_handle_unrealize;
  item_class->translate   = gnome_canvas_handle_translate;
  item_class->draw        = gnome_canvas_handle_draw;
  item_class->bounds      = gnome_canvas_handle_bounds;

  object_class->destroy = gnome_canvas_handle_destroy;
  object_class->set_arg = gnome_canvas_handle_set_arg;
  object_class->get_arg = gnome_canvas_handle_get_arg;
  D_FUNC_END;
}

static void
gnome_canvas_handle_init (GnomeCanvasHandle *handle)
{
  D_FUNC_START;
  handle->gc        = NULL;
  handle->x         = 0.0;
  handle->y         = 0.0;
  handle->anchor    = GTK_ANCHOR_CENTER;
  handle->sensitive = FALSE;
  handle->prelight  = FALSE;
  handle->dragging  = FALSE;
  D_FUNC_END;
}

static void
gnome_canvas_handle_destroy (GtkObject *object)
{
  GnomeCanvasHandle *handle;

  D_FUNC_START;
  g_return_if_fail (object != NULL);
  g_return_if_fail (GNOME_IS_CANVAS_HANDLE (object));

  handle = GNOME_CANVAS_HANDLE (object);

  if (handle->gc) 
    gdk_gc_unref(handle->gc);
  handle->gc = NULL;
  
  if (GTK_OBJECT_CLASS (parent_class)->destroy)
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
  D_FUNC_END;
}


static void
recalc_coords (GnomeCanvasHandle *handle, 
	       double* x1, double* y1, double* x2, double* y2)
{
  GnomeCanvasItem *item;

  double wx, wy;
  double half;
  double onepixel;

  D_FUNC_START;
  g_return_if_fail(x1 != 0);
  g_return_if_fail(y1 != 0);
  g_return_if_fail(x2 != 0);
  g_return_if_fail(y2 != 0);
  
  item = GNOME_CANVAS_ITEM (handle);
  
  wx = handle->x;
  wy = handle->y;
  
  onepixel = 1/item->canvas->pixels_per_unit;

  half = HALF_A_HANDLE/item->canvas->pixels_per_unit;
  
  /* Anchor handle */
  
  switch (handle->anchor) 
    {
    case GTK_ANCHOR_NW:
    case GTK_ANCHOR_W:
    case GTK_ANCHOR_SW:
      /* onepixel prevents overlap with dragged item */
      *x1 = wx - half*2 - onepixel;
      *x2 = wx - onepixel;
      break;
      
    case GTK_ANCHOR_N:
    case GTK_ANCHOR_CENTER:
    case GTK_ANCHOR_S:
      *x1 = wx - half;
      *x2 = wx + half;
      break;
      
    case GTK_ANCHOR_NE:
    case GTK_ANCHOR_E:
    case GTK_ANCHOR_SE:
      *x1 = wx + onepixel;
      *x2 = wx + half*2 + onepixel;
      break;
    }
  
  switch (handle->anchor) 
    {
    case GTK_ANCHOR_NW:
    case GTK_ANCHOR_N:
    case GTK_ANCHOR_NE:
      *y1 = wy - half*2 - onepixel;
      *y2 = wy - onepixel;
      break;
      
    case GTK_ANCHOR_W:
    case GTK_ANCHOR_CENTER:
    case GTK_ANCHOR_E:
      *y1 = wy - half;
      *y2 = wy + half;
      break;
      
    case GTK_ANCHOR_SW:
    case GTK_ANCHOR_S:
    case GTK_ANCHOR_SE:
      *y1 = wy + onepixel;
      *y2 = wy + half*2 + onepixel;
      break;
    }
  D_FUNC_END;
}

static void
recalc_bounds (GnomeCanvasHandle* handle)
{
  GnomeCanvasItem *item;
  double x1, y1, x2, y2;
  D_FUNC_START;
  item = GNOME_CANVAS_ITEM (handle);

  recalc_coords(handle,&x1,&y1,&x2,&y2);
  
  gnome_canvas_item_i2w (item, &x1, &y1);
  gnome_canvas_item_i2w (item, &x2, &y2);
  gnome_canvas_w2c (item->canvas, x1, y1, &item->x1, &item->y1);
  gnome_canvas_w2c (item->canvas, x2, y2, &item->x2, &item->y2);
  
  /* Some safety fudging */
  
  item->x1 -= 1;
  item->y1 -= 1;
  item->x2 += 1;
  item->y2 += 1;

  gnome_canvas_group_child_bounds (GNOME_CANVAS_GROUP (item->parent), item);
  D_FUNC_END;
}


static void
gnome_canvas_handle_bounds (GnomeCanvasItem *item, double *x1, double *y1, 
			    double *x2, double *y2)
{
  GnomeCanvasHandle* handle = GNOME_CANVAS_HANDLE (item);
  D_FUNC_START;
  recalc_coords (handle,x1,y1,x2,y2);
  D_FUNC_END;
}

static void
gnome_canvas_handle_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
  GnomeCanvasItem *item;
  GnomeCanvasHandle *handle;
  D_FUNC_START;
  item = GNOME_CANVAS_ITEM (object);
  handle = GNOME_CANVAS_HANDLE (object);

  switch (arg_id) 
    {
    case ARG_PRELIGHT:
      handle->prelight = GTK_VALUE_BOOL(*arg);
      break;
    case ARG_SENSITIVE:
      handle->sensitive = GTK_VALUE_BOOL(*arg);
      break;
    case ARG_X:
      handle->x = GTK_VALUE_DOUBLE (*arg);
      break;
    case ARG_Y:
      handle->y = GTK_VALUE_DOUBLE (*arg);
      break;
    case ARG_ANCHOR:
      handle->anchor = GTK_VALUE_ENUM (*arg);
      break;
    default:
      g_warning("GnomeCanvasHandle got an unknown arg type.");
      break;
    }
  
  recalc_bounds(handle);
  D_FUNC_END;
}


static void
gnome_canvas_handle_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
  GnomeCanvasHandle *handle;

  D_FUNC_START;
  handle = GNOME_CANVAS_HANDLE (object);

  switch (arg_id) 
    {
    case ARG_PRELIGHT:
      GTK_VALUE_BOOL (*arg) = handle->prelight;
      break;
    case ARG_SENSITIVE:
      GTK_VALUE_BOOL (*arg) = handle->sensitive;
      break;
    case ARG_X:
      GTK_VALUE_DOUBLE (*arg) = handle->x;
      break;
    case ARG_Y:
      GTK_VALUE_DOUBLE (*arg) = handle->y;
      break;
    case ARG_ANCHOR:
      GTK_VALUE_ENUM (*arg) = handle->anchor;
      break;
    default:
      arg->type = GTK_TYPE_INVALID;
      break;
    }
  D_FUNC_END;
}


static void
gnome_canvas_handle_realize (GnomeCanvasItem *item)
{
  GdkColor            color;
  GnomeCanvasHandle   *handle = GNOME_CANVAS_HANDLE(item);
  D_FUNC_START;
  if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize)
    (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item);

  if (!item->canvas->aa)
    {
      handle->gc = gdk_gc_new (item->canvas->layout.bin_window);
      
      gdk_gc_set_line_attributes (handle->gc, 1,
				  GDK_LINE_SOLID, 
				  GDK_CAP_PROJECTING, 
				  GDK_JOIN_MITER);

      if (!gdk_color_white(item->canvas->cc->colormap, &color)) {
	g_warning("Couldn't get white color for GnomeCanvasHandle!");
      }
      
      gdk_gc_set_foreground(handle->gc, &color);
      gdk_gc_set_function(handle->gc, GDK_XOR);
    }
  D_FUNC_END;
}


static void 
gnome_canvas_handle_unrealize   (GnomeCanvasItem *item)
{
  GnomeCanvasHandle* handle = GNOME_CANVAS_HANDLE(item);
  D_FUNC_START;
  if (handle->gc) 
    gdk_gc_unref(handle->gc);
  handle->gc = NULL;

  if (GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize)
    (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item);
  D_FUNC_END;
}


static void 
gnome_canvas_handle_translate   (GnomeCanvasItem *item, double dx, double dy)
{
  GnomeCanvasHandle* handle = GNOME_CANVAS_HANDLE(item);
  D_FUNC_START;
  handle->x += dx;
  handle->y += dy;

  recalc_bounds(handle);
  D_FUNC_END;
}

static void 
gnome_canvas_handle_reconfigure (GnomeCanvasItem *item)
{
  D_FUNC_START;
  /*
  if (GNOME_CANVAS_ITEM_CLASS(parent_class)->reconfigure)
    (* GNOME_CANVAS_ITEM_CLASS(parent_class)->reconfigure) (item);
  */
  recalc_bounds(GNOME_CANVAS_HANDLE(item));
  D_FUNC_END;
}


static void   
gnome_canvas_handle_draw  (GnomeCanvasItem *item, GdkDrawable *drawable, 
			   int x, int y, int width, int height)
{
  GnomeCanvasHandle* handle;
  double dx, dy;
  double x1, y1, x2, y2;
  int cx1, cy1, cx2, cy2;
  gboolean with_prelight;
  D_FUNC_START;
  handle = GNOME_CANVAS_HANDLE (item);

  g_return_if_fail(handle->gc != 0);
  
  dx = 0.0;
  dy = 0.0;
  
  gnome_canvas_item_i2w (item, &dx, &dy);
  recalc_coords(handle,&x1,&y1,&x2,&y2);

  gnome_canvas_w2c (item->canvas, dx + x1, dy + y1, &cx1, &cy1);
  gnome_canvas_w2c (item->canvas, dx + x2, dy + y2, &cx2, &cy2);
  
  with_prelight = handle->prelight && handle->sensitive;

  gdk_draw_rectangle (drawable,
		      handle->gc,
		      with_prelight,
		      cx1 - x,
		      cy1 - y,
		      /* Filled rectangle covers one fewer so we have to add one */
		      cx2 - cx1 + (with_prelight ? 1 : 0),
		      cy2 - cy1 + (with_prelight ? 1 : 0));  
  D_FUNC_END;
}

static void
queue_redraw(GnomeCanvasHandle* handle) 
{
  GnomeCanvasItem* item = GNOME_CANVAS_ITEM(handle);
  double wx1, wy1, wx2, wy2;
  int cx1, cy1, cx2, cy2;
  D_FUNC_START;
  recalc_coords(handle, &wx1, &wy1, &wx2, &wy2);
  gnome_canvas_item_i2w(item, &wx1, &wy1);
  gnome_canvas_item_i2w(item, &wx2, &wy2);
  gnome_canvas_w2c(item->canvas, wx1, wy1, &cx1, &cy1);
  gnome_canvas_w2c(item->canvas, wx2, wy2, &cx2, &cy2);
  /* Use a slightly larger area for safety */
  gnome_canvas_request_redraw(item->canvas, cx1-1, cy1-1, cx2+1, cy2+1);
  D_FUNC_END;
}

static void
switch_cursors_and_grab(GnomeCanvasHandle* handle, guint32 grab_time)
{
  D_FUNC_START;
  if (!handle->dragging) 
    {
    GdkCursor* ptr;
    
    ptr = NULL;
    switch (handle->anchor) 
      {
      case GTK_ANCHOR_NW:
	ptr = gdk_cursor_new (GDK_TOP_LEFT_CORNER);
	break;
      case GTK_ANCHOR_W:
	ptr = gdk_cursor_new (GDK_LEFT_SIDE);
	break;
      case GTK_ANCHOR_SW:
	ptr = gdk_cursor_new (GDK_BOTTOM_LEFT_CORNER);
	break;
      case GTK_ANCHOR_N:
	ptr = gdk_cursor_new (GDK_TOP_SIDE);
	break;
      case GTK_ANCHOR_CENTER:
	ptr = gdk_cursor_new (GDK_CROSSHAIR);
	break;
      case GTK_ANCHOR_S:
	ptr = gdk_cursor_new (GDK_BOTTOM_SIDE);
	break;      
      case GTK_ANCHOR_NE:
	ptr = gdk_cursor_new (GDK_TOP_RIGHT_CORNER);
	break;
      case GTK_ANCHOR_E:
	ptr = gdk_cursor_new (GDK_RIGHT_SIDE);
	break;
      case GTK_ANCHOR_SE:
	ptr = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER);
	break;
	
      default:
	g_warning("Bad anchor");
	break;
    }
    
    gnome_canvas_item_grab (GNOME_CANVAS_ITEM(handle),
			    GDK_POINTER_MOTION_MASK | 
			    GDK_BUTTON_RELEASE_MASK | 
			    GDK_BUTTON_PRESS_MASK,
			    ptr,
			    grab_time);
    
    gdk_cursor_destroy (ptr);
    
    handle->dragging = TRUE;
    }
  D_FUNC_END;
}

static void
ungrab(GnomeCanvasHandle* handle, guint32 ungrab_time)
{
  D_FUNC_START;
  if (handle->dragging) 
    {
      gnome_canvas_item_ungrab(GNOME_CANVAS_ITEM(handle), ungrab_time);
      handle->dragging = FALSE;
    }
  D_FUNC_END;
}

static gint 
gnome_canvas_handle_event(GnomeCanvasItem* item, GdkEvent* event)
{
  GnomeCanvasHandle* handle = GNOME_CANVAS_HANDLE(item);
  gboolean need_redraw = FALSE;
  D_FUNC_START;
  switch (event->type)
    {
    case GDK_ENTER_NOTIFY:
      handle->prelight = TRUE;
      need_redraw = TRUE;
      break;
      
    case GDK_LEAVE_NOTIFY:
      handle->prelight = FALSE;
      need_redraw = TRUE;
      break;
      
    case GDK_BUTTON_PRESS:
      if (!handle->sensitive)
	{
	  D_FUNC_END;
	  return FALSE;
	}
      switch (event->button.button) 
	{
	case 1:
	  switch_cursors_and_grab(handle, event->button.time);
	  break;
	  
	default:
	  D_FUNC_END;
	  return FALSE;
	  break;
	}
      break; /* Button press */
      
    case GDK_BUTTON_RELEASE:
      switch (event->button.button) 
	{
	case 1:
	  if (!handle->dragging) return FALSE;
	  else ungrab(handle, event->button.time);
	  break;
	  
	default:
	  D_FUNC_END;
	  return FALSE;
	  break;
	}
      break; /* Button release */
      
    case GDK_MOTION_NOTIFY:
      if (handle->dragging) 
	{
	  double newx, newy;
	  /* Queue a redraw on the old location */
	  queue_redraw(handle);
	  
	  /* Now move the handle, only on the dimension(s) allowed
	     by the anchor type, snapping as needed. */
	  newx = event->motion.x;
	  newy = event->motion.y;
	  
	  gnome_canvas_item_w2i(item, &newx, &newy);
	  
	  if (handle->snap_func) 
	    {
	      (*(handle->snap_func))(&newx, &newy, handle->snap_func_data);
	    }
	  
	  switch (handle->anchor) 
	    {
	    case GTK_ANCHOR_NW:
	    case GTK_ANCHOR_SW:
	    case GTK_ANCHOR_W:
	    case GTK_ANCHOR_NE:
	    case GTK_ANCHOR_SE:
	    case GTK_ANCHOR_E:
	    case GTK_ANCHOR_CENTER:
	      handle->x = newx;
	      break;
	      
	    case GTK_ANCHOR_N:
	    case GTK_ANCHOR_S:
	      /* Can't move in X direction */
	      break;
	      
	    default:
	      g_warning("Bad anchor");
	      break;
	    }
	  
	  switch (handle->anchor) 
	    {
	    case GTK_ANCHOR_NW:
	    case GTK_ANCHOR_NE:
	    case GTK_ANCHOR_N:
	    case GTK_ANCHOR_SW:
	    case GTK_ANCHOR_SE:
	    case GTK_ANCHOR_S:
	    case GTK_ANCHOR_CENTER:
	      handle->y = newy;
	      break;
	      
	    case GTK_ANCHOR_W:
	    case GTK_ANCHOR_E:
	      /* Can't move in Y direction */
	      break;
	      
	    default:
	      g_warning("Bad anchor");
	      break;
	    }
	  
	  recalc_bounds(handle);
	  gtk_signal_emit(GTK_OBJECT(handle), handle_signals[MOVED],
			  handle->x, handle->y);
	  need_redraw = TRUE;
	}
      else
	{
	  D_FUNC_END;
	  return FALSE;
	}
      break; /* Motion notify */
      
    default:
      D_FUNC_END;
      return FALSE;
    }
  
  /* Draw new location or redraw with/without fill */
  if (need_redraw) 
    queue_redraw(handle);
  D_FUNC_END;
  return TRUE;
}

void    
gnome_canvas_handle_transfer_drag(GnomeCanvasHandle* current_grab, 
				  GnomeCanvasHandle* new_grab,
				  guint32 event_time)
{
  g_return_if_fail(current_grab || new_grab);
  D_FUNC_START;
  if (current_grab) ungrab(current_grab, event_time);
  if (new_grab) switch_cursors_and_grab(new_grab, event_time);

  if (current_grab) current_grab->prelight = FALSE;
  if (new_grab) new_grab->prelight     = TRUE;

  if (current_grab) queue_redraw(current_grab);
  if (new_grab) queue_redraw(new_grab);
  D_FUNC_END;
}

void    
gnome_canvas_handle_set_snap_func(GnomeCanvasHandle* handle, 
				  GnomeCanvasSnapFunc func, 
				  gpointer data)
{
  handle->snap_func = func;
  handle->snap_func_data = data;
}

static double
gnome_canvas_handle_point (GnomeCanvasItem *item, double x, double y, 
			   int cx, int cy, GnomeCanvasItem **actual_item)
{
  GnomeCanvasHandle *handle;
  double x1, y1, x2, y2;
  double dx, dy;
  D_FUNC_START;
  handle = GNOME_CANVAS_HANDLE (item);

  *actual_item = item;

  recalc_coords(handle,&x1,&y1,&x2,&y2);

  /* On top of the handle */

  if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
    return 0.0;
  }

  /* Point is outside */

  if (x < x1)
    dx = x1 - x;
  else if (x > x2)
    dx = x - x2;
  else
    dx = 0.0;

  if (y < y1)
    dy = y1 - y;
  else if (y > y2)
    dy = y - y2;
  else
    dy = 0.0;
  D_FUNC_END;
  return sqrt (dx * dx + dy * dy);
}


typedef void (*GtkSignal_NONE__DOUBLE_DOUBLE) (GtkObject * object,
					       gdouble arg1,
					       gdouble arg2,
					       gpointer user_data);

static void gtk_marshal_NONE__DOUBLE_DOUBLE (GtkObject * object,
					     GtkSignalFunc func,
					     gpointer func_data,
					     GtkArg * args)
{
  GtkSignal_NONE__DOUBLE_DOUBLE rfunc;
  rfunc = (GtkSignal_NONE__DOUBLE_DOUBLE) func;
  (*rfunc) (object,
	    GTK_VALUE_DOUBLE (args[0]),
	    GTK_VALUE_DOUBLE (args[1]),
	    func_data);
}

