/* -*- Mode: C -*-
 * Handle line type for GnomeCanvas widget
 * Copyright (C) 1998 Free Software Foundation
 *
 * Developed by Havoc Pennington <hp@pobox.com>
 * Additonal enhancements/bug fixes Gregory McLean <gregm@comstar.net>
 *
 * 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 <math.h>
#include <time.h>

#include "gnome-canvas-handle-line.h"
#include "debug.h"
/****************************************************************************
 * Forward references
 **/
static void gnome_canvas_handle_line_class_init (GnomeCanvasHandleLineClass *class);
static void gnome_canvas_handle_line_init       (GnomeCanvasHandleLine      *handle);
static void gnome_canvas_handle_line_destroy    (GtkObject            *object);
static void gnome_canvas_handle_line_set_arg    (GtkObject            *object,
						 GtkArg               *arg,
						 guint                arg_id);
static void gnome_canvas_handle_line_get_arg    (GtkObject            *object,
						 GtkArg               *arg,
						 guint                arg_id);
static void gnome_canvas_handle_line_create     (GnomeCanvasHandled   *handled,
						 GdkEventButton       *event);
static void gnome_canvas_handle_line_scale(GnomeCanvasHandled* handled,
					   gdouble x1, gdouble y1,
					   gdouble x2, gdouble y2);

static void gnome_canvas_handle_line_size (GnomeCanvasHandled* handled, 
					   double* x1, double* y1, 
					   double* x2, double* y2);

static void gnome_canvas_handle_line_realize (GnomeCanvasItem *item);

static void gnome_canvas_handle_line_unrealize   (GnomeCanvasItem *item);

static void gnome_canvas_handle_line_reconfigure (GnomeCanvasItem *item);

static void gnome_canvas_handle_line_handle1_moved(GnomeCanvasItem* item, gdouble x, gdouble y,
						   GnomeCanvasHandleLine* handle_line);

static void gnome_canvas_handle_line_handle2_moved(GnomeCanvasItem* item, gdouble x, gdouble y,
						   GnomeCanvasHandleLine* handle_line);

static gint gnome_canvas_handle_line_line_event(GnomeCanvasItem* item, GdkEvent* event, 
						GnomeCanvasHandleLine* handle_line);

enum {
  ARG_0,
  ARG_TYPE,
  ARG_X1,
  ARG_Y1,
  ARG_X2,
  ARG_Y2
};


enum {
  LAST_SIGNAL
};

static GnomeCanvasHandledClass *parent_class;

/* static gint handle_line_signals[LAST_SIGNAL] = { 0 }; */

GtkType
gnome_canvas_handle_line_get_type (void)
{
  static GtkType handle_line_type = 0;

  if (!handle_line_type) {
    GtkTypeInfo handle_line_info = {
      "GnomeCanvasHandleLine",
      sizeof (GnomeCanvasHandleLine),
      sizeof (GnomeCanvasHandleLineClass),
      (GtkClassInitFunc) gnome_canvas_handle_line_class_init,
      (GtkObjectInitFunc) gnome_canvas_handle_line_init,
      NULL, /* reserved_1 */
      NULL, /* reserved_2 */
      (GtkClassInitFunc) NULL
    };

    handle_line_type = gtk_type_unique (gnome_canvas_handled_get_type (), &handle_line_info);
  }

  return handle_line_type;
}

static void
gnome_canvas_handle_line_class_init (GnomeCanvasHandleLineClass *klass)
{
  GtkObjectClass *object_class;
  GnomeCanvasItemClass *item_class;
  GnomeCanvasHandledClass *handled_class;

  object_class = (GtkObjectClass *) klass;
  item_class = (GnomeCanvasItemClass *) klass;
  handled_class = (GnomeCanvasHandledClass*) klass;

  parent_class = gtk_type_class (gnome_canvas_handled_get_type ());

  gtk_object_add_arg_type ("GnomeCanvasHandleLine::type", GTK_TYPE_ENUM, GTK_ARG_READWRITE, ARG_TYPE);
  gtk_object_add_arg_type ("GnomeCanvasHandleLine::x1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X1);
  gtk_object_add_arg_type ("GnomeCanvasHandleLine::y1", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y1);
  gtk_object_add_arg_type ("GnomeCanvasHandleLine::x2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_X2);
  gtk_object_add_arg_type ("GnomeCanvasHandleLine::y2", GTK_TYPE_DOUBLE, GTK_ARG_READWRITE, ARG_Y2);

  handled_class->create         = gnome_canvas_handle_line_create;
  handled_class->size           = gnome_canvas_handle_line_size;
  handled_class->scale          = gnome_canvas_handle_line_scale;

  item_class->realize     = gnome_canvas_handle_line_realize;
  //item_class->reconfigure = gnome_canvas_handle_line_reconfigure;
  item_class->unrealize   = gnome_canvas_handle_line_unrealize;

  object_class->destroy = gnome_canvas_handle_line_destroy;
  object_class->set_arg = gnome_canvas_handle_line_set_arg;
  object_class->get_arg = gnome_canvas_handle_line_get_arg;
}

static void
gnome_canvas_handle_line_init (GnomeCanvasHandleLine *handle_line)
{
  handle_line->type = GNOME_HANDLE_LINE_LINE;
  handle_line->line = NULL;
  
  handle_line->handle1 = NULL;
  handle_line->handle2 = NULL;

  handle_line->coords[0] = 0.0;
  handle_line->coords[1] = 0.0;
  handle_line->coords[2] = 0.0;
  handle_line->coords[3] = 0.0;
}

static void
gnome_canvas_handle_line_destroy (GtkObject *object)
{
  GnomeCanvasHandleLine *handle_line;

  g_return_if_fail (object != NULL);
  g_return_if_fail (GNOME_IS_CANVAS_HANDLE_LINE (object));

  handle_line = GNOME_CANVAS_HANDLE_LINE (object);

  /* Want to emit unselect if appropriate */
  if (GNOME_CANVAS_HANDLED_IS_SELECTED(GNOME_CANVAS_HANDLED(object))) 
    gnome_canvas_handled_set_selected(GNOME_CANVAS_HANDLED(object), FALSE);

  /* Group method will take care of all these. */

  handle_line->line = NULL;

  handle_line->handle1 = NULL;
  
  handle_line->handle2 = NULL;

  if (GTK_OBJECT_CLASS (parent_class)->destroy)
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}

static void
gnome_canvas_handle_line_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
  GnomeCanvasItem *item;
  GnomeCanvasHandleLine *handle_line;

  item = GNOME_CANVAS_ITEM (object);
  handle_line = GNOME_CANVAS_HANDLE_LINE (object);

  switch (arg_id) {
  case ARG_TYPE:
    handle_line->type = GTK_VALUE_ENUM (*arg);
    break;
  case ARG_X1:
    handle_line->coords[0] = GTK_VALUE_DOUBLE (*arg);
    break;
  case ARG_Y1:
    handle_line->coords[1] = GTK_VALUE_DOUBLE (*arg);
    break;
  case ARG_X2:
    handle_line->coords[2] = GTK_VALUE_DOUBLE (*arg);
    break;
  case ARG_Y2:
    handle_line->coords[3] = GTK_VALUE_DOUBLE (*arg);
    break;
  default:
    g_warning("GnomeCanvasHandleLine got an unknown arg type.");
    break;
  }

  gnome_canvas_handle_line_reconfigure(item);
}

static void
gnome_canvas_handle_line_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
  GnomeCanvasHandleLine *handle_line;

  handle_line = GNOME_CANVAS_HANDLE_LINE (object);

  switch (arg_id) {
  case ARG_TYPE:
    GTK_VALUE_ENUM (*arg) = handle_line->type;
    break;
  case ARG_X1:
    GTK_VALUE_DOUBLE (*arg) = handle_line->coords[0];
    break;
  case ARG_Y1:
    GTK_VALUE_DOUBLE (*arg) = handle_line->coords[1];
    break;
  case ARG_X2:
    GTK_VALUE_DOUBLE (*arg) = handle_line->coords[2];
    break;
  case ARG_Y2:
    GTK_VALUE_DOUBLE (*arg) = handle_line->coords[3];
    break;
  default:
    arg->type = GTK_TYPE_INVALID;
    break;
  }
}


static void
gnome_canvas_handle_line_realize (GnomeCanvasItem *item)
{
  GnomeCanvasHandleLine* handle_line = GNOME_CANVAS_HANDLE_LINE(item);

  if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize)
    (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item);

  /* This is a horrible hack - it should be in gnome_canvas_handle_line_new(GnomeCanvasGroup*),
     which does not exist and would be all weird in the canvas context. 
     However, people might want to change the line characteristics at creation time. 
     Which is currently impossible. */

  handle_line->line = 
    GNOME_CANVAS_LINE(gnome_canvas_item_new(GNOME_CANVAS_GROUP(handle_line),
					    gnome_canvas_line_get_type(), 
					    NULL));
  gtk_signal_connect(GTK_OBJECT(handle_line->line), "event",
		     GTK_SIGNAL_FUNC(gnome_canvas_handle_line_line_event),
		     handle_line);

  gnome_canvas_handle_line_reconfigure(item);
}

static void 
gnome_canvas_handle_line_unrealize   (GnomeCanvasItem *item)
{
  GnomeCanvasHandleLine* handle_line = GNOME_CANVAS_HANDLE_LINE(item);

  /* Want to emit unselect if appropriate */
  if (GNOME_CANVAS_HANDLED_IS_SELECTED(GNOME_CANVAS_HANDLED(item))) 
    gnome_canvas_handled_set_selected(GNOME_CANVAS_HANDLED(item), FALSE);

  /* Let the group unrealize function unrealize handles and line. */

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

static void
sync_line(GnomeCanvasHandleLine* handle_line)
{
  GnomeCanvasPoints points;

  g_assert(handle_line->line != NULL);

  points.num_points = 2;
  points.coords = handle_line->coords;
  
  gnome_canvas_item_set(GNOME_CANVAS_ITEM(handle_line->line),
			"points", &points, 
			NULL);  
}

static void
show_handles(GnomeCanvasHandleLine* handle_line) 
{
  g_return_if_fail(handle_line->handle1);

  gnome_canvas_item_show(GNOME_CANVAS_ITEM(handle_line->handle1));
  gnome_canvas_item_show(GNOME_CANVAS_ITEM(handle_line->handle2));
}


static void
hide_handles(GnomeCanvasHandleLine* handle_line) 
{
  g_return_if_fail(handle_line->handle1);

  gnome_canvas_item_hide(GNOME_CANVAS_ITEM(handle_line->handle1));
  gnome_canvas_item_hide(GNOME_CANVAS_ITEM(handle_line->handle2));
}

static void 
sync_handles(GnomeCanvasHandleLine* handle_line)
{
  GnomeCanvasHandled* handled =        GNOME_CANVAS_HANDLED(handle_line);

  g_assert(handle_line->handle1 != NULL);
  g_assert(handle_line->handle2 != NULL);

  gnome_canvas_item_set(GNOME_CANVAS_ITEM(handle_line->handle1),
			"x", handle_line->coords[0],
			"y", handle_line->coords[1],
			"sensitive", handled->sensitive,
			NULL);

  gnome_canvas_item_set(GNOME_CANVAS_ITEM(handle_line->handle2),
			"x", handle_line->coords[2],
			"y", handle_line->coords[3],
			"sensitive", handled->sensitive,
			NULL);
}

static void
sync_handles_directions(GnomeCanvasHandleLine* handle_line)
{
  GtkAnchorType anchor = GTK_ANCHOR_CENTER;

  switch (handle_line->type) {
  case GNOME_HANDLE_LINE_LINE:
    anchor = GTK_ANCHOR_CENTER;
    break;
  case GNOME_HANDLE_LINE_VRULE:
    if (handle_line->coords[1] > handle_line->coords[3])
      anchor = GTK_ANCHOR_SOUTH;
    else 
      anchor = GTK_ANCHOR_NORTH;
    break;
  case GNOME_HANDLE_LINE_HRULE:
    if (handle_line->coords[0] < handle_line->coords[2])
      anchor = GTK_ANCHOR_WEST;
    else 
      anchor = GTK_ANCHOR_EAST;
    break;
  }
  
  gnome_canvas_item_set(GNOME_CANVAS_ITEM(handle_line->handle1),
			"anchor", anchor,
			NULL);
  
  switch (handle_line->type) {
  case GNOME_HANDLE_LINE_LINE:
    anchor = GTK_ANCHOR_CENTER;
    break;
  case GNOME_HANDLE_LINE_VRULE:
    if (handle_line->coords[1] > handle_line->coords[3])
      anchor = GTK_ANCHOR_NORTH;
    else 
      anchor = GTK_ANCHOR_SOUTH;
    break;
  case GNOME_HANDLE_LINE_HRULE:
    if (handle_line->coords[0] < handle_line->coords[2])
      anchor = GTK_ANCHOR_EAST;
    else 
      anchor = GTK_ANCHOR_WEST;
    break;
  }
  
  gnome_canvas_item_set(GNOME_CANVAS_ITEM(handle_line->handle2),
			"anchor", anchor,
			NULL);
}


static void 
gnome_canvas_handle_line_reconfigure (GnomeCanvasItem *item)
{
  GnomeCanvasHandleLine* handle_line = GNOME_CANVAS_HANDLE_LINE(item);
  GnomeCanvasHandled* handled =        GNOME_CANVAS_HANDLED(item);

  if (handle_line->line == NULL) 
    return; /* Not realized yet. */

  if (GNOME_CANVAS_HANDLED_IS_SELECTED(handled)) 
    {
      if (handle_line->handle1 == NULL) 
	{
	  d_print (DEBUG_DUMP, "Adding handles...\n");
	  handle_line->handle1 = 
	    GNOME_CANVAS_HANDLE(gnome_canvas_item_new (GNOME_CANVAS_GROUP(item),
						       gnome_canvas_handle_get_type(),
						       NULL));
	  handle_line->handle2 = 
	    GNOME_CANVAS_HANDLE(gnome_canvas_item_new(GNOME_CANVAS_GROUP(item),
						      gnome_canvas_handle_get_type(),
						      NULL));
	  

	  gtk_signal_connect(GTK_OBJECT(handle_line->handle1), "moved",
			     GTK_SIGNAL_FUNC(gnome_canvas_handle_line_handle1_moved),
			     handle_line);
	  gtk_signal_connect(GTK_OBJECT(handle_line->handle2), "moved",
			     GTK_SIGNAL_FUNC(gnome_canvas_handle_line_handle2_moved),
			     handle_line);
	}
      
      sync_handles(handle_line);
      sync_handles_directions(handle_line);
    }
  /* Not selected */
  else 
    {
      if (handle_line->handle1) 
	{
	  g_assert(handle_line->handle2);
	  
	  gtk_object_destroy(GTK_OBJECT(handle_line->handle1));
	  gtk_object_destroy(GTK_OBJECT(handle_line->handle2));
	  handle_line->handle1 = handle_line->handle2 = NULL;
	}
    }
  
  sync_line(handle_line);
}

static gint 
gnome_canvas_handle_line_line_event(GnomeCanvasItem* item, GdkEvent* event, 
				    GnomeCanvasHandleLine* handle_line)
{
  /*  GnomeCanvasLine* line = GNOME_CANVAS_LINE(item); */
  static double lastx = 0.0, lasty = 0.0;
  GdkCursor* ptr = NULL;
  GnomeCanvasHandled* handled = GNOME_CANVAS_HANDLED(handle_line);

  switch (event->type)
    {
    case GDK_ENTER_NOTIFY:
      if (!GNOME_CANVAS_HANDLED_IS_SENSITIVE(handled)) 
	return FALSE;
      
      ptr = gdk_cursor_new(GDK_FLEUR);
      gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, ptr);
      gdk_cursor_destroy (ptr);
      break;
      
    case GDK_LEAVE_NOTIFY:
      /* Unset the cursor, even if insensitive 
	 (in case we set it while sensitive) */
      gdk_window_set_cursor(GTK_WIDGET(item->canvas)->window, NULL);
      break;
      
    case GDK_BUTTON_PRESS:
      if (!GNOME_CANVAS_HANDLED_IS_SENSITIVE(handled)) 
	return FALSE;
      
      switch (event->button.button) 
	{
	case 1: 
	  if (!handled->dragging) 
	    {
	      gnome_canvas_item_grab (item,
				      GDK_POINTER_MOTION_MASK | 
				      GDK_BUTTON_RELEASE_MASK |
				      GDK_BUTTON_PRESS_MASK,
				      NULL, /* already set on enter */
				      event->button.time);
	      
	      lastx = event->button.x;
	      lasty = event->button.y;
	      gnome_canvas_item_w2i (GNOME_CANVAS_ITEM(handle_line), 
				     &lastx, &lasty);
	      	      
	      handled->dragging = TRUE;
	      gnome_canvas_handled_set_selected(handled, TRUE); 
	      hide_handles(handle_line);
	    }
	  break;
	  
	case 2:
	  if (event->button.state & GDK_CONTROL_MASK) 
	    gnome_canvas_item_lower(GNOME_CANVAS_ITEM(handle_line),1);
	  else 
	    gnome_canvas_item_raise(GNOME_CANVAS_ITEM(handle_line),1);
	  
	  gnome_canvas_handle_line_reconfigure(GNOME_CANVAS_ITEM(handle_line));
	  break;
	  
	default:
	  return FALSE;
	  break;
	}
      break; /* Button press */
      
    case GDK_BUTTON_RELEASE:
      switch (event->button.button) 
	{
	case 1:
	  if (handled->dragging) 
	    {
	      gnome_canvas_item_ungrab(item, event->button.time);
	      
	      handled->dragging = FALSE;
	      show_handles(handle_line);
	    }
	  else return FALSE;
	  break;
	  
	default:
	  return FALSE;
	  break;
	}
      break; /* Button release */
      
    case GDK_MOTION_NOTIFY:
      if (handled->dragging) 
	{
	  double newx, newy, dx, dy;
	  
	  newx = event->motion.x;
	  newy = event->motion.y;
	  
	  gnome_canvas_item_w2i(GNOME_CANVAS_ITEM(handle_line), 
				&newx, &newy);
	  
	  dx = newx - lastx;
	  dy = newy - lasty;
	  lastx = newx;
	  lasty = newy;
	  
	  handle_line->coords[0] += dx;
	  handle_line->coords[1] += dy;
	  handle_line->coords[2] += dx;
	  handle_line->coords[3] += dy;
	  
	  gnome_canvas_handle_line_reconfigure(GNOME_CANVAS_ITEM(handle_line));
	  
	  gnome_canvas_handled_resized(handled, 
				       handle_line->coords[0], 
				       handle_line->coords[1],
				       handle_line->coords[2],
				       handle_line->coords[3]);
	}
      else return FALSE;
      break; /* Motion notify */
      
    default:
      return FALSE;
    }
  
  return TRUE;
}

static void 
gnome_canvas_handle_line_create (GnomeCanvasHandled* handled, 
				 GdkEventButton* event)
{
  GnomeCanvasHandleLine* handle_line = GNOME_CANVAS_HANDLE_LINE(handled);  
  double x1, y1, x2, y2;

  handled->selected = TRUE;

  if (event == NULL) 
    {
      /* Make up some defaults */
      gnome_canvas_get_scroll_region(GNOME_CANVAS_ITEM(handled)->canvas,
				     &x1, &y1, &x2, &y2);
      gnome_canvas_item_w2i(GNOME_CANVAS_ITEM(handled),
			    &x1, &y1);
      gnome_canvas_item_w2i(GNOME_CANVAS_ITEM(handled),
			    &x2, &y2);
    
      handle_line->coords[0] = x1;
      handle_line->coords[1] = y1;
      handle_line->coords[2] = 
	(handle_line->type != GNOME_HANDLE_LINE_VRULE) ? x1+(x2-x1)/2 : x1;
      handle_line->coords[3] = 
	(handle_line->type != GNOME_HANDLE_LINE_HRULE) ? y1+(y2-y1)/2 : y1;
      
      gnome_canvas_handle_line_reconfigure(GNOME_CANVAS_ITEM(handled));
    }
  else 
    {
      x1 = event->x;
      y1 = event->y;
      gnome_canvas_item_w2i(GNOME_CANVAS_ITEM(handled), &x1, &y1);
      
      handle_line->coords[0] = handle_line->coords[2] = x1;
      handle_line->coords[1] = handle_line->coords[3] = y1;
      gnome_canvas_handle_line_reconfigure(GNOME_CANVAS_ITEM(handled));
      
      gnome_canvas_handle_transfer_drag(NULL,handle_line->handle1,event->time);
    }
}

static void
gnome_canvas_handle_line_handle1_moved(GnomeCanvasItem* item, gdouble x, gdouble y,
				       GnomeCanvasHandleLine* handle_line)
{
  /*  GnomeCanvasHandle* handle = GNOME_CANVAS_HANDLE(item); */

  gnome_canvas_item_i2w(item, &x, &y);
  gnome_canvas_item_w2i(GNOME_CANVAS_ITEM(handle_line), &x, &y);

  handle_line->coords[0] = x;
  handle_line->coords[1] = y;

  switch (handle_line->type) {
  case GNOME_HANDLE_LINE_LINE:
    /* doesn't matter if we pass the other handle */
    break;

  case GNOME_HANDLE_LINE_VRULE:
  case GNOME_HANDLE_LINE_HRULE:
    sync_handles_directions(handle_line);
    break;
  }
  
  sync_line(handle_line);

  gnome_canvas_handled_resized(GNOME_CANVAS_HANDLED(handle_line),
			       handle_line->coords[0], 
			       handle_line->coords[1],
			       handle_line->coords[2],
			       handle_line->coords[3]);
}


static void
gnome_canvas_handle_line_handle2_moved(GnomeCanvasItem* item, gdouble x, gdouble y,
				       GnomeCanvasHandleLine* handle_line)
{
  /*  GnomeCanvasHandle* handle = GNOME_CANVAS_HANDLE(item); */

  gnome_canvas_item_i2w(item, &x, &y);
  gnome_canvas_item_w2i(GNOME_CANVAS_ITEM(handle_line), &x, &y);
  
  handle_line->coords[2] = x;
  handle_line->coords[3] = y;

  switch (handle_line->type) 
    {
    case GNOME_HANDLE_LINE_LINE:
      /* doesn't matter if we pass the other handle */
      break;
      
    case GNOME_HANDLE_LINE_VRULE:
    case GNOME_HANDLE_LINE_HRULE:
      sync_handles_directions(handle_line);
      break;
    }
  
  sync_line(handle_line);

  gnome_canvas_handled_resized(GNOME_CANVAS_HANDLED(handle_line),
			       handle_line->coords[0], 
			       handle_line->coords[1],
			       handle_line->coords[2],
			       handle_line->coords[3]);
}

static void 
gnome_canvas_handle_line_scale(GnomeCanvasHandled* handled,
			       gdouble x1, gdouble y1,
			       gdouble x2, gdouble y2)
{
  GnomeCanvasHandleLine* handle_line = GNOME_CANVAS_HANDLE_LINE(handled);  
  
  handle_line->coords[0] = x1;
  handle_line->coords[1] = y1;
  handle_line->coords[2] = x2;
  handle_line->coords[3] = y2;

  gnome_canvas_handle_line_reconfigure(GNOME_CANVAS_ITEM(handled));
}

static void 
gnome_canvas_handle_line_size (GnomeCanvasHandled* handled, 
			       double* x1, double* y1, 
			       double* x2, double* y2)
{
  GnomeCanvasHandleLine* handle_line;

  g_return_if_fail(GNOME_IS_CANVAS_HANDLE_LINE(handled));

  handle_line = GNOME_CANVAS_HANDLE_LINE(handled);
  
  if (x1) *x1 = MIN(handle_line->coords[0], handle_line->coords[2]);
  if (x2) *x2 = MAX(handle_line->coords[0], handle_line->coords[2]);
  if (y1) *y1 = MIN(handle_line->coords[1], handle_line->coords[3]);
  if (y2) *y2 = MAX(handle_line->coords[1], handle_line->coords[3]);
}

