gimpdrawablepreview.c 22 KB
Newer Older
1 2 3 4 5
/* LIBGIMP - The GIMP Library
 * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
 *
 * gimpdrawablepreview.c
 *
6
 * This library is free software: you can redistribute it and/or
7 8
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
9
 * version 3 of the License, or (at your option) any later version.
10 11 12 13 14 15 16
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
17 18
 * License along with this library.  If not, see
 * <http://www.gnu.org/licenses/>.
19 20 21 22
 */

#include "config.h"

23
#include <gegl.h>
24 25 26 27
#include <gtk/gtk.h>

#include "libgimpwidgets/gimpwidgets.h"

28 29 30 31
#include "gimpuitypes.h"

#include "gimp.h"

32 33 34
#include "gimpdrawablepreview.h"


35 36 37 38 39 40 41 42 43
/**
 * SECTION: gimpdrawablepreview
 * @title: GimpDrawablePreview
 * @short_description: A widget providing a preview of a #GimpDrawable.
 *
 * A widget providing a preview of a #GimpDrawable.
 **/


44
#define SELECTION_BORDER  8
45

46 47 48
enum
{
  PROP_0,
49
  PROP_DRAWABLE_ID
50 51
};

52 53
typedef struct
{
54 55 56
  gint      x;
  gint      y;
  gboolean  update;
57
} PreviewSettings;
58 59


60 61 62 63 64 65 66
struct _GimpDrawablePreviewPrivate
{
  gint32 drawable_ID;
};

#define GET_PRIVATE(obj) (((GimpDrawablePreview *) (obj))->priv)

67

68
static void  gimp_drawable_preview_constructed   (GObject         *object);
69
static void  gimp_drawable_preview_dispose       (GObject         *object);
70
static void  gimp_drawable_preview_get_property  (GObject         *object,
Sven Neumann's avatar
Sven Neumann committed
71 72 73
                                                  guint            property_id,
                                                  GValue          *value,
                                                  GParamSpec      *pspec);
74
static void  gimp_drawable_preview_set_property  (GObject         *object,
Sven Neumann's avatar
Sven Neumann committed
75 76 77
                                                  guint            property_id,
                                                  const GValue    *value,
                                                  GParamSpec      *pspec);
78

79
static void  gimp_drawable_preview_style_updated (GtkWidget       *widget);
80

81 82 83 84 85 86 87 88
static void  gimp_drawable_preview_draw_original (GimpPreview     *preview);
static void  gimp_drawable_preview_draw_thumb    (GimpPreview     *preview,
                                                  GimpPreviewArea *area,
                                                  gint             width,
                                                  gint             height);
static void  gimp_drawable_preview_draw_buffer   (GimpPreview     *preview,
                                                  const guchar    *buffer,
                                                  gint             rowstride);
89

90 91 92
static void  gimp_drawable_preview_set_drawable_id
                                                (GimpDrawablePreview *preview,
                                                 gint32               drawable_ID);
93

94

95
G_DEFINE_TYPE (GimpDrawablePreview, gimp_drawable_preview,
96
               GIMP_TYPE_SCROLLED_PREVIEW)
97

98
#define parent_class gimp_drawable_preview_parent_class
99

100 101
static gint gimp_drawable_preview_counter = 0;

102 103 104 105

static void
gimp_drawable_preview_class_init (GimpDrawablePreviewClass *klass)
{
106 107 108
  GObjectClass     *object_class  = G_OBJECT_CLASS (klass);
  GtkWidgetClass   *widget_class  = GTK_WIDGET_CLASS (klass);
  GimpPreviewClass *preview_class = GIMP_PREVIEW_CLASS (klass);
109

110 111 112 113
  object_class->constructed   = gimp_drawable_preview_constructed;
  object_class->dispose       = gimp_drawable_preview_dispose;
  object_class->get_property  = gimp_drawable_preview_get_property;
  object_class->set_property  = gimp_drawable_preview_set_property;
114

115
  widget_class->style_updated = gimp_drawable_preview_style_updated;
116

117 118 119
  preview_class->draw         = gimp_drawable_preview_draw_original;
  preview_class->draw_thumb   = gimp_drawable_preview_draw_thumb;
  preview_class->draw_buffer  = gimp_drawable_preview_draw_buffer;
120

121 122 123 124 125 126 127 128 129 130
  g_type_class_add_private (object_class, sizeof (GimpDrawablePreviewPrivate));

  /**
   * GimpDrawablePreview:drawable-id:
   *
   * The drawable the #GimpDrawablePreview is attached to.
   *
   * Since: 2.10
   */
  g_object_class_install_property (object_class, PROP_DRAWABLE_ID,
131 132 133
                                   g_param_spec_int ("drawable-id",
                                                     "Drawable ID",
                                                     "The drawable this preview is attached to",
134 135 136 137
                                                     -1, G_MAXINT, -1,
                                                     GIMP_PARAM_READWRITE |
                                                     G_PARAM_CONSTRUCT_ONLY));

138 139
}

140 141 142
static void
gimp_drawable_preview_init (GimpDrawablePreview *preview)
{
143 144 145 146
  preview->priv = G_TYPE_INSTANCE_GET_PRIVATE (preview,
                                               GIMP_TYPE_DRAWABLE_PREVIEW,
                                               GimpDrawablePreviewPrivate);

147
  g_object_set (gimp_preview_get_area (GIMP_PREVIEW (preview)),
148 149 150 151 152
                "check-size", gimp_check_size (),
                "check-type", gimp_check_type (),
                NULL);
}

153 154
static void
gimp_drawable_preview_constructed (GObject *object)
155
{
156
  gchar           *data_name;
157
  PreviewSettings  settings;
158

159
  G_OBJECT_CLASS (parent_class)->constructed (object);
160

161 162 163
  data_name = g_strdup_printf ("%s-drawable-preview-%d",
                               g_get_prgname (),
                               ++gimp_drawable_preview_counter);
164 165

  if (gimp_get_data (data_name, &settings))
166 167 168 169 170
    {
      gimp_preview_set_update (GIMP_PREVIEW (object), settings.update);
      gimp_scrolled_preview_set_position (GIMP_SCROLLED_PREVIEW (object),
                                          settings.x, settings.y);
    }
171

172 173
  g_object_set_data_full (object, "gimp-drawable-preview-data-name",
                          data_name, (GDestroyNotify) g_free);
174 175
}

176 177 178 179 180 181 182 183 184 185 186
static void
gimp_drawable_preview_dispose (GObject *object)
{
  const gchar *data_name = g_object_get_data (G_OBJECT (object),
                                              "gimp-drawable-preview-data-name");

  if (data_name)
    {
      GimpPreview     *preview = GIMP_PREVIEW (object);
      PreviewSettings  settings;

187
      gimp_preview_get_position (preview, &settings.x, &settings.y);
188 189 190 191 192 193 194 195
      settings.update = gimp_preview_get_update (preview);

      gimp_set_data (data_name, &settings, sizeof (PreviewSettings));
    }

  G_OBJECT_CLASS (parent_class)->dispose (object);
}

196 197
static void
gimp_drawable_preview_get_property (GObject    *object,
Sven Neumann's avatar
Sven Neumann committed
198 199 200
                                    guint       property_id,
                                    GValue     *value,
                                    GParamSpec *pspec)
201 202 203 204 205
{
  GimpDrawablePreview *preview = GIMP_DRAWABLE_PREVIEW (object);

  switch (property_id)
    {
206 207 208
    case PROP_DRAWABLE_ID:
      g_value_set_int (value,
                       gimp_drawable_preview_get_drawable_id (preview));
209 210 211 212 213 214 215 216 217 218
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
gimp_drawable_preview_set_property (GObject      *object,
Sven Neumann's avatar
Sven Neumann committed
219 220 221
                                    guint         property_id,
                                    const GValue *value,
                                    GParamSpec   *pspec)
222
{
223
  GimpDrawablePreview *preview = GIMP_DRAWABLE_PREVIEW (object);
224 225 226

  switch (property_id)
    {
227 228 229
    case PROP_DRAWABLE_ID:
      gimp_drawable_preview_set_drawable_id (preview,
                                             g_value_get_int (value));
230 231 232 233 234 235 236 237
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

238
static void
239
gimp_drawable_preview_style_updated (GtkWidget *widget)
240 241
{
  GimpPreview *preview = GIMP_PREVIEW (widget);
242
  GtkWidget   *area    = gimp_preview_get_area (preview);
243

244
  GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
245

246
  if (area)
247
    {
248 249
      gint xmin, ymin;
      gint xmax, ymax;
250 251
      gint size;

252 253
      gimp_preview_get_bounds (preview, &xmin, &ymin, &xmax, &ymax);

254 255 256
      gtk_widget_style_get (widget,
                            "size", &size,
                            NULL);
257

258 259 260
      gtk_widget_set_size_request (area,
                                   MIN (xmax - xmin, size),
                                   MIN (ymax - ymin, size));
261
    }
262 263 264
}

static void
265
gimp_drawable_preview_draw_original (GimpPreview *preview)
266
{
267
  GimpDrawablePreviewPrivate *priv = GET_PRIVATE (preview);
268 269
  guchar                     *buffer;
  gint                        width, height;
270 271 272
  gint                        xoff, yoff;
  gint                        xmin, ymin;
  gint                        xmax, ymax;
273 274
  gint                        bpp;
  GimpImageType               type;
275

276
  if (priv->drawable_ID < 1)
277 278
    return;

279 280 281 282 283 284
  gimp_preview_get_size (preview, &width, &height);
  gimp_preview_get_offsets (preview, &xoff, &yoff);
  gimp_preview_get_bounds (preview, &xmin, &ymin, &xmax, &ymax);

  xoff = CLAMP (xoff, 0, xmax - xmin - width);
  yoff = CLAMP (yoff, 0, ymax - ymin - height);
285

286
  gimp_preview_set_offsets (preview, xoff, yoff);
287

288
  buffer = gimp_drawable_get_sub_thumbnail_data (priv->drawable_ID,
289 290 291
                                                 xoff + xmin,
                                                 yoff + ymin,
                                                 width, height,
292 293 294 295 296 297 298 299 300 301 302 303
                                                 &width, &height, &bpp);

  switch (bpp)
    {
    case 1: type = GIMP_GRAY_IMAGE; break;
    case 2: type = GIMP_GRAYA_IMAGE; break;
    case 3: type = GIMP_RGB_IMAGE; break;
    case 4: type = GIMP_RGBA_IMAGE; break;
    default:
      g_free (buffer);
      return;
    }
304

305
  gimp_preview_area_draw (GIMP_PREVIEW_AREA (gimp_preview_get_area (preview)),
306
                          0, 0, width, height, type, buffer, width * bpp);
307 308 309
  g_free (buffer);
}

310
static void
311 312 313 314
gimp_drawable_preview_draw_thumb (GimpPreview     *preview,
                                  GimpPreviewArea *area,
                                  gint             width,
                                  gint             height)
315
{
316
  GimpDrawablePreviewPrivate *priv = GET_PRIVATE (preview);
317

318 319
  if (priv->drawable_ID > 0)
    _gimp_drawable_preview_area_draw_thumb (area, priv->drawable_ID,
320
                                            width, height);
321
}
322

323 324
void
_gimp_drawable_preview_area_draw_thumb (GimpPreviewArea *area,
325
                                        gint32           drawable_ID,
Sven Neumann's avatar
Sven Neumann committed
326 327
                                        gint             width,
                                        gint             height)
328 329 330 331 332 333 334 335
{
  guchar *buffer;
  gint    x1, y1, x2, y2;
  gint    bpp;
  gint    size = 100;
  gint    nav_width, nav_height;

  g_return_if_fail (GIMP_IS_PREVIEW_AREA (area));
336 337
  g_return_if_fail (gimp_item_is_valid (drawable_ID));
  g_return_if_fail (gimp_item_is_drawable (drawable_ID));
338

339
  if (_gimp_drawable_preview_get_bounds (drawable_ID, &x1, &y1, &x2, &y2))
340 341 342 343 344 345
    {
      width  = x2 - x1;
      height = y2 - y1;
    }
  else
    {
346 347
      width  = gimp_drawable_width  (drawable_ID);
      height = gimp_drawable_height (drawable_ID);
348 349 350 351 352 353 354 355 356 357 358 359 360
    }

  if (width > height)
    {
      nav_width  = MIN (width, size);
      nav_height = (height * nav_width) / width;
    }
  else
    {
      nav_height = MIN (height, size);
      nav_width  = (width * nav_height) / height;
    }

361
  if (_gimp_drawable_preview_get_bounds (drawable_ID, &x1, &y1, &x2, &y2))
362
    {
363
      buffer = gimp_drawable_get_sub_thumbnail_data (drawable_ID,
364
                                                     x1, y1, x2 - x1, y2 - y1,
365
                                                     &nav_width, &nav_height,
Sven Neumann's avatar
Sven Neumann committed
366
                                                     &bpp);
367 368 369
    }
  else
    {
370
      buffer = gimp_drawable_get_thumbnail_data (drawable_ID,
371
                                                 &nav_width, &nav_height,
Sven Neumann's avatar
Sven Neumann committed
372
                                                 &bpp);
373
    }
374 375 376

  if (buffer)
    {
377
      GimpImageType type;
378

379
      gtk_widget_set_size_request (GTK_WIDGET (area), nav_width, nav_height);
380 381 382 383 384
      gtk_widget_show (GTK_WIDGET (area));
      gtk_widget_realize (GTK_WIDGET (area));

      switch (bpp)
        {
385 386 387 388 389 390 391
        case 1:  type = GIMP_GRAY_IMAGE;   break;
        case 2:  type = GIMP_GRAYA_IMAGE;  break;
        case 3:  type = GIMP_RGB_IMAGE;    break;
        case 4:  type = GIMP_RGBA_IMAGE;   break;
        default:
          g_free (buffer);
          return;
392 393
        }

394
      gimp_preview_area_draw (area,
395 396
                              0, 0, nav_width, nav_height,
                              type, buffer, bpp * nav_width);
397 398 399 400
      g_free (buffer);
    }
}

401 402 403 404 405 406 407 408 409
static void
gimp_drawable_preview_draw_area (GimpDrawablePreview *preview,
                                 gint                 x,
                                 gint                 y,
                                 gint                 width,
                                 gint                 height,
                                 const guchar        *buf,
                                 gint                 rowstride)
{
410
  GimpDrawablePreviewPrivate *priv         = GET_PRIVATE (preview);
411
  GimpPreview                *gimp_preview = GIMP_PREVIEW (preview);
412 413 414
  GtkWidget                  *area         = gimp_preview_get_area (gimp_preview);
  gint                        xmin, ymin;
  gint                        xoff, yoff;
415
  gint32                      image_ID;
416

417 418 419
  gimp_preview_get_bounds (gimp_preview, &xmin, &ymin, NULL, NULL);
  gimp_preview_get_offsets (gimp_preview, &xoff, &yoff);

420
  image_ID = gimp_item_get_image (priv->drawable_ID);
421

422
  if (gimp_selection_is_empty (image_ID))
423
    {
424 425 426
      gimp_preview_area_draw (GIMP_PREVIEW_AREA (area),
                              x - xoff - xmin,
                              y - yoff - ymin,
427 428
                              width,
                              height,
429
                              gimp_drawable_type (priv->drawable_ID),
430 431 432 433
                              buf, rowstride);
    }
  else
    {
434 435 436 437 438
      gint offset_x, offset_y;
      gint mask_x, mask_y;
      gint mask_width, mask_height;
      gint draw_x, draw_y;
      gint draw_width, draw_height;
439

440
      gimp_drawable_offsets (priv->drawable_ID, &offset_x, &offset_y);
441

442
      if (gimp_drawable_mask_intersect (priv->drawable_ID,
443 444 445 446 447 448 449 450
                                        &mask_x, &mask_y,
                                        &mask_width, &mask_height) &&
          gimp_rectangle_intersect (mask_x, mask_y,
                                    mask_width, mask_height,
                                    x, y, width, height,
                                    &draw_x, &draw_y,
                                    &draw_width, &draw_height))
        {
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
          GimpImageType  type;
          gint32         selection_ID;
          guchar        *src;
          guchar        *sel;
          gint           d_w, d_h, d_bpp;
          gint           s_w, s_h, s_bpp;

          d_w = draw_width;
          d_h = draw_height;

          s_w = draw_width;
          s_h = draw_height;

          selection_ID = gimp_image_get_selection (image_ID);

          src = gimp_drawable_get_sub_thumbnail_data (priv->drawable_ID,
                                                      draw_x, draw_y,
                                                      draw_width, draw_height,
                                                      &d_w, &d_h,
                                                      &d_bpp);

          sel = gimp_drawable_get_sub_thumbnail_data (selection_ID,
                                                      draw_x + offset_x,
                                                      draw_y + offset_y,
                                                      draw_width, draw_height,
                                                      &s_w, &s_h,
                                                      &s_bpp);

          switch (d_bpp)
            {
            case 1:  type = GIMP_GRAY_IMAGE;   break;
            case 2:  type = GIMP_GRAYA_IMAGE;  break;
            case 3:  type = GIMP_RGB_IMAGE;    break;
            case 4:  type = GIMP_RGBA_IMAGE;   break;
            default:
              g_free (sel);
              g_free (src);
              return;
            }
490

491 492 493
          gimp_preview_area_mask (GIMP_PREVIEW_AREA (area),
                                  draw_x - xoff - xmin,
                                  draw_y - yoff - ymin,
494 495
                                  draw_width,
                                  draw_height,
496 497
                                  type,
                                  src, draw_width * d_bpp,
498
                                  (buf +
499 500
                                   (draw_x - x) * d_bpp +
                                   (draw_y - y) * d_w * d_bpp),
501
                                  rowstride,
502
                                  sel, s_w);
503 504 505 506

          g_free (sel);
          g_free (src);
        }
507 508 509
    }
}

510 511 512 513 514
static void
gimp_drawable_preview_draw_buffer (GimpPreview  *preview,
                                   const guchar *buffer,
                                   gint          rowstride)
{
515 516 517 518 519 520
  gint x, y;
  gint width, height;

  gimp_preview_get_position (preview, &x, &y);
  gimp_preview_get_size (preview, &width, &height);

521
  gimp_drawable_preview_draw_area (GIMP_DRAWABLE_PREVIEW (preview),
522 523
                                   x, y,
                                   width, height,
524 525 526
                                   buffer, rowstride);
}

527 528 529 530 531
static void
gimp_drawable_preview_set_drawable_id (GimpDrawablePreview *drawable_preview,
                                       gint32               drawable_ID)
{
  GimpPreview                *preview = GIMP_PREVIEW (drawable_preview);
532
  GimpDrawablePreviewPrivate *priv    = GET_PRIVATE (preview);
533 534 535 536 537 538 539
  gint                        x1, y1, x2, y2;

  g_return_if_fail (priv->drawable_ID < 1);

  priv->drawable_ID = drawable_ID;

  _gimp_drawable_preview_get_bounds (drawable_ID, &x1, &y1, &x2, &y2);
540

541
  gimp_preview_set_bounds (preview, x1, y1, x2, y2);
542

543
  if (gimp_drawable_is_indexed (drawable_ID))
544
    {
545 546 547 548
      guint32    image_ID = gimp_item_get_image (drawable_ID);
      GtkWidget *area     = gimp_preview_get_area (preview);
      guchar    *cmap;
      gint       num_colors;
549

550
      cmap = gimp_image_get_colormap (image_ID, &num_colors);
551
      gimp_preview_area_set_colormap (GIMP_PREVIEW_AREA (area),
552
                                      cmap, num_colors);
553 554
      g_free (cmap);
    }
555
}
556

557 558 559 560

#define MAX3(a, b, c)  (MAX (MAX ((a), (b)), (c)))
#define MIN3(a, b, c)  (MIN (MIN ((a), (b)), (c)))

561
gboolean
562 563 564 565 566
_gimp_drawable_preview_get_bounds (gint32  drawable_ID,
                                   gint   *xmin,
                                   gint   *ymin,
                                   gint   *xmax,
                                   gint   *ymax)
567 568 569 570 571 572 573 574 575
{
  gint     width;
  gint     height;
  gint     offset_x;
  gint     offset_y;
  gint     x1, y1;
  gint     x2, y2;
  gboolean retval;

576 577
  g_return_val_if_fail (gimp_item_is_valid (drawable_ID), FALSE);
  g_return_val_if_fail (gimp_item_is_drawable (drawable_ID), FALSE);
578

579 580
  width  = gimp_drawable_width (drawable_ID);
  height = gimp_drawable_height (drawable_ID);
581

582
  retval = gimp_drawable_mask_bounds (drawable_ID, &x1, &y1, &x2, &y2);
583

584
  gimp_drawable_offsets (drawable_ID, &offset_x, &offset_y);
585 586 587 588 589 590 591 592 593 594

  *xmin = MAX3 (x1 - SELECTION_BORDER, 0, - offset_x);
  *ymin = MAX3 (y1 - SELECTION_BORDER, 0, - offset_y);
  *xmax = MIN3 (x2 + SELECTION_BORDER, width,  width  + offset_x);
  *ymax = MIN3 (y2 + SELECTION_BORDER, height, height + offset_y);

  return retval;
}


595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
/**
 * gimp_drawable_preview_new_from_drawable_id:
 * @drawable_ID: a drawable ID
 *
 * Creates a new #GimpDrawablePreview widget for @drawable_ID.
 *
 * Returns: A pointer to the new #GimpDrawablePreview widget.
 *
 * Since: 2.10
 **/
GtkWidget *
gimp_drawable_preview_new_from_drawable_id (gint32 drawable_ID)
{
  g_return_val_if_fail (gimp_item_is_valid (drawable_ID), NULL);
  g_return_val_if_fail (gimp_item_is_drawable (drawable_ID), NULL);

  return g_object_new (GIMP_TYPE_DRAWABLE_PREVIEW,
                       "drawable-id", drawable_ID,
                       NULL);
}

/**
 * gimp_drawable_preview_get_drawable_id:
 * @preview:   a #GimpDrawablePreview widget
 *
 * Return value: the drawable_ID that has been passed to
 *               gimp_drawable_preview_new_from_drawable_id().
 *
 * Since: 2.10
 **/
gint32
gimp_drawable_preview_get_drawable_id (GimpDrawablePreview *preview)
{
628
  g_return_val_if_fail (GIMP_IS_DRAWABLE_PREVIEW (preview), -1);
629

630
  return GET_PRIVATE (preview)->drawable_ID;
631 632
}

633 634 635 636 637
/**
 * gimp_drawable_preview_draw_region:
 * @preview: a #GimpDrawablePreview widget
 * @region:  a #GimpPixelRgn
 *
638
 * Since: 2.2
639 640 641 642 643
 **/
void
gimp_drawable_preview_draw_region (GimpDrawablePreview *preview,
                                   const GimpPixelRgn  *region)
{
644 645
  GimpDrawablePreviewPrivate *priv;

646 647
  g_return_if_fail (GIMP_IS_DRAWABLE_PREVIEW (preview));
  g_return_if_fail (region != NULL);
648

649
  priv = GET_PRIVATE (preview);
650 651 652

  g_return_if_fail (priv->drawable_ID > 0);

653 654 655 656
  /*  If the data field is initialized, this region is currently being
   *  processed and we can access it directly.
   */
  if (region->data)
657
    {
658 659 660 661 662 663 664
      gimp_drawable_preview_draw_area (preview,
                                       region->x,
                                       region->y,
                                       region->w,
                                       region->h,
                                       region->data,
                                       region->rowstride);
665 666 667
    }
  else
    {
668 669
      GimpPixelRgn  src = *region;
      gpointer      iter;
670

671 672
      src.dirty = FALSE; /* we don't dirty the tiles, just read them */

673 674 675 676 677 678 679 680 681 682 683 684
      for (iter = gimp_pixel_rgns_register (1, &src);
           iter != NULL;
           iter = gimp_pixel_rgns_process (iter))
        {
          gimp_drawable_preview_draw_area (preview,
                                           src.x,
                                           src.y,
                                           src.w,
                                           src.h,
                                           src.data,
                                           src.rowstride);
        }
685
    }
686
}