gimpdrawable.c 18.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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.
 */
Sven Neumann's avatar
Sven Neumann committed
18

19 20
#include "config.h"

21
#include <stdlib.h>
Sven Neumann's avatar
Sven Neumann committed
22
#include <stdio.h>
23
#include <string.h>
24

25
#include <glib-object.h>
Sven Neumann's avatar
Sven Neumann committed
26

27 28
#include "libgimpcolor/gimpcolor.h"
#include "libgimpmath/gimpmath.h"
29
#include "libgimpbase/gimpbase.h"
30

Michael Natterer's avatar
Michael Natterer committed
31
#include "core-types.h"
32

Michael Natterer's avatar
Michael Natterer committed
33 34 35 36
#include "base/pixel-region.h"
#include "base/tile.h"
#include "base/tile-manager.h"

37 38
#include "paint-funcs/paint-funcs.h"

39
#include "gimp.h"
40
#include "gimpchannel.h"
Michael Natterer's avatar
Michael Natterer committed
41
#include "gimpcontext.h"
42
#include "gimpdrawable.h"
43
#include "gimpdrawable-preview.h"
44
#include "gimpimage.h"
45
#include "gimpimage-mask.h"
46
#include "gimplayer.h"
47
#include "gimplist.h"
48
#include "gimpmarshal.h"
49
#include "gimpparasitelist.h"
50
#include "gimppreviewcache.h"
51

52
#include "undo.h"
53

54
#include "libgimp/gimpintl.h"
55

56 57 58

enum
{
59
  VISIBILITY_CHANGED,
60 61 62
  LAST_SIGNAL
};

63

64 65
/*  local function prototypes  */

66 67
static void       gimp_drawable_class_init         (GimpDrawableClass *klass);
static void       gimp_drawable_init               (GimpDrawable      *drawable);
68

69
static void       gimp_drawable_finalize           (GObject           *object);
70

71
static gsize      gimp_drawable_get_memsize        (GimpObject        *object);
72

73 74 75 76 77
static void       gimp_drawable_invalidate_preview (GimpViewable      *viewable);

static GimpItem * gimp_drawable_duplicate          (GimpItem          *item,
                                                    GType              new_type,
                                                    gboolean           add_alpha);
78

79

80 81
/*  private variables  */

82 83
static guint gimp_drawable_signals[LAST_SIGNAL] = { 0 };

84
static GimpItemClass *parent_class = NULL;
85 86


87
GType
Manish Singh's avatar
Manish Singh committed
88
gimp_drawable_get_type (void)
89
{
90
  static GType drawable_type = 0;
91 92 93

  if (! drawable_type)
    {
94
      static const GTypeInfo drawable_info =
95
      {
96 97 98 99 100 101
        sizeof (GimpDrawableClass),
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_drawable_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data     */
102
	sizeof (GimpDrawable),
103 104
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_drawable_init,
105 106
      };

107
      drawable_type = g_type_register_static (GIMP_TYPE_ITEM,
108 109
					      "GimpDrawable", 
					      &drawable_info, 0);
110 111 112
    }

  return drawable_type;
113 114 115
}

static void
116
gimp_drawable_class_init (GimpDrawableClass *klass)
117
{
118
  GObjectClass      *object_class;
119 120
  GimpObjectClass   *gimp_object_class;
  GimpViewableClass *viewable_class;
121
  GimpItemClass     *item_class;
122

123 124 125
  object_class      = G_OBJECT_CLASS (klass);
  gimp_object_class = GIMP_OBJECT_CLASS (klass);
  viewable_class    = GIMP_VIEWABLE_CLASS (klass);
126
  item_class        = GIMP_ITEM_CLASS (klass);
127

128
  parent_class = g_type_class_peek_parent (klass);
129

130
  gimp_drawable_signals[VISIBILITY_CHANGED] =
131 132 133 134 135
    g_signal_new ("visibility_changed",
		  G_TYPE_FROM_CLASS (klass),
		  G_SIGNAL_RUN_FIRST,
		  G_STRUCT_OFFSET (GimpDrawableClass, visibility_changed),
		  NULL, NULL,
136
		  gimp_marshal_VOID__VOID,
137
		  G_TYPE_NONE, 0);
138

139
  object_class->finalize             = gimp_drawable_finalize;
140

141
  gimp_object_class->get_memsize     = gimp_drawable_get_memsize;
142

143
  viewable_class->invalidate_preview = gimp_drawable_invalidate_preview;
144
  viewable_class->get_preview        = gimp_drawable_get_preview;
145

146 147
  item_class->duplicate              = gimp_drawable_duplicate;

Michael Natterer's avatar
Michael Natterer committed
148
  klass->visibility_changed          = NULL;
149 150
}

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
static void
gimp_drawable_init (GimpDrawable *drawable)
{
  drawable->tiles         = NULL;
  drawable->visible       = FALSE;
  drawable->width         = 0;
  drawable->height        = 0;
  drawable->offset_x      = 0;
  drawable->offset_y      = 0;
  drawable->bytes         = 0;
  drawable->type          = -1;
  drawable->has_alpha     = FALSE;
  drawable->preview_cache = NULL;
  drawable->preview_valid = FALSE;
}

static void
168
gimp_drawable_finalize (GObject *object)
169 170 171 172 173 174 175 176
{
  GimpDrawable *drawable;

  g_return_if_fail (GIMP_IS_DRAWABLE (object));

  drawable = GIMP_DRAWABLE (object);

  if (drawable->tiles)
177 178 179 180
    {
      tile_manager_destroy (drawable->tiles);
      drawable->tiles = NULL;
    }
181 182 183 184

  if (drawable->preview_cache)
    gimp_preview_cache_invalidate (&drawable->preview_cache);

185
  G_OBJECT_CLASS (parent_class)->finalize (object);
186 187
}

188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
static gsize
gimp_drawable_get_memsize (GimpObject *object)
{
  GimpDrawable *drawable;
  gsize         memsize = 0;

  drawable = GIMP_DRAWABLE (object);

  if (drawable->tiles)
    memsize += tile_manager_get_memsize (drawable->tiles);

  if (drawable->preview_cache)
    memsize += gimp_preview_cache_get_memsize (drawable->preview_cache);

  return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object);
}

205 206 207 208 209 210
static void
gimp_drawable_invalidate_preview (GimpViewable *viewable)
{
  GimpDrawable *drawable;
  GimpImage    *gimage;

211 212 213
  if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview)
    GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable);

214 215 216 217
  drawable = GIMP_DRAWABLE (viewable);

  drawable->preview_valid = FALSE;

218
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
219 220

  if (gimage)
221
    gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage));
222 223
}

224 225 226 227
static GimpItem *
gimp_drawable_duplicate (GimpItem *item,
                         GType     new_type,
                         gboolean  add_alpha)
228
{
229 230
  GimpDrawable  *drawable;
  GimpItem      *new_item;
231 232 233 234 235 236 237
  GimpDrawable  *new_drawable;
  GimpImageType  new_image_type;
  PixelRegion    srcPR;
  PixelRegion    destPR;

  g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL);

238 239 240 241 242 243 244 245
  new_item = GIMP_ITEM_CLASS (parent_class)->duplicate (item, new_type,
                                                        add_alpha);

  if (! GIMP_IS_DRAWABLE (new_item))
    return new_item;

  drawable     = GIMP_DRAWABLE (item);
  new_drawable = GIMP_DRAWABLE (new_item);
246 247

  if (add_alpha)
248
    new_image_type = gimp_drawable_type_with_alpha (drawable);
249
  else
250
    new_image_type = gimp_drawable_type (drawable);
251 252

  gimp_drawable_configure (new_drawable,
253
                           gimp_item_get_image (GIMP_ITEM (drawable)),
254 255
                           drawable->offset_x,
                           drawable->offset_y,
256 257 258
                           gimp_drawable_width (drawable),
                           gimp_drawable_height (drawable),
                           new_image_type,
259
                           GIMP_OBJECT (new_drawable)->name);
260

261
  new_drawable->visible = drawable->visible;
262 263 264

  pixel_region_init (&srcPR, drawable->tiles, 
                     0, 0, 
265 266
                     gimp_drawable_width (drawable),
                     gimp_drawable_height (drawable),
267 268 269
                     FALSE);
  pixel_region_init (&destPR, new_drawable->tiles,
                     0, 0, 
270 271
                     gimp_drawable_width (new_drawable),
                     gimp_drawable_height (new_drawable),
272 273 274
                     TRUE);

  if (new_image_type == drawable->type)
275
    copy_region (&srcPR, &destPR);
276
  else
277
    add_alpha_region (&srcPR, &destPR);
278

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
  return new_item;
}

void
gimp_drawable_configure (GimpDrawable  *drawable,
			 GimpImage     *gimage,
                         gint           offset_x,
                         gint           offset_y,
			 gint           width,
			 gint           height, 
			 GimpImageType  type,
			 const gchar   *name)
{
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
  g_return_if_fail (GIMP_IS_IMAGE (gimage));

  /*  if not already configured by gimp_item_copy()  */
  if (! GIMP_ITEM (drawable)->ID)
    gimp_item_configure (GIMP_ITEM (drawable), gimage, name);

  drawable->width     = width;
  drawable->height    = height;
  drawable->type      = type;
  drawable->bytes     = GIMP_IMAGE_TYPE_BYTES (type);
  drawable->has_alpha = GIMP_IMAGE_TYPE_HAS_ALPHA (type);
  drawable->offset_x  = offset_x;
  drawable->offset_y  = offset_y;

  if (drawable->tiles)
    tile_manager_destroy (drawable->tiles);

  drawable->tiles = tile_manager_new (width, height,
                                      drawable->bytes);

  drawable->visible = TRUE;

  /*  preview variables  */
  drawable->preview_cache = NULL;
  drawable->preview_valid = FALSE;
318 319
}

Michael Natterer's avatar
Michael Natterer committed
320 321 322 323
void
gimp_drawable_update (GimpDrawable *drawable,
		      gint          x,
		      gint          y,
324 325
		      gint          w,
		      gint          h)
Michael Natterer's avatar
Michael Natterer committed
326 327 328 329 330 331 332
{
  GimpImage *gimage;
  gint       offset_x;
  gint       offset_y;

  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

333
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
Michael Natterer's avatar
Michael Natterer committed
334 335 336 337 338 339 340 341 342 343 344 345 346

  g_return_if_fail (gimage != NULL);

  gimp_drawable_offsets (drawable, &offset_x, &offset_y);
  x += offset_x;
  y += offset_y;

  gimp_image_update (gimage, x, y, w, h);

  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable));
}

void
347 348 349 350 351 352 353
gimp_drawable_push_undo (GimpDrawable *drawable, 
                         gint          x1,
                         gint          y1,
                         gint          x2,
                         gint          y2, 
                         TileManager  *tiles,
                         gboolean      sparse)
Michael Natterer's avatar
Michael Natterer committed
354 355 356
{
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

357
  if (! tiles)
358 359
    undo_push_image (gimp_item_get_image (GIMP_ITEM (drawable)),
                     drawable, 
Michael Natterer's avatar
Michael Natterer committed
360 361
		     x1, y1, x2, y2);
  else
362 363 364 365
    undo_push_image_mod (gimp_item_get_image (GIMP_ITEM (drawable)),
                         drawable, 
			 x1, y1, x2, y2,
                         tiles, sparse);
Michael Natterer's avatar
Michael Natterer committed
366 367
}

368
void
369
gimp_drawable_merge_shadow (GimpDrawable *drawable,
370
			    gboolean      push_undo)
371
{
372
  GimpImage   *gimage;
373 374
  PixelRegion  shadowPR;
  gint         x1, y1, x2, y2;
375

Manish Singh's avatar
Manish Singh committed
376
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
377

378
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
379

380
  g_return_if_fail (GIMP_IS_IMAGE (gimage));
Manish Singh's avatar
Manish Singh committed
381
  g_return_if_fail (gimage->shadow != NULL);
382

383 384 385 386 387 388 389
  /*  A useful optimization here is to limit the update to the
   *  extents of the selection mask, as it cannot extend beyond
   *  them.
   */
  gimp_drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
  pixel_region_init (&shadowPR, gimage->shadow, x1, y1,
		     (x2 - x1), (y2 - y1), FALSE);
390
  gimp_image_apply_image (gimage, drawable, &shadowPR, push_undo,
391 392
                          GIMP_OPACITY_OPAQUE, GIMP_REPLACE_MODE,
                          NULL, x1, y1);
393 394 395
}

void
396 397
gimp_drawable_fill (GimpDrawable  *drawable,
		    const GimpRGB *color)
398
{
399
  GimpImage   *gimage;
400 401 402
  PixelRegion  destPR;
  guchar       c[MAX_CHANNELS];
  guchar       i;
403

Manish Singh's avatar
Manish Singh committed
404 405
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

406
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
407

Manish Singh's avatar
Manish Singh committed
408
  g_return_if_fail (gimage != NULL);
409

410
  switch (GIMP_IMAGE_TYPE_BASE_TYPE (gimp_drawable_type (drawable)))
411
    {
412
    case GIMP_RGB:
413 414 415 416 417
      gimp_rgba_get_uchar (color,
			   &c[RED_PIX],
			   &c[GREEN_PIX],
			   &c[BLUE_PIX],
			   &c[ALPHA_PIX]);
418
      if (gimp_drawable_type (drawable) != GIMP_RGBA_IMAGE)
419
	c[ALPHA_PIX] = 255;
420
      break;
421

422
    case GIMP_GRAY:
423 424 425 426 427
      gimp_rgba_get_uchar (color,
			   &c[GRAY_PIX],
			   NULL,
			   NULL,
			   &c[ALPHA_G_PIX]);
428
      if (gimp_drawable_type (drawable) != GIMP_GRAYA_IMAGE)
429
	c[ALPHA_G_PIX] = 255;
430
      break;
431

432
    case GIMP_INDEXED:
433 434 435 436
      gimp_rgb_get_uchar (color,
			  &c[RED_PIX],
			  &c[GREEN_PIX],
			  &c[BLUE_PIX]);
437
      gimp_image_transform_color (gimage, drawable, c, &i, GIMP_RGB);
438
      c[INDEXED_PIX] = i;
439
      if (gimp_drawable_type (drawable) == GIMP_INDEXEDA_IMAGE)
440 441 442 443 444
	gimp_rgba_get_uchar (color,
			     NULL,
			     NULL,
			     NULL,
			     &c[ALPHA_I_PIX]);
445
      break;
446

447
    default:
448 449
      g_warning ("%s: Cannot fill unknown image type.", 
                 G_GNUC_PRETTY_FUNCTION);
450 451 452 453 454 455
      break;
    }

  pixel_region_init (&destPR,
		     gimp_drawable_data (drawable),
		     0, 0,
456
		     gimp_drawable_width  (drawable),
457 458 459
		     gimp_drawable_height (drawable),
		     TRUE);
  color_region (&destPR, c);
Michael Natterer's avatar
Michael Natterer committed
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475

  gimp_drawable_update (drawable,
			0, 0,
			gimp_drawable_width  (drawable),
			gimp_drawable_height (drawable));
}

void
gimp_drawable_fill_by_type (GimpDrawable *drawable,
			    GimpContext  *context,
			    GimpFillType  fill_type)
{
  GimpRGB color;

  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

476
  color.a = GIMP_OPACITY_OPAQUE;
Michael Natterer's avatar
Michael Natterer committed
477 478 479

  switch (fill_type)
    {
480
    case GIMP_FOREGROUND_FILL:
Michael Natterer's avatar
Michael Natterer committed
481 482 483
      gimp_context_get_foreground (context, &color);
      break;

484
    case  GIMP_BACKGROUND_FILL:
Michael Natterer's avatar
Michael Natterer committed
485 486 487
      gimp_context_get_background (context, &color);
      break;

488
    case GIMP_WHITE_FILL:
Michael Natterer's avatar
Michael Natterer committed
489 490 491
      gimp_rgb_set (&color, 1.0, 1.0, 1.0);
      break;

492
    case GIMP_TRANSPARENT_FILL:
493
      gimp_rgba_set (&color, 0.0, 0.0, 0.0, GIMP_OPACITY_TRANSPARENT);
Michael Natterer's avatar
Michael Natterer committed
494 495
      break;

496
    case  GIMP_NO_FILL:
Michael Natterer's avatar
Michael Natterer committed
497 498 499
      return;

    default:
500
      g_warning ("%s: unknown fill type %d", G_GNUC_PRETTY_FUNCTION, fill_type);
Michael Natterer's avatar
Michael Natterer committed
501 502 503 504
      return;
    }

  gimp_drawable_fill (drawable, &color);
505 506
}

507
gboolean
508
gimp_drawable_mask_bounds (GimpDrawable *drawable, 
509 510 511 512
			   gint         *x1,
			   gint         *y1,
			   gint         *x2,
			   gint         *y2)
513
{
Manish Singh's avatar
Manish Singh committed
514
  GimpImage *gimage;
515
  gint       off_x, off_y;
516

Manish Singh's avatar
Manish Singh committed
517
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
518

519
  gimage = gimp_item_get_image (GIMP_ITEM (drawable));
520

Manish Singh's avatar
Manish Singh committed
521
  g_return_val_if_fail (gimage != NULL, FALSE);
522

523
  if (gimp_image_mask_bounds (gimage, x1, y1, x2, y2))
524 525
    {
      gimp_drawable_offsets (drawable, &off_x, &off_y);
526
      *x1 = CLAMP (*x1 - off_x, 0, gimp_drawable_width  (drawable));
527
      *y1 = CLAMP (*y1 - off_y, 0, gimp_drawable_height (drawable));
528
      *x2 = CLAMP (*x2 - off_x, 0, gimp_drawable_width  (drawable));
529 530 531 532 533
      *y2 = CLAMP (*y2 - off_y, 0, gimp_drawable_height (drawable));
      return TRUE;
    }
  else
    {
534
      *x2 = gimp_drawable_width  (drawable);
535 536 537 538 539
      *y2 = gimp_drawable_height (drawable);
      return FALSE;
    }
}

540
gboolean
541
gimp_drawable_has_alpha (const GimpDrawable *drawable)
542
{
Manish Singh's avatar
Manish Singh committed
543 544 545
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

  return drawable->has_alpha;
546
}
547

548
GimpImageType
549
gimp_drawable_type (const GimpDrawable *drawable)
550
{
Manish Singh's avatar
Manish Singh committed
551 552 553
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

  return drawable->type;
554 555
}

556
GimpImageType
557
gimp_drawable_type_with_alpha (const GimpDrawable *drawable)
558
{
Manish Singh's avatar
Manish Singh committed
559
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);
560

561
  return GIMP_IMAGE_TYPE_WITH_ALPHA (gimp_drawable_type (drawable));
562 563 564 565 566 567 568
}

gboolean
gimp_drawable_is_rgb (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

569
  return GIMP_IMAGE_TYPE_IS_RGB (gimp_drawable_type (drawable));
570 571 572 573 574 575 576
}

gboolean
gimp_drawable_is_gray (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

577
  return GIMP_IMAGE_TYPE_IS_GRAY (gimp_drawable_type (drawable));
578 579 580 581 582 583 584
}

gboolean
gimp_drawable_is_indexed (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

585
  return GIMP_IMAGE_TYPE_IS_INDEXED (gimp_drawable_type (drawable));
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602
}

TileManager *
gimp_drawable_data (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);

  return drawable->tiles;
}

TileManager *
gimp_drawable_shadow (GimpDrawable *drawable)
{
  GimpImage *gimage;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);

603
  if (! (gimage = gimp_item_get_image (GIMP_ITEM (drawable))))
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
    return NULL;

  return gimp_image_shadow (gimage, drawable->width, drawable->height, 
			    drawable->bytes);
}

gint
gimp_drawable_bytes (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

  return drawable->bytes;
}

gint
gimp_drawable_bytes_with_alpha (const GimpDrawable *drawable)
{
621 622
  GimpImageType type;

623 624
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

625
  type = GIMP_IMAGE_TYPE_WITH_ALPHA (gimp_drawable_type (drawable));
626

627
  return GIMP_IMAGE_TYPE_BYTES (type);
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
}

gint
gimp_drawable_width (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

  return drawable->width;
}

gint
gimp_drawable_height (const GimpDrawable *drawable)
{
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), -1);

  return drawable->height;
644 645
}

646
gboolean
647
gimp_drawable_get_visible (const GimpDrawable *drawable)
648
{
649 650
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);

651 652 653
  return drawable->visible;
}

654 655 656 657 658 659 660 661 662 663 664 665
void
gimp_drawable_set_visible (GimpDrawable *drawable,
                           gboolean      visible)
{
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

  visible = visible ? TRUE : FALSE;

  if (drawable->visible != visible)
    {
      drawable->visible = visible;

666
      g_signal_emit (drawable, gimp_drawable_signals[VISIBILITY_CHANGED], 0);
Michael Natterer's avatar
Michael Natterer committed
667 668 669 670 671

      gimp_drawable_update (drawable,
			    0, 0,
			    drawable->width,
			    drawable->height);
672 673 674
    }
}

675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
void
gimp_drawable_offsets (const GimpDrawable *drawable,
		       gint               *off_x,
		       gint               *off_y)
{
  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));

  *off_x = drawable->offset_x;
  *off_y = drawable->offset_y;
}

guchar *
gimp_drawable_cmap (const GimpDrawable *drawable)
{
  GimpImage *gimage;

  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);

693
  if (! (gimage = gimp_item_get_image (GIMP_ITEM (drawable))))
694 695 696 697 698
    return NULL;

  return gimage->cmap;
}

699 700 701 702
guchar *
gimp_drawable_get_color_at (GimpDrawable *drawable,
			    gint          x,
			    gint          y)
703
{
704
  Tile   *tile;
705 706
  guchar *src;
  guchar *dest;
707

Manish Singh's avatar
Manish Singh committed
708
  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
709
  g_return_val_if_fail (gimp_item_get_image (GIMP_ITEM (drawable)) ||
710
			! gimp_drawable_is_indexed (drawable), NULL);
711 712 713 714

  /* do not make this a g_return_if_fail() */
  if ( !(x >= 0 && x < drawable->width && y >= 0 && y < drawable->height))
    return NULL;
Manish Singh's avatar
Manish Singh committed
715

716
  dest = g_new (guchar, 5);
Manish Singh's avatar
Manish Singh committed
717

718 719 720
  tile = tile_manager_get_tile (gimp_drawable_data (drawable), x, y,
				TRUE, FALSE);
  src = tile_data_pointer (tile, x % TILE_WIDTH, y % TILE_HEIGHT);
Manish Singh's avatar
Manish Singh committed
721

722
  gimp_image_get_color (gimp_item_get_image (GIMP_ITEM (drawable)),
723
			gimp_drawable_type (drawable), dest, src);
Manish Singh's avatar
Manish Singh committed
724

725
  if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_drawable_type (drawable)))
726 727 728
    dest[3] = src[gimp_drawable_bytes (drawable) - 1];
  else
    dest[3] = 255;
Manish Singh's avatar
Manish Singh committed
729

Marc Lehmann's avatar
Marc Lehmann committed
730
  if (gimp_drawable_is_indexed (drawable))
731 732 733
    dest[4] = src[0];
  else
    dest[4] = 0;
Manish Singh's avatar
Manish Singh committed
734

735
  tile_release (tile, FALSE);
Manish Singh's avatar
Manish Singh committed
736

737 738
  return dest;
}