Index: gimp/app/config/gimprc-blurbs.h
===================================================================
RCS file: /cvs/gnome/gimp/app/config/gimprc-blurbs.h,v
retrieving revision 1.48
diff -u -p -r1.48 gimprc-blurbs.h
--- gimp/app/config/gimprc-blurbs.h	4 Jun 2004 23:08:27 -0000	1.48
+++ gimp/app/config/gimprc-blurbs.h	12 Jun 2004 13:47:29 -0000
@@ -291,6 +291,8 @@ N_("When enabled, the selection is visib
 N_("When enabled, the layer boundary is visible by default. This can also " \
    "be toggled with the \"View->Show Layer Boundary\" command.")
 
+#define SHOW_TRANSFORM_PREVIEW_BLURB NULL
+
 #define SHOW_GUIDES_BLURB \
 N_("When enabled, the guides are visible by default. This can also be " \
    "toggled with the \"View->Show Guides\" command.")
Index: gimp/app/display/gimpdisplayoptions.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayoptions.c,v
retrieving revision 1.4
diff -u -p -r1.4 gimpdisplayoptions.c
--- gimp/app/display/gimpdisplayoptions.c	23 Oct 2003 17:02:37 -0000	1.4
+++ gimp/app/display/gimpdisplayoptions.c	12 Jun 2004 13:47:29 -0000
@@ -31,7 +31,6 @@
 #include "display-enums.h"
 
 #include "config/gimpconfig.h"
-#include "config/gimpconfig.h"
 #include "config/gimpconfig-params.h"
 #include "config/gimprc-blurbs.h"
 
@@ -49,6 +48,7 @@ enum
   PROP_SHOW_STATUSBAR,
   PROP_SHOW_SELECTION,
   PROP_SHOW_LAYER_BOUNDARY,
+  PROP_SHOW_TRANSFORM_PREVIEW,
   PROP_SHOW_GUIDES,
   PROP_SHOW_GRID,
   PROP_PADDING_MODE,
@@ -179,6 +179,10 @@ gimp_display_options_class_init (GimpDis
                                     "show-layer-boundary", SHOW_LAYER_BOUNDARY_BLURB,
                                     TRUE,
                                     0);
+  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_SHOW_TRANSFORM_PREVIEW,
+                                    "show-transform-preview", SHOW_TRANSFORM_PREVIEW_BLURB,
+                                    FALSE,
+                                    0);
   GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_SHOW_GUIDES,
                                     "show-guides", SHOW_GUIDES_BLURB,
                                     TRUE,
@@ -233,6 +237,10 @@ gimp_display_options_fs_class_init (Gimp
                                     "show-layer-boundary", SHOW_LAYER_BOUNDARY_BLURB,
                                     FALSE,
                                     0);
+  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_SHOW_TRANSFORM_PREVIEW,
+                                    "show-transform-preview", SHOW_TRANSFORM_PREVIEW_BLURB,
+                                    FALSE,
+                                    0);
   GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_SHOW_GUIDES,
                                     "show-guides", SHOW_GUIDES_BLURB,
                                     FALSE,
@@ -286,6 +294,9 @@ gimp_display_options_set_property (GObje
     case PROP_SHOW_LAYER_BOUNDARY:
       options->show_layer_boundary = g_value_get_boolean (value);
       break;
+    case PROP_SHOW_TRANSFORM_PREVIEW:
+      options->show_transform_preview = g_value_get_boolean (value);
+      break;
     case PROP_SHOW_GUIDES:
       options->show_guides = g_value_get_boolean (value);
       break;
@@ -332,6 +343,9 @@ gimp_display_options_get_property (GObje
       break;
     case PROP_SHOW_LAYER_BOUNDARY:
       g_value_set_boolean (value, options->show_layer_boundary);
+      break;
+    case PROP_SHOW_TRANSFORM_PREVIEW:
+      g_value_set_boolean (value, options->show_transform_preview);
       break;
     case PROP_SHOW_GUIDES:
       g_value_set_boolean (value, options->show_guides);
Index: gimp/app/display/gimpdisplayoptions.h
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayoptions.h,v
retrieving revision 1.2
diff -u -p -r1.2 gimpdisplayoptions.h
--- gimp/app/display/gimpdisplayoptions.h	23 Oct 2003 07:33:15 -0000	1.2
+++ gimp/app/display/gimpdisplayoptions.h	12 Jun 2004 13:47:29 -0000
@@ -48,6 +48,7 @@ struct _GimpDisplayOptions
   /*  GimpCanvas options  */
   gboolean               show_selection;
   gboolean               show_layer_boundary;
+  gboolean               show_transform_preview;
   gboolean               show_guides;
   gboolean               show_grid;
   GimpCanvasPaddingMode  padding_mode;
Index: gimp/app/display/gimpdisplayshell-appearance.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell-appearance.c,v
retrieving revision 1.13
diff -u -p -r1.13 gimpdisplayshell-appearance.c
--- gimp/app/display/gimpdisplayshell-appearance.c	17 May 2004 13:38:01 -0000	1.13
+++ gimp/app/display/gimpdisplayshell-appearance.c	12 Jun 2004 13:47:29 -0000
@@ -320,6 +320,27 @@ gimp_display_shell_get_show_layer (GimpD
 }
 
 void
+gimp_display_shell_set_show_transform (GimpDisplayShell *shell,
+                                       gboolean          show)
+{
+  GimpDisplayOptions *options;
+
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+
+  options = GET_OPTIONS (shell);
+
+  g_object_set (options, "show-transform-preview", show, NULL);
+}
+
+gboolean
+gimp_display_shell_get_show_transform (GimpDisplayShell *shell)
+{
+  g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
+
+  return GET_OPTIONS (shell)->show_transform_preview;
+}
+
+void
 gimp_display_shell_set_show_grid (GimpDisplayShell *shell,
                                   gboolean          show)
 {
Index: gimp/app/display/gimpdisplayshell-appearance.h
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell-appearance.h,v
retrieving revision 1.6
diff -u -p -r1.6 gimpdisplayshell-appearance.h
--- gimp/app/display/gimpdisplayshell-appearance.h	29 Apr 2004 12:52:12 -0000	1.6
+++ gimp/app/display/gimpdisplayshell-appearance.h	12 Jun 2004 13:47:29 -0000
@@ -48,6 +48,10 @@ void       gimp_display_shell_set_show_l
                                                    gboolean          show);
 gboolean   gimp_display_shell_get_show_layer      (GimpDisplayShell *shell);
 
+void       gimp_display_shell_set_show_transform  (GimpDisplayShell *shell,
+                                                   gboolean          show);
+gboolean   gimp_display_shell_get_show_transform  (GimpDisplayShell *shell);
+
 void       gimp_display_shell_set_show_grid       (GimpDisplayShell *shell,
                                                    gboolean          show);
 gboolean   gimp_display_shell_get_show_grid       (GimpDisplayShell *shell);
Index: gimp/app/display/gimpdisplayshell-callbacks.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell-callbacks.c,v
retrieving revision 1.252
diff -u -p -r1.252 gimpdisplayshell-callbacks.c
--- gimp/app/display/gimpdisplayshell-callbacks.c	4 Jun 2004 23:08:27 -0000	1.252
+++ gimp/app/display/gimpdisplayshell-callbacks.c	12 Jun 2004 13:47:30 -0000
@@ -387,6 +387,9 @@ gimp_display_shell_canvas_expose (GtkWid
 
   g_free (rects);
 
+  /* draw the transform tool preview */
+  gimp_display_shell_draw_transform_preview (shell);
+  
   /* draw the guides */
   gimp_display_shell_draw_guides (shell);
 
@@ -667,7 +670,7 @@ gimp_display_shell_canvas_tool_events (G
             event_mask = (GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK);
 
             if (active_tool &&
-                (! GIMP_DISPLAY_CONFIG (gimp->config)->perfect_mouse &&
+                (! GIMP_DISPLAY_CONFIG (gimp->config)->perfect_mouse ||
                  (gimp_tool_control_motion_mode (active_tool->control) !=
                   GIMP_MOTION_MODE_EXACT)))
               {
Index: gimp/app/display/gimpdisplayshell-draw.c
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell-draw.c,v
retrieving revision 1.307
diff -u -p -r1.307 gimpdisplayshell-draw.c
--- gimp/app/display/gimpdisplayshell-draw.c	27 May 2004 14:51:44 -0000	1.307
+++ gimp/app/display/gimpdisplayshell-draw.c	12 Jun 2004 13:47:30 -0000
@@ -21,12 +21,19 @@
 #include <gtk/gtk.h>
 
 #include "display-types.h"
+#include "tools/tools-types.h"
 
 #include "core/gimp-utils.h"
 #include "core/gimpgrid.h"
 #include "core/gimpimage.h"
 #include "core/gimpimage-guides.h"
 #include "core/gimplist.h"
+#include "core/gimpdrawable.h"
+
+#include "base/tile-manager.h"
+
+#include "tools/gimptransformtool.h"
+#include "tools/tool_manager.h"
 
 #include "vectors/gimpstroke.h"
 #include "vectors/gimpvectors.h"
@@ -44,9 +51,29 @@
 
 /*  local function prototypes  */
 
-static GdkGC * gimp_display_shell_get_grid_gc (GimpDisplayShell *shell,
-                                               GimpGrid         *grid);
-
+static GdkGC * gimp_display_shell_get_grid_gc     (GimpDisplayShell *shell,
+                                                   GimpGrid         *grid);
+static void    gimp_display_shell_draw_quad       (GimpDrawable     *texture,
+                                                   GdkDrawable      *dest,
+                                                   gint             *x,
+                                                   gint             *y,
+                                                   gfloat           *u,
+                                                   gfloat           *v);
+static void    gimp_display_shell_draw_quad_row   (GimpDrawable     *texture,
+                                                   GdkDrawable      *dest,
+                                                   GdkPixbuf        *row,
+                                                   gint              x1,
+                                                   gfloat            u1,
+                                                   gfloat            v1,
+                                                   gint              x2,
+                                                   gfloat            u2,
+                                                   gfloat            v2,
+                                                   gint              y);
+static void    gimp_display_shell_trace_quad_edge (gint             *dest,
+                                                   gint              x1,
+                                                   gint              y1,
+                                                   gint              x2,
+                                                   gint              y2);
 
 /*  public functions  */
 
@@ -287,6 +314,70 @@ gimp_display_shell_draw_grid (GimpDispla
 }
 
 void
+gimp_display_shell_draw_transform_preview (GimpDisplayShell *shell)
+{
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+  
+  if (gimp_display_shell_get_show_transform (shell))
+    {
+      GimpTool          *tool;
+      GimpTransformTool *tr_tool;
+      gdouble            z1, z2, z3, z4;
+
+      tool = tool_manager_get_active (shell->gdisp->gimage->gimp);
+
+      if (! GIMP_IS_TRANSFORM_TOOL (tool))
+        return;
+
+      tr_tool = GIMP_TRANSFORM_TOOL (tool);
+
+      if (! tr_tool->use_grid)
+        return;
+      
+      z1 = ((tr_tool->tx2 - tr_tool->tx1) * (tr_tool->ty4 - tr_tool->ty1) -
+            (tr_tool->tx4 - tr_tool->tx1) * (tr_tool->ty2 - tr_tool->ty1));
+      z2 = ((tr_tool->tx4 - tr_tool->tx1) * (tr_tool->ty3 - tr_tool->ty1) -
+            (tr_tool->tx3 - tr_tool->tx1) * (tr_tool->ty4 - tr_tool->ty1));
+      z3 = ((tr_tool->tx4 - tr_tool->tx2) * (tr_tool->ty3 - tr_tool->ty2) -
+            (tr_tool->tx3 - tr_tool->tx2) * (tr_tool->ty4 - tr_tool->ty2));
+      z4 = ((tr_tool->tx3 - tr_tool->tx2) * (tr_tool->ty1 - tr_tool->ty2) -
+            (tr_tool->tx1 - tr_tool->tx2) * (tr_tool->ty3 - tr_tool->ty2));
+
+      /* only draw convex polygons */
+
+      if ((z1 * z2 > 0) && (z3 * z4 > 0))
+        {      
+          gdouble dx [4];
+          gdouble dy [4];
+          gint    x [4];
+          gint    y [4];
+          gfloat  u [4] = {0, 1, 0, 1};
+          gfloat  v [4] = {0, 0, 1, 1};
+          gint    i;
+
+          gimp_display_shell_transform_xy_f (shell, tr_tool->tx1, tr_tool->ty1,
+                                             dx + 0, dy + 0, FALSE);
+          gimp_display_shell_transform_xy_f (shell, tr_tool->tx2, tr_tool->ty2,
+                                             dx + 1, dy + 1, FALSE);
+          gimp_display_shell_transform_xy_f (shell, tr_tool->tx3, tr_tool->ty3,
+                                             dx + 2, dy + 2, FALSE);
+          gimp_display_shell_transform_xy_f (shell, tr_tool->tx4, tr_tool->ty4,
+                                             dx + 3, dy + 3, FALSE);
+
+          for (i = 0; i < 4; i++)
+            {
+              x [i] = (gint) dx [i];
+              y [i] = (gint) dy [i];
+            }
+
+          gimp_display_shell_draw_quad (tool->drawable,
+                              GDK_DRAWABLE (GTK_WIDGET (shell->canvas)->window),
+                              x, y, u, v);
+        }
+    }
+}
+      
+void
 gimp_display_shell_draw_vector (GimpDisplayShell *shell,
                                 GimpVectors      *vectors)
 {
@@ -474,3 +565,445 @@ gimp_display_shell_get_grid_gc (GimpDisp
 
   return shell->grid_gc;
 }
+
+static void
+gimp_display_shell_draw_quad (GimpDrawable *texture,
+                              GdkDrawable  *dest,
+                              gint         *x,
+                              gint         *y,
+                              gfloat       *u, /* texture coords */
+                              gfloat       *v) /* 0.0 ... 1.0 */
+{
+  GdkPixbuf   *row;
+  gint         dwidth, dheight;    /* clip boundary */
+  gint         j, k;
+  gint         ry;
+  gint        *l_edge, *r_edge;    /* arrays holding x-coords of edge pixels */
+  gint        *left,   *right;
+  gfloat       dul, dvl, dur, dvr; /* left and right texture coord deltas */
+  gfloat       u_l, v_l, u_r, v_r; /* left and right texture coord pairs */
+ 
+  if (! GIMP_IS_DRAWABLE (texture) ||
+      ! GDK_IS_DRAWABLE (dest))
+    return;
+
+  g_return_if_fail (x != NULL && y != NULL && u != NULL && v != NULL);
+
+  left = right = NULL;
+  dul = dvl = dur = dvr = 0;
+  u_l = v_l = u_r = v_r = 0;
+
+  gdk_drawable_get_size (dest, &dwidth, &dheight);
+
+  /* is the preview in the window? */
+  {
+    gboolean in_window_x, in_window_y;
+
+    in_window_x = in_window_y = FALSE;
+    for (j = 0; j < 4; j++)
+      {
+        if (x [j] >= 0)
+          in_window_x = TRUE;
+        if (y [j] >= 0)
+          in_window_y = TRUE;
+      }
+    if (! (in_window_x && in_window_y))
+      return;
+    
+    in_window_x = in_window_y = FALSE;
+    for (j = 0; j < 4; j++)
+      {
+        if (x [j] < dwidth)
+          in_window_x = TRUE;
+        if (y [j] < dheight)
+          in_window_y = TRUE;
+      }
+    if (! (in_window_x && in_window_y))
+      return;
+  }
+
+  row = gdk_pixbuf_new (GDK_COLORSPACE_RGB, gimp_drawable_has_alpha (texture),
+                        8, dwidth, 1);
+  if (row == NULL) return;
+
+  /* scale texture coords to fit the source drawable */
+  
+  for (j = 0; j < 4; j++)
+    {
+      u [j] *= tile_manager_width (texture->tiles);
+      v [j] *= tile_manager_height (texture->tiles);
+    }
+  
+  /* sort vertices in order of y-coordinate */
+
+  for (j = 0; j < 4; j++)
+    for (k = j + 1; k < 4; k++)
+      if (y [k] < y [j])
+        {
+          gint tmp;
+          gfloat ftmp;
+          
+          tmp  = y [k];  y [k] = y [j];  y [j] = tmp;
+          tmp  = x [k];  x [k] = x [j];  x [j] = tmp;
+          ftmp = u [k];  u [k] = u [j];  u [j] = ftmp;
+          ftmp = v [k];  v [k] = v [j];  v [j] = ftmp;
+        }
+  
+  if (y [3] == y [0])
+    return;
+  
+  l_edge = g_malloc ((y [3] - y [0]) * sizeof (gint));
+  r_edge = g_malloc ((y [3] - y [0]) * sizeof (gint));
+
+  /* draw the quad */
+
+#define QUAD_TRACE_L_EDGE(a, b) \
+      if (y [a] != y [b]) \
+        { \
+          gimp_display_shell_trace_quad_edge (l_edge, \
+                                              x [a], y [a], \
+                                              x [b], y [b]); \
+          left = l_edge; \
+          dul  = (u [b] - u [a]) / (y [b] - y [a]); \
+          dvl  = (v [b] - v [a]) / (y [b] - y [a]); \
+          u_l  = u [a]; \
+          v_l  = v [a]; \
+        }
+
+#define QUAD_TRACE_R_EDGE(a, b) \
+      if (y [a] != y [b]) \
+        { \
+          gimp_display_shell_trace_quad_edge (r_edge, \
+                                              x [a], y [a], \
+                                              x [b], y [b]); \
+          right = r_edge; \
+          dur   = (u [b] - u [a]) / (y [b] - y [a]); \
+          dvr   = (v [b] - v [a]) / (y [b] - y [a]); \
+          u_r   = u [a]; \
+          v_r   = v [a]; \
+        }
+
+#define QUAD_DRAW_SECTION(a, b) \
+      if (y [a] != y [b]) \
+        for (ry = y [a]; ry < y [b]; ry++) \
+          { \
+            if (ry >= 0 && ry < dheight) \
+              gimp_display_shell_draw_quad_row (texture, dest, row, \
+                                                *left, u_l, v_l, \
+                                                *right, u_r, v_r, \
+                                                ry); \
+            left ++; \
+            right ++; \
+            u_l += dul; \
+            v_l += dvl; \
+            u_r += dur; \
+            v_r += dvr; \
+          } \
+
+  if (((x [0] > x [1]) && (x [3] > x [2])) ||
+      ((x [0] < x [1]) && (x [3] < x [2])))
+    {
+      /*
+       *     v0
+       *       |--__
+       * _____ |....--_ v2 ____
+       *       |       |
+       *       |       |
+       * _____ |.....__| ______
+       *       |__---   v3
+       *     v3
+       */
+    
+      QUAD_TRACE_L_EDGE (0, 3);
+      
+      QUAD_TRACE_R_EDGE (0, 1);
+      QUAD_DRAW_SECTION (0, 1);  /* top section */
+
+      QUAD_TRACE_R_EDGE (1, 2);
+      QUAD_DRAW_SECTION (1, 2);  /* middle section */
+
+      QUAD_TRACE_R_EDGE (2, 3);
+      QUAD_DRAW_SECTION (2, 3);  /* bottom section */
+    }
+  else
+    {
+      /*
+       *           v0
+       *           /-___
+       * -------- /.....-- v1 ---
+       *         /       /
+       * ___ v2 /__...../________
+       *           ---_/
+       *               v3
+       */
+    
+      QUAD_TRACE_L_EDGE (0, 2);
+  
+      QUAD_TRACE_R_EDGE (0, 1);
+      QUAD_DRAW_SECTION (0, 1);  /* top section */
+  
+      QUAD_TRACE_R_EDGE (1, 3);
+  
+      QUAD_DRAW_SECTION (1, 2);  /* middle section */
+  
+      QUAD_TRACE_L_EDGE (2, 3);
+      QUAD_DRAW_SECTION (2, 3);  /* bottom section */
+    }
+
+#undef QUAD_TRACE_L_EDGE
+#undef QUAD_TRACE_R_EDGE
+#undef QUAD_DRAW_SECTION
+  
+  g_object_unref (row);
+  g_free (l_edge);
+  g_free (r_edge);
+}
+
+static void
+gimp_display_shell_draw_quad_row (GimpDrawable *texture,
+                                  GdkDrawable  *dest,
+                                  GdkPixbuf    *row,
+                                  gint          x1,
+                                  gfloat        u1,
+                                  gfloat        v1,
+                                  gint          x2,
+                                  gfloat        u2,
+                                  gfloat        v2,
+                                  gint          y)
+{
+  TileManager *tiles;
+  guchar      *pptr;
+  gchar        bytes;
+  gfloat       u, v;
+  gfloat       du, dv;
+  gint         dx;
+  guchar       pixel [4];
+  guchar      *cmap;
+  gint         offset;
+
+  if (! (x2 - x1))
+    return;
+  
+  g_return_if_fail (GIMP_IS_DRAWABLE (texture));
+  g_return_if_fail (GDK_IS_DRAWABLE (dest));
+  g_return_if_fail (GDK_IS_PIXBUF (row));
+  g_return_if_fail (gdk_pixbuf_get_bits_per_sample (row) == 8);
+  g_return_if_fail (gdk_pixbuf_get_colorspace (row) == GDK_COLORSPACE_RGB);
+  g_return_if_fail (gdk_pixbuf_get_has_alpha (row) ==
+                    gimp_drawable_has_alpha (texture));
+
+  bytes = gdk_pixbuf_get_n_channels (row);
+  pptr  = gdk_pixbuf_get_pixels (row);
+  tiles = gimp_drawable_data (texture);
+  
+  if (x1 > x2)
+    {
+      gint tmp;
+      gfloat ftmp;
+      
+      tmp  = x2;  x2 = x1;  x1 = tmp;
+      ftmp = u2;  u2 = u1;  u1 = ftmp;
+      ftmp = v2;  v2 = v1;  v1 = ftmp;
+    }
+
+  u = u1;
+  v = v1;
+  du = (u2 - u1) / (x2 - x1);
+  dv = (v2 - v1) / (x2 - x1);
+
+  /* don't calculate unseen pixels */
+  if (x1 < 0)
+    {
+      u += du * (0 - x1);
+      v += dv * (0 - x1);
+      x1 = 0;
+    }
+  else if (x1 > gdk_pixbuf_get_width (row))
+    return;
+  if (x2 < 0)
+    return;
+  else if (x2 > gdk_pixbuf_get_width (row))
+    x2 = gdk_pixbuf_get_width (row);
+
+  
+  dx = x2 - x1;
+
+  switch (gimp_drawable_type (texture))
+    {
+    case GIMP_INDEXED_IMAGE:
+      cmap = gimp_drawable_cmap (texture);
+      
+      while (dx --)
+        {
+          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+          offset = pixel [0] + pixel [0] + pixel [0];
+          
+          *pptr++ = cmap [offset];
+          *pptr++ = cmap [offset + 1];
+          *pptr++ = cmap [offset + 2];
+
+          u += du;
+          v += dv;
+        }
+      break;
+
+    case GIMP_INDEXEDA_IMAGE:
+      cmap = gimp_drawable_cmap (texture);
+      
+      while (dx --)
+        {
+          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+          offset = pixel [0] + pixel [0] + pixel [0];
+          
+          *pptr++ = cmap [offset];
+          *pptr++ = cmap [offset + 1];
+          *pptr++ = cmap [offset + 2];
+          *pptr++ = pixel [1];
+
+          u += du;
+          v += dv;
+        }
+      break;
+
+    case GIMP_GRAY_IMAGE:
+      while (dx --)
+        {
+          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+
+          *pptr++ = pixel [0];
+          *pptr++ = pixel [0];
+          *pptr++ = pixel [0];
+
+          u += du;
+          v += dv;
+        }
+      break;
+
+    case GIMP_GRAYA_IMAGE:
+      while (dx --)
+        {
+          read_pixel_data_1 (tiles, (gint) u, (gint) v, pixel);
+          
+          *pptr++ = pixel [0];
+          *pptr++ = pixel [0];
+          *pptr++ = pixel [0];
+          *pptr++ = pixel [1];
+          
+          u += du;
+          v += dv;
+        }
+      break;
+
+    case GIMP_RGB_IMAGE:
+    case GIMP_RGBA_IMAGE:      
+      while (dx --)
+        {
+          read_pixel_data_1 (tiles, (gint) u, (gint) v, pptr);
+
+          pptr += bytes;
+          u += du;
+          v += dv;
+        }
+      break;
+
+    default:
+      return;
+    }
+
+  gdk_draw_pixbuf (dest, NULL, row, 0, 0, x1, y, x2 - x1, 1,
+                   GDK_RGB_DITHER_NONE, 0, 0);
+}
+
+static void
+gimp_display_shell_trace_quad_edge (gint *dest,
+                                    gint  x1,
+                                    gint  y1,
+                                    gint  x2,
+                                    gint  y2)
+{
+  const gint  dy = y2 - y1;
+  gint        dx;
+  gchar       xdir;
+  gint        errorterm;
+  gint        b;
+  gint       *dptr;
+
+  if (dy == 0) 
+    return;
+  
+  g_return_if_fail (dest != NULL);
+  
+  b         = 0;
+  errorterm = 0;
+  dptr      = dest;
+  
+  if (x2 < x1)
+    {
+      dx = x1 - x2;
+      xdir = -1;
+    }
+  else
+    {
+      dx = x2 - x1;
+      xdir = 1;
+    }
+
+  if (dx >= dy)
+    {
+      b = dy;
+      while (b --)
+        {
+          *dptr = x1;
+          errorterm += dx;
+          
+          while (errorterm > dy)
+            {
+              x1 += xdir;
+              errorterm -= dy;
+            }
+          
+          dptr ++;
+        }
+    }
+  else if (dy >= dx)
+    {
+      b = dy;
+      while (b --)
+        {
+          *dptr = x1;
+          errorterm += dx;
+          
+          if (errorterm > dy)
+            {
+              x1 += xdir;
+              errorterm -= dy;
+            }
+          
+          dptr ++;
+        }
+    }
+  else if (dx == 0)
+    {
+      b = dy;
+      while (b --)
+        {
+          *dptr = x1;
+          
+          dptr ++;
+        }
+    }
+  else /* dy == dx */
+    {
+      b = dy;
+      while (b --)
+        {
+          *dptr = x1;
+          x1 += xdir;
+          
+          dptr ++;
+        }
+    }
+}
+
Index: gimp/app/display/gimpdisplayshell-draw.h
===================================================================
RCS file: /cvs/gnome/gimp/app/display/gimpdisplayshell-draw.h,v
retrieving revision 1.72
diff -u -p -r1.72 gimpdisplayshell-draw.h
--- gimp/app/display/gimpdisplayshell-draw.h	4 Apr 2004 17:17:40 -0000	1.72
+++ gimp/app/display/gimpdisplayshell-draw.h	12 Jun 2004 13:47:30 -0000
@@ -20,21 +20,23 @@
 #define __GIMP_DISPLAY_SHELL_DRAW_H__
 
 
-void   gimp_display_shell_draw_guide   (GimpDisplayShell   *shell,
-                                        GimpGuide          *guide,
-                                        gboolean            active);
-void   gimp_display_shell_draw_guides  (GimpDisplayShell   *shell);
-void   gimp_display_shell_draw_grid    (GimpDisplayShell   *shell,
-                                        const GdkRectangle *area);
-void   gimp_display_shell_draw_vector  (GimpDisplayShell   *shell,
-                                        GimpVectors        *vectors);
-void   gimp_display_shell_draw_vectors (GimpDisplayShell   *shell);
-void   gimp_display_shell_draw_cursor  (GimpDisplayShell   *shell);
-void   gimp_display_shell_draw_area    (GimpDisplayShell   *shell,
-                                        gint                x,
-                                        gint                y,
-                                        gint                w,
-                                        gint                h);
+void   gimp_display_shell_draw_guide             (GimpDisplayShell   *shell,
+                                                  GimpGuide          *guide,
+                                                  gboolean            active);
+void   gimp_display_shell_draw_guides            (GimpDisplayShell   *shell);
+void   gimp_display_shell_draw_grid              (GimpDisplayShell   *shell,
+                                                  const GdkRectangle *area);
+void   gimp_display_shell_draw_transform_preview (GimpDisplayShell *shell);
+
+void   gimp_display_shell_draw_vector            (GimpDisplayShell   *shell,
+                                                  GimpVectors        *vectors);
+void   gimp_display_shell_draw_vectors           (GimpDisplayShell   *shell);
+void   gimp_display_shell_draw_cursor            (GimpDisplayShell   *shell);
+void   gimp_display_shell_draw_area              (GimpDisplayShell   *shell,
+                                                  gint                x,
+                                                  gint                y,
+                                                  gint                w,
+                                                  gint                h);
 
 
 #endif /* __GIMP_DISPLAY_SHELL_DRAW_H__ */
Index: gimp/app/tools/gimpperspectivetool.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimpperspectivetool.c,v
retrieving revision 1.73
diff -u -p -r1.73 gimpperspectivetool.c
--- gimp/app/tools/gimpperspectivetool.c	4 Jun 2004 23:08:28 -0000	1.73
+++ gimp/app/tools/gimpperspectivetool.c	12 Jun 2004 13:47:30 -0000
@@ -209,6 +209,8 @@ gimp_perspective_tool_motion (GimpTransf
     default:
       break;
     }
+
+  gimp_transform_tool_expose_preview (transform_tool);
 }
 
 static void
Index: gimp/app/tools/gimprotatetool.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimprotatetool.c,v
retrieving revision 1.95
diff -u -p -r1.95 gimprotatetool.c
--- gimp/app/tools/gimprotatetool.c	4 Jun 2004 23:08:28 -0000	1.95
+++ gimp/app/tools/gimprotatetool.c	12 Jun 2004 13:47:30 -0000
@@ -270,6 +270,8 @@ gimp_rotate_tool_motion (GimpTransformTo
       tr_tool->cx                   = tr_tool->curx;
       tr_tool->cy                   = tr_tool->cury;
 
+      gimp_transform_tool_expose_preview (tr_tool);
+      
       return;
     }
 
@@ -317,6 +319,8 @@ gimp_rotate_tool_motion (GimpTransformTo
     {
       tr_tool->trans_info[ANGLE] = tr_tool->trans_info[REAL_ANGLE];
     }
+
+  gimp_transform_tool_expose_preview (tr_tool);
 }
 
 static void
@@ -372,6 +376,8 @@ rotate_angle_changed (GtkWidget         
 
       gimp_rotate_tool_recalc (tr_tool, GIMP_TOOL (tr_tool)->gdisp);
 
+      gimp_transform_tool_expose_preview (tr_tool);
+      
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
     }
 
@@ -400,6 +406,8 @@ rotate_center_changed (GtkWidget        
 
       gimp_rotate_tool_recalc (tr_tool, GIMP_TOOL (tr_tool)->gdisp);
 
+      gimp_transform_tool_expose_preview (tr_tool);
+      
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
     }
 }
Index: gimp/app/tools/gimpscaletool.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimpscaletool.c,v
retrieving revision 1.96
diff -u -p -r1.96 gimpscaletool.c
--- gimp/app/tools/gimpscaletool.c	4 Jun 2004 23:08:28 -0000	1.96
+++ gimp/app/tools/gimpscaletool.c	12 Jun 2004 13:47:30 -0000
@@ -320,6 +320,9 @@ gimp_scale_tool_motion (GimpTransformToo
       tr_tool->trans_info[Y2] += diff_y;
       tr_tool->trans_info[X3] += diff_x;
       tr_tool->trans_info[Y3] += diff_y;
+
+      gimp_transform_tool_expose_preview (tr_tool);
+      
       return;
 
     default:
@@ -377,6 +380,8 @@ gimp_scale_tool_motion (GimpTransformToo
       *y1 = *y2 - dir_y * h;
       *x1 = *x2 - dir_x * w;
     }
+
+  gimp_transform_tool_expose_preview (tr_tool);
 }
 
 static void
@@ -490,6 +495,8 @@ gimp_scale_tool_size_changed (GtkWidget 
       tr_tool->trans_info[Y1] = tr_tool->trans_info[Y0] + height;
 
       gimp_scale_tool_recalc (tr_tool, GIMP_TOOL (tr_tool)->gdisp);
+
+      gimp_transform_tool_expose_preview (tr_tool);
 
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
     }
Index: gimp/app/tools/gimpsheartool.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimpsheartool.c,v
retrieving revision 1.78
diff -u -p -r1.78 gimpsheartool.c
--- gimp/app/tools/gimpsheartool.c	4 Jun 2004 23:08:28 -0000	1.78
+++ gimp/app/tools/gimpsheartool.c	12 Jun 2004 13:47:30 -0000
@@ -262,6 +262,8 @@ gimp_shear_tool_motion (GimpTransformToo
 	  break;
 	}
     }
+
+  gimp_transform_tool_expose_preview (tr_tool);
 }
 
 static void
@@ -318,6 +320,8 @@ shear_x_mag_changed (GtkWidget         *
 
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
     }
+
+  gimp_transform_tool_expose_preview (tr_tool);
 }
 
 static void
@@ -338,4 +342,6 @@ shear_y_mag_changed (GtkWidget         *
 
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
     }
+  
+  gimp_transform_tool_expose_preview (tr_tool);
 }
Index: gimp/app/tools/gimptransformoptions.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimptransformoptions.c,v
retrieving revision 1.40
diff -u -p -r1.40 gimptransformoptions.c
--- gimp/app/tools/gimptransformoptions.c	4 May 2004 21:11:06 -0000	1.40
+++ gimp/app/tools/gimptransformoptions.c	12 Jun 2004 13:47:30 -0000
@@ -51,6 +51,7 @@ enum
   PROP_SUPERSAMPLE,
   PROP_RECURSION_LEVEL,
   PROP_CLIP,
+  PROP_SHOW_PREVIEW,
   PROP_GRID_TYPE,
   PROP_GRID_SIZE,
   PROP_CONSTRAIN_1,
@@ -162,6 +163,10 @@ gimp_transform_options_class_init (GimpT
                                     "clip", NULL,
                                     FALSE,
                                     0);
+  GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_SHOW_PREVIEW,
+                                    "show-preview", NULL,
+                                    FALSE,
+                                    0);
   GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_GRID_TYPE,
                                  "grid-type", NULL,
                                  GIMP_TYPE_TRANSFORM_GRID_TYPE,
@@ -216,6 +221,9 @@ gimp_transform_options_set_property (GOb
     case PROP_CLIP:
       options->clip = g_value_get_boolean (value);
       break;
+    case PROP_SHOW_PREVIEW:
+      options->show_preview = g_value_get_boolean (value);
+      break;
     case PROP_GRID_TYPE:
       options->grid_type = g_value_get_enum (value);
       break;
@@ -264,6 +272,9 @@ gimp_transform_options_get_property (GOb
     case PROP_CLIP:
       g_value_set_boolean (value, options->clip);
       break;
+    case PROP_SHOW_PREVIEW:
+      g_value_set_boolean (value, options->show_preview);
+      break;
     case PROP_GRID_TYPE:
       g_value_set_enum (value, options->grid_type);
       break;
@@ -359,6 +370,11 @@ gimp_transform_options_gui (GimpToolOpti
   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
   gtk_widget_show (button);
 
+  /* the preview toggle button */
+  button = gimp_prop_check_button_new (config, "show-preview", _("Preview"));
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+  
   /*  the grid frame  */
   frame = gimp_frame_new (NULL);
   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
Index: gimp/app/tools/gimptransformoptions.h
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimptransformoptions.h,v
retrieving revision 1.17
diff -u -p -r1.17 gimptransformoptions.h
--- gimp/app/tools/gimptransformoptions.h	13 Mar 2004 17:45:56 -0000	1.17
+++ gimp/app/tools/gimptransformoptions.h	12 Jun 2004 13:47:30 -0000
@@ -44,6 +44,7 @@ struct _GimpTransformOptions
   gboolean                supersample;
   gint                    recursion_level;
   gboolean                clip;
+  gboolean                show_preview;
   GimpTransformGridType   grid_type;
   gint                    grid_size;
   gboolean                constrain_1;
Index: gimp/app/tools/gimptransformtool.c
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimptransformtool.c,v
retrieving revision 1.121
diff -u -p -r1.121 gimptransformtool.c
--- gimp/app/tools/gimptransformtool.c	4 Jun 2004 23:08:29 -0000	1.121
+++ gimp/app/tools/gimptransformtool.c	12 Jun 2004 13:47:30 -0000
@@ -48,6 +48,9 @@
 
 #include "display/gimpdisplay.h"
 #include "display/gimpprogress.h"
+#include "display/gimpdisplayshell.h"
+#include "display/gimpdisplayshell-appearance.h"
+#include "display/gimpdisplayshell-transform.h"
 
 #ifdef __GNUC__
 #warning FIXME #include "gui/gui-types.h"
@@ -133,13 +136,15 @@ static void     gimp_transform_tool_resp
                                                     gint               response_id,
                                                     GimpTransformTool *tr_tool);
 
-static void     gimp_transform_tool_notify_type (GimpTransformOptions *options,
-                                                 GParamSpec           *pspec,
-                                                 GimpTransformTool    *tr_tool);
-static void     gimp_transform_tool_notify_grid (GimpTransformOptions *options,
-                                                 GParamSpec           *pspec,
-                                                 GimpTransformTool    *tr_tool);
-
+static void     gimp_transform_tool_notify_type    (GimpTransformOptions *options,
+                                                    GParamSpec           *pspec,
+                                                    GimpTransformTool    *tr_tool);
+static void     gimp_transform_tool_notify_grid    (GimpTransformOptions *options,
+                                                    GParamSpec           *pspec,
+                                                    GimpTransformTool    *tr_tool);
+static void     gimp_transform_tool_notify_preview (GimpTransformOptions *options,
+                                                    GParamSpec           *pspec,
+                                                    GimpTransformTool    *tr_tool);
 
 static GimpDrawToolClass *parent_class = NULL;
 
@@ -282,6 +287,10 @@ gimp_transform_tool_constructor (GType  
                                "notify::grid-size",
                                G_CALLBACK (gimp_transform_tool_notify_grid),
                                tr_tool, 0);
+      g_signal_connect_object (tool->tool_info->tool_options,
+                               "notify::show-preview",
+                               G_CALLBACK (gimp_transform_tool_notify_preview),
+                               tr_tool, 0);
     }
 
   return object;
@@ -707,14 +716,14 @@ gimp_transform_tool_draw (GimpDrawTool *
       k = tr_tool->ngx + tr_tool->ngy;
 
       for (i = 0, gci = 0; i < k; i++, gci += 4)
-	{
+        {
           gimp_draw_tool_draw_line (draw_tool,
                                     tr_tool->tgrid_coords[gci],
                                     tr_tool->tgrid_coords[gci + 1],
                                     tr_tool->tgrid_coords[gci + 2],
                                     tr_tool->tgrid_coords[gci + 3],
                                     FALSE);
-	}
+        }
     }
 
   /*  draw the tool handles  */
@@ -1070,11 +1079,92 @@ gimp_transform_tool_transform_bounding_b
     }
 }
 
+void
+gimp_transform_tool_expose_preview (GimpTransformTool *tr_tool)
+{
+  static gint           last_x = 0,
+                        last_y = 0,
+                        last_w = 0,
+                        last_h = 0;
+  GimpDisplayShell     *shell;
+  GimpTransformOptions *options;
+  gdouble               dx [4], dy [4];
+  gint                  area_x, area_y, area_w, area_h;
+  gint                  i;
+
+  g_return_if_fail (GIMP_IS_TRANSFORM_TOOL (tr_tool));
+  
+  options = GIMP_TRANSFORM_OPTIONS (GIMP_TOOL (tr_tool)->tool_info->tool_options);
+  
+  if (! (tr_tool->use_grid && options->show_preview))
+    return;
+  
+  g_return_if_fail (GIMP_IS_DISPLAY (GIMP_DRAW_TOOL (tr_tool)->gdisp));
+
+  shell = GIMP_DISPLAY_SHELL (GIMP_DRAW_TOOL (tr_tool)->gdisp->shell);
+
+  gimp_display_shell_transform_xy_f (shell, tr_tool->tx1, tr_tool->ty1,
+                                     dx + 0, dy + 0, FALSE);
+  gimp_display_shell_transform_xy_f (shell, tr_tool->tx2, tr_tool->ty2,
+                                     dx + 1, dy + 1, FALSE);
+  gimp_display_shell_transform_xy_f (shell, tr_tool->tx3, tr_tool->ty3,
+                                     dx + 2, dy + 2, FALSE);
+  gimp_display_shell_transform_xy_f (shell, tr_tool->tx4, tr_tool->ty4,
+                                     dx + 3, dy + 3, FALSE);
+
+  /* find bounding box around preview */
+  area_x = area_w = (gint) dx [0];
+  area_y = area_h = (gint) dy [0];
+    
+  for (i = 1; i < 4; i++)
+    {
+      if (dx [i] < area_x)
+        area_x = (gint) dx [i];
+      else if (dx [i] > area_w)
+        area_w = (gint) dx [i];
+    
+      if (dy [i] < area_y)
+        area_y = (gint) dy [i];
+      else if (dy [i] > area_h)
+        area_h = (gint) dy [i];
+    }
+      
+  area_w -= area_x;
+  area_h -= area_y;
+          
+  gimp_display_shell_expose_area (shell,
+                                  MIN (area_x, last_x),
+                                  MIN (area_y, last_y),
+                                  MAX (area_w, last_w) + ABS (last_x - area_x),
+                                  MAX (area_h, last_h) + ABS (last_y - area_y));
+
+  /* area of last preview must be re-exposed to avoid leaving artifacts */
+  last_x = area_x;
+  last_y = area_y;
+  last_w = area_w;
+  last_h = area_h;
+}
+
 static void
 gimp_transform_tool_halt (GimpTransformTool *tr_tool)
 {
   GimpTool *tool = GIMP_TOOL (tr_tool);
 
+  if (GIMP_IS_DISPLAY (GIMP_DRAW_TOOL (tr_tool)->gdisp))
+    {
+      GimpDisplayShell *shell;
+    
+      shell = GIMP_DISPLAY_SHELL (GIMP_DRAW_TOOL (tr_tool)->gdisp->shell);
+
+      if (gimp_display_shell_get_show_transform (shell))
+        {
+          gimp_display_shell_set_show_transform (shell, FALSE);
+      
+          /* get rid of preview artifacts left outside the drawable's area */
+          gimp_transform_tool_expose_preview (tr_tool);
+        }
+    }
+
   if (tr_tool->original)
     {
       tile_manager_unref (tr_tool->original);
@@ -1295,6 +1385,12 @@ static void
 gimp_transform_tool_prepare (GimpTransformTool *tr_tool,
                              GimpDisplay       *gdisp)
 {
+  GimpTransformOptions *options;
+  
+  options = GIMP_TRANSFORM_OPTIONS (GIMP_TOOL (tr_tool)->tool_info->tool_options);
+  gimp_display_shell_set_show_transform (GIMP_DISPLAY_SHELL (gdisp->shell),
+                                         options->show_preview);
+
   if (tr_tool->info_dialog)
     {
       gimp_viewable_dialog_set_viewable (GIMP_VIEWABLE_DIALOG (tr_tool->info_dialog->shell),
@@ -1340,6 +1436,9 @@ gimp_transform_tool_response (GtkWidget 
         /*  recalculate the tool's transformation matrix  */
         gimp_transform_tool_recalc (tr_tool, tool->gdisp);
 
+        /* update preview */
+        gimp_transform_tool_expose_preview (tr_tool);
+
         gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
       }
       break;
@@ -1389,3 +1488,28 @@ gimp_transform_tool_notify_grid (GimpTra
 
   gimp_draw_tool_resume (GIMP_DRAW_TOOL (tr_tool));
 }
+
+static void
+gimp_transform_tool_notify_preview (GimpTransformOptions *options,
+                                    GParamSpec           *pspec,
+                                    GimpTransformTool    *tr_tool)
+{
+  GimpDisplayShell *shell;
+  gboolean          show_preview;
+
+  if (! GIMP_IS_DISPLAY (GIMP_DRAW_TOOL (tr_tool)->gdisp))
+      return;
+  
+  shell = GIMP_DISPLAY_SHELL (GIMP_DRAW_TOOL (tr_tool)->gdisp->shell);
+  
+  gimp_display_shell_set_show_transform (shell, options->show_preview);
+
+  /* expose area to clean up if preview is being turned off */
+  show_preview = options->show_preview;
+  options->show_preview = TRUE;
+  
+  gimp_transform_tool_expose_preview (tr_tool);
+
+  options->show_preview = show_preview;
+}
+
Index: gimp/app/tools/gimptransformtool.h
===================================================================
RCS file: /cvs/gnome/gimp/app/tools/gimptransformtool.h,v
retrieving revision 1.32
diff -u -p -r1.32 gimptransformtool.h
--- gimp/app/tools/gimptransformtool.h	20 Oct 2003 21:27:27 -0000	1.32
+++ gimp/app/tools/gimptransformtool.h	12 Jun 2004 13:47:30 -0000
@@ -120,6 +120,6 @@ struct _GimpTransformToolClass
 GType   gimp_transform_tool_get_type               (void) G_GNUC_CONST;
 
 void    gimp_transform_tool_transform_bounding_box (GimpTransformTool *tr_tool);
-
+void    gimp_transform_tool_expose_preview         (GimpTransformTool *tr_tool);
 
 #endif  /*  __GIMP_TRANSFORM_TOOL_H__  */
