diff --git a/ChangeLog b/ChangeLog index fa03738498..25fa600c09 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,70 @@ +2003-09-06 Michael Natterer + + To optimize duplicate and/or wrong image updates away, introduced + new policy that a child object must never explicitly update or + invalidate its parent object (just like the GUI is not updated + explicitly by the core): + + * app/core/gimpdrawable.[ch]: added new signal + GimpDrawable::update(). Never update or invalidate the image when + the drawable is updated or invalidated. + + (gimp_drawable_set_visible): don't gimp_drawable_update() the + drawable since its pixels have not changed. + + * app/core/gimpimage.[ch]: connect to the "add" and "remove" + signals of the layers and channels containers. Also connect to the + "update" and "visibility_changed" signals of all drawables in + these containers (optimizes away updates issued by drawables which + are not yet added to the image and updates of the selection + mask). Also, don't propagate updates to the image if the emitting + drawable is invisible (optimizes away updates issued by invisible + drawables). + + (gimp_image_add_layer,channel) + (gimp_image_remove_layer,channel): don't update the image since + that's done by our "add" and "remove" handlers now. + + (gimp_image_position_layer,channel): update just the image, not + the drawable since its pixels have not changed. + + (gimp_image_real_colormap_changed) + (gimp_image_set_component_visible): always call + gimp_image_update() *and* gimp_viewable_invalidate_preview() to + get everything updated, since update and invalidate of images are + not connected. + + * app/core/gimpimage-undo-push.c (undo_pop_layer,channel): don't + update the drawable since (a) its pixels don't change and (b) the + image updates itself upon adding/removing now. + + (undo_pop_layer_mod): replaced gimp_image_update() by + gimp_drawable_update() (just for consistency with other similar + functions). + + * app/core/gimplayer.c: connect to "update" of the layer mask and + issue updates on the layer if the mask update has any effect on + the projection. + (gimp_layer_create_mask): don't set the mask's offsets here since + they may be different when we later add the mask to the layer. + + * app/core/gimplayermask.c (gimp_layer_mask_set_layer): set the + mask offsets here instead. + + * app/core/gimpchannel.c (gimp_channel_translate): update the + channel even if push_undo == FALSE. + + * app/paint/gimppaintcore.c (gimp_paint_core_finish) + * app/tools/gimpinktool.c (ink_finish): invalidate both the + drawable and the image preview since invalidating the drawable + doesn't invalidate the image any more. + + * app/text/gimptextlayer.c (gimp_text_layer_render_now): also + update the new extents of the text layer, not only the old one. + + (gimp_text_layer_render_layout): don't update the drawable since + gimp_drawable_fill() already updated it. + 2003-09-06 Sven Neumann * app/vectors/gimpbezierstroke.c diff --git a/app/core/gimpchannel.c b/app/core/gimpchannel.c index af36efde85..df79d4f205 100644 --- a/app/core/gimpchannel.c +++ b/app/core/gimpchannel.c @@ -362,19 +362,15 @@ gimp_channel_translate (GimpItem *item, height = y2 - y1; if (push_undo) - { - gimp_channel_push_undo (channel, - GIMP_CHANNEL_GET_CLASS (channel)->translate_desc); - - /* update the old area */ - gimp_drawable_update (GIMP_DRAWABLE (item), - x1, y1, - x2 - x1, y2 - y1); - } + gimp_channel_push_undo (channel, + GIMP_CHANNEL_GET_CLASS (channel)->translate_desc); else - { - gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (channel)); - } + gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (channel)); + + /* update the old area */ + gimp_drawable_update (GIMP_DRAWABLE (item), + x1, y1, + x2 - x1, y2 - y1); /* make sure width and height are non-zero */ if (width != 0 && height != 0) @@ -429,16 +425,11 @@ gimp_channel_translate (GimpItem *item, channel->y2 = y2; } - if (push_undo) - { - /* update the new area */ - gimp_drawable_update (GIMP_DRAWABLE (item), - channel->x1, channel->y1, - channel->x2 - channel->x1, - channel->y2 - channel->y1); - - gimp_viewable_size_changed (GIMP_VIEWABLE (item)); - } + /* update the new area */ + gimp_drawable_update (GIMP_DRAWABLE (item), + channel->x1, channel->y1, + channel->x2 - channel->x1, + channel->y2 - channel->y1); } static void diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index 9239708cac..b7d344ac10 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -56,6 +56,7 @@ enum { + UPDATE, VISIBILITY_CHANGED, ALPHA_CHANGED, LAST_SIGNAL @@ -105,6 +106,12 @@ static void gimp_drawable_transform (GimpItem *item, GimpProgressFunc progress_callback, gpointer progress_data); +static void gimp_drawable_real_update (GimpDrawable *drawable, + gint x, + gint y, + gint width, + gint height); + /* private variables */ @@ -156,6 +163,19 @@ gimp_drawable_class_init (GimpDrawableClass *klass) parent_class = g_type_class_peek_parent (klass); + gimp_drawable_signals[UPDATE] = + g_signal_new ("update", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (GimpDrawableClass, update), + NULL, NULL, + gimp_marshal_VOID__INT_INT_INT_INT, + G_TYPE_NONE, 4, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT); + gimp_drawable_signals[VISIBILITY_CHANGED] = g_signal_new ("visibility_changed", G_TYPE_FROM_CLASS (klass), @@ -190,6 +210,7 @@ gimp_drawable_class_init (GimpDrawableClass *klass) item_class->rotate = gimp_drawable_rotate; item_class->transform = gimp_drawable_transform; + klass->update = gimp_drawable_real_update; klass->visibility_changed = NULL; klass->alpha_changed = NULL; klass->invalidate_boundary = NULL; @@ -247,7 +268,6 @@ static void gimp_drawable_invalidate_preview (GimpViewable *viewable) { GimpDrawable *drawable; - GimpImage *gimage; if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview) GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable); @@ -258,11 +278,6 @@ gimp_drawable_invalidate_preview (GimpViewable *viewable) if (drawable->preview_cache) gimp_preview_cache_invalidate (&drawable->preview_cache); - - gimage = gimp_item_get_image (GIMP_ITEM (drawable)); - - if (gimage) - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); } static GimpItem * @@ -559,6 +574,16 @@ gimp_drawable_transform (GimpItem *item, } } +static void +gimp_drawable_real_update (GimpDrawable *drawable, + gint x, + gint y, + gint width, + gint height) +{ + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable)); +} + void gimp_drawable_configure (GimpDrawable *drawable, GimpImage *gimage, @@ -595,28 +620,13 @@ void gimp_drawable_update (GimpDrawable *drawable, gint x, gint y, - gint w, - gint h) + gint width, + gint height) { - GimpItem *item; - GimpImage *gimage; - gint offset_x; - gint offset_y; - g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); - item = GIMP_ITEM (drawable); - gimage = gimp_item_get_image (item); - - g_return_if_fail (gimage != NULL); - - gimp_item_offsets (item, &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)); + g_signal_emit (drawable, gimp_drawable_signals[UPDATE], 0, + x, y, width, height); } void @@ -947,8 +957,6 @@ gimp_drawable_set_visible (GimpDrawable *drawable, drawable->visible = visible ? TRUE : FALSE; g_signal_emit (drawable, gimp_drawable_signals[VISIBILITY_CHANGED], 0); - - gimp_drawable_update (drawable, 0, 0, item->width, item->height); } } diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h index 93a575221c..6f7bf2eb76 100644 --- a/app/core/gimpdrawable.h +++ b/app/core/gimpdrawable.h @@ -54,6 +54,11 @@ struct _GimpDrawableClass GimpItemClass parent_class; /* signals */ + void (* update) (GimpDrawable *drawable, + gint x, + gint y, + gint width, + gint height); void (* visibility_changed) (GimpDrawable *drawable); void (* alpha_changed) (GimpDrawable *drawable); @@ -78,8 +83,8 @@ void gimp_drawable_configure (GimpDrawable *drawable, void gimp_drawable_update (GimpDrawable *drawable, gint x, gint y, - gint w, - gint h); + gint width, + gint height); void gimp_drawable_push_undo (GimpDrawable *drawable, const gchar *undo_desc, diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index 4a7fb66cce..0b317206e7 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -1563,11 +1563,6 @@ undo_pop_layer (GimpUndo *undo, gimp_image_floating_selection_changed (undo->gimage); } - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - GIMP_ITEM (layer)->width, - GIMP_ITEM (layer)->height); - if (gimp_container_num_children (undo->gimage->layers) == 1 && ! gimp_drawable_has_alpha (GIMP_LIST (undo->gimage->layers)->list->data)) { @@ -1607,11 +1602,6 @@ undo_pop_layer (GimpUndo *undo, if (gimp_layer_is_floating_sel (layer)) gimp_image_floating_selection_changed (undo->gimage); - - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - GIMP_ITEM (layer)->width, - GIMP_ITEM (layer)->height); } return TRUE; @@ -1699,11 +1689,10 @@ undo_pop_layer_mod (GimpUndo *undo, layer = GIMP_LAYER (GIMP_ITEM_UNDO (undo)->item); /* Issue the first update */ - gimp_image_update (undo->gimage, - GIMP_ITEM (layer)->offset_x, - GIMP_ITEM (layer)->offset_y, - GIMP_ITEM (layer)->width, - GIMP_ITEM (layer)->height); + gimp_drawable_update (GIMP_DRAWABLE (layer), + 0, 0, + GIMP_ITEM (layer)->width, + GIMP_ITEM (layer)->height); tiles = lmu->tiles; layer_type = lmu->type; @@ -2237,12 +2226,6 @@ undo_pop_channel (GimpUndo *undo, else gimp_image_unset_active_channel (undo->gimage); } - - /* update the area */ - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - GIMP_ITEM (channel)->width, - GIMP_ITEM (channel)->height); } else { @@ -2257,12 +2240,6 @@ undo_pop_channel (GimpUndo *undo, gimp_container_insert (undo->gimage->channels, GIMP_OBJECT (channel), cu->prev_position); gimp_image_set_active_channel (undo->gimage, channel); - - /* update the area */ - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - GIMP_ITEM (channel)->width, - GIMP_ITEM (channel)->height); } return TRUE; diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index 8cb026f2e0..79f8e3542a 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -118,6 +118,21 @@ static gchar * gimp_image_get_description (GimpViewable *viewable, static void gimp_image_real_colormap_changed (GimpImage *gimage, gint ncol); +static void gimp_image_drawable_update (GimpDrawable *drawable, + gint x, + gint y, + gint width, + gint height, + GimpImage *gimage); +static void gimp_image_drawable_visibility (GimpDrawable *drawable, + GimpImage *gimage); +static void gimp_image_drawable_add (GimpContainer *container, + GimpDrawable *drawable, + GimpImage *gimage); +static void gimp_image_drawable_remove (GimpContainer *container, + GimpDrawable *drawable, + GimpImage *gimage); + static void gimp_image_get_active_components (const GimpImage *gimage, const GimpDrawable *drawable, gboolean *active); @@ -478,6 +493,38 @@ gimp_image_init (GimpImage *gimage) GIMP_CONTAINER_POLICY_STRONG); gimage->layer_stack = NULL; + gimage->layer_update_handler = + gimp_container_add_handler (gimage->layers, "update", + G_CALLBACK (gimp_image_drawable_update), + gimage); + gimage->channel_update_handler = + gimp_container_add_handler (gimage->channels, "update", + G_CALLBACK (gimp_image_drawable_update), + gimage); + + gimage->layer_visible_handler = + gimp_container_add_handler (gimage->layers, "visibility_changed", + G_CALLBACK (gimp_image_drawable_visibility), + gimage); + gimage->channel_visible_handler = + gimp_container_add_handler (gimage->channels, "visibility_changed", + G_CALLBACK (gimp_image_drawable_visibility), + gimage); + + g_signal_connect (gimage->layers, "add", + G_CALLBACK (gimp_image_drawable_add), + gimage); + g_signal_connect (gimage->channels, "add", + G_CALLBACK (gimp_image_drawable_add), + gimage); + + g_signal_connect (gimage->layers, "remove", + G_CALLBACK (gimp_image_drawable_remove), + gimage); + g_signal_connect (gimage->channels, "remove", + G_CALLBACK (gimp_image_drawable_remove), + gimage); + gimage->active_layer = NULL; gimage->active_channel = NULL; gimage->active_vectors = NULL; @@ -507,21 +554,41 @@ gimp_image_init (GimpImage *gimage) static void gimp_image_dispose (GObject *object) { - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); + GimpImage *gimage = GIMP_IMAGE (object); gimp_image_undo_free (gimage); + gimp_container_remove_handler (gimage->layers, + gimage->layer_update_handler); + gimp_container_remove_handler (gimage->channels, + gimage->channel_update_handler); + + gimp_container_remove_handler (gimage->layers, + gimage->layer_visible_handler); + gimp_container_remove_handler (gimage->channels, + gimage->channel_visible_handler); + + g_signal_handlers_disconnect_by_func (gimage->layers, + gimp_image_drawable_add, + gimage); + g_signal_handlers_disconnect_by_func (gimage->channels, + gimp_image_drawable_add, + gimage); + + g_signal_handlers_disconnect_by_func (gimage->layers, + gimp_image_drawable_remove, + gimage); + g_signal_handlers_disconnect_by_func (gimage->channels, + gimp_image_drawable_remove, + gimage); + G_OBJECT_CLASS (parent_class)->dispose (object); } static void gimp_image_finalize (GObject *object) { - GimpImage *gimage; - - gimage = GIMP_IMAGE (object); + GimpImage *gimage = GIMP_IMAGE (object); if (gimage->gimp && gimage->gimp->image_table) { @@ -763,11 +830,71 @@ gimp_image_real_colormap_changed (GimpImage *gimage, { /* A colormap alteration affects the whole image */ gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); gimp_image_color_hash_invalidate (gimage, ncol); } } +static void +gimp_image_drawable_update (GimpDrawable *drawable, + gint x, + gint y, + gint width, + gint height, + GimpImage *gimage) +{ + if (gimp_drawable_get_visible (drawable)) + { + gint offset_x; + gint offset_y; + + gimp_item_offsets (GIMP_ITEM (drawable), &offset_x, &offset_y); + x += offset_x; + y += offset_y; + + gimp_image_update (gimage, x, y, width, height); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); + } +} + +static void +gimp_image_drawable_visibility (GimpDrawable *drawable, + GimpImage *gimage) +{ + GimpItem *item; + gint offset_x; + gint offset_y; + + item = GIMP_ITEM (drawable); + + gimp_item_offsets (item, &offset_x, &offset_y); + + gimp_image_update (gimage, + offset_x, offset_y, + gimp_item_width (item), + gimp_item_height (item)); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); +} + +static void +gimp_image_drawable_add (GimpContainer *container, + GimpDrawable *drawable, + GimpImage *gimage) +{ + if (gimp_drawable_get_visible (drawable)) + gimp_image_drawable_visibility (drawable, gimage); +} + +static void +gimp_image_drawable_remove (GimpContainer *container, + GimpDrawable *drawable, + GimpImage *gimage) +{ + if (gimp_drawable_get_visible (drawable)) + gimp_image_drawable_visibility (drawable, gimage); +} + static void gimp_image_get_active_components (const GimpImage *gimage, const GimpDrawable *drawable, @@ -1236,6 +1363,7 @@ gimp_image_set_component_visible (GimpImage *gimage, channel); gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); } } @@ -1820,8 +1948,6 @@ gimp_image_replace_image (GimpImage *gimage, gint x1, y1, x2, y2; gint offset_x, offset_y; PixelRegion src1PR, destPR; - PixelRegion mask2PR, tempPR; - guchar *temp_data; CombinationMode operation; gboolean active_components[MAX_CHANNELS]; @@ -1887,7 +2013,9 @@ gimp_image_replace_image (GimpImage *gimage, if (mask) { - int mx, my; + PixelRegion mask2PR, tempPR; + guchar *temp_data; + gint mx, my; /* configure the mask pixel region * don't use x1 and y1 because they are in layer @@ -1902,30 +2030,29 @@ gimp_image_replace_image (GimpImage *gimage, (x2 - x1), (y2 - y1), FALSE); - tempPR.bytes = 1; - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; + tempPR.bytes = 1; + tempPR.x = 0; + tempPR.y = 0; + tempPR.w = x2 - x1; + tempPR.h = y2 - y1; tempPR.rowstride = tempPR.w * tempPR.bytes; - temp_data = g_malloc (tempPR.h * tempPR.rowstride); - tempPR.data = temp_data; + tempPR.data = temp_data = g_malloc (tempPR.h * tempPR.rowstride); copy_region (&mask2PR, &tempPR); /* apparently, region operations can mutate some PR data. */ - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; + tempPR.x = 0; + tempPR.y = 0; + tempPR.w = x2 - x1; + tempPR.h = y2 - y1; tempPR.data = temp_data; apply_mask_to_region (&tempPR, maskPR, OPAQUE_OPACITY); - tempPR.x = 0; - tempPR.y = 0; - tempPR.w = x2 - x1; - tempPR.h = y2 - y1; + tempPR.x = 0; + tempPR.y = 0; + tempPR.w = x2 - x1; + tempPR.h = y2 - y1; tempPR.data = temp_data; combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL, @@ -2569,12 +2696,6 @@ gimp_image_add_layer (GimpImage *gimage, /* notify the layers dialog of the currently active layer */ gimp_image_set_active_layer (gimage, layer); - /* update the new layer's area */ - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - gimp_item_width (GIMP_ITEM (layer)), - gimp_item_height (GIMP_ITEM (layer))); - if (alpha_changed) gimp_image_alpha_changed (gimage); @@ -2585,8 +2706,6 @@ void gimp_image_remove_layer (GimpImage *gimage, GimpLayer *layer) { - gint x, y, w, h; - g_return_if_fail (GIMP_IS_IMAGE (gimage)); g_return_if_fail (GIMP_IS_LAYER (layer)); @@ -2630,16 +2749,8 @@ gimp_image_remove_layer (GimpImage *gimage, /* Send out REMOVED signal from layer */ gimp_item_removed (GIMP_ITEM (layer)); - gimp_item_offsets (GIMP_ITEM (layer), &x, &y); - w = gimp_item_width (GIMP_ITEM (layer)); - h = gimp_item_height (GIMP_ITEM (layer)); - g_object_unref (layer); - gimp_image_update (gimage, x, y, w, h); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); - if (gimp_container_num_children (gimage->layers) == 1 && ! gimp_drawable_has_alpha (GIMP_LIST (gimage->layers)->list->data)) { @@ -2755,7 +2866,6 @@ gimp_image_position_layer (GimpImage *gimage, gboolean push_undo, const gchar *undo_desc) { - gint off_x, off_y; gint index; gint num_layers; @@ -2800,14 +2910,18 @@ gimp_image_position_layer (GimpImage *gimage, gimp_container_reorder (gimage->layers, GIMP_OBJECT (layer), new_index); - gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); + if (gimp_drawable_get_visible (GIMP_DRAWABLE (layer))) + { + gint off_x, off_y; - gimp_image_update (gimage, - off_x, off_y, - gimp_item_width (GIMP_ITEM (layer)), - gimp_item_height (GIMP_ITEM (layer))); + gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); + gimp_image_update (gimage, + off_x, off_y, + gimp_item_width (GIMP_ITEM (layer)), + gimp_item_height (GIMP_ITEM (layer))); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); + } return TRUE; } @@ -2867,13 +2981,6 @@ gimp_image_add_channel (GimpImage *gimage, /* notify this gimage of the currently active channel */ gimp_image_set_active_channel (gimage, channel); - /* if channel is visible, update the image */ - if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel))) - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_item_width (GIMP_ITEM (channel)), - gimp_item_height (GIMP_ITEM (channel))); - return TRUE; } @@ -2916,10 +3023,6 @@ gimp_image_remove_channel (GimpImage *gimage, } g_object_unref (channel); - - gimp_image_update (gimage, 0, 0, gimage->width, gimage->height); - - gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); } gboolean @@ -2971,7 +3074,7 @@ gimp_image_position_channel (GimpImage *gimage, gboolean push_undo, const gchar *undo_desc) { - gint index; + gint index; gint num_channels; g_return_val_if_fail (GIMP_IS_IMAGE (gimage), FALSE); @@ -2995,10 +3098,18 @@ gimp_image_position_channel (GimpImage *gimage, gimp_container_reorder (gimage->channels, GIMP_OBJECT (channel), new_index); - gimp_drawable_update (GIMP_DRAWABLE (channel), - 0, 0, - gimp_item_width (GIMP_ITEM (channel)), - gimp_item_height (GIMP_ITEM (channel))); + if (gimp_drawable_get_visible (GIMP_DRAWABLE (channel))) + { + gint off_x, off_y; + + gimp_item_offsets (GIMP_ITEM (channel), &off_x, &off_y); + + gimp_image_update (gimage, + off_x, off_y, + gimp_item_width (GIMP_ITEM (channel)), + gimp_item_height (GIMP_ITEM (channel))); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); + } return TRUE; } diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h index 2375ec66a5..e6930b0e49 100644 --- a/app/core/gimpimage.h +++ b/app/core/gimpimage.h @@ -132,6 +132,11 @@ struct _GimpImage GimpContainer *vectors; /* the list of vectors */ GSList *layer_stack; /* the layers in MRU order */ + GQuark layer_update_handler; + GQuark channel_update_handler; + GQuark layer_visible_handler; + GQuark channel_visible_handler; + GimpLayer *active_layer; /* the active layer */ GimpChannel *active_channel; /* the active channel */ GimpVectors *active_vectors; /* the active vectors */ diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c index 1e69c9a7fa..22d9f720ef 100644 --- a/app/core/gimplayer.c +++ b/app/core/gimplayer.c @@ -63,6 +63,7 @@ enum static void gimp_layer_class_init (GimpLayerClass *klass); static void gimp_layer_init (GimpLayer *layer); +static void gimp_layer_dispose (GObject *object); static void gimp_layer_finalize (GObject *object); static gsize gimp_layer_get_memsize (GimpObject *object, @@ -120,6 +121,13 @@ static void gimp_layer_transform_color (GimpImage *gimage, GimpDrawable *drawable, GimpImageBaseType type); +static void gimp_layer_layer_mask_update (GimpDrawable *layer_mask, + gint x, + gint y, + gint width, + gint height, + GimpLayer *layer); + static guint layer_signals[LAST_SIGNAL] = { 0 }; @@ -207,6 +215,7 @@ gimp_layer_class_init (GimpLayerClass *klass) gimp_marshal_VOID__VOID, G_TYPE_NONE, 0); + object_class->dispose = gimp_layer_dispose; object_class->finalize = gimp_layer_finalize; gimp_object_class->get_memsize = gimp_layer_get_memsize; @@ -252,6 +261,19 @@ gimp_layer_init (GimpLayer *layer) layer->fs.num_segs = 0; } +static void +gimp_layer_dispose (GObject *object) +{ + GimpLayer *layer = GIMP_LAYER (object); + + if (layer->mask) + g_signal_handlers_disconnect_by_func (layer->mask, + gimp_layer_layer_mask_update, + layer); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + static void gimp_layer_finalize (GObject *object) { @@ -266,7 +288,8 @@ gimp_layer_finalize (GObject *object) if (layer->fs.segs) { g_free (layer->fs.segs); - layer->fs.segs = NULL; + layer->fs.segs = NULL; + layer->fs.num_segs = 0; } /* free the floating selection if it exists */ @@ -303,9 +326,7 @@ gimp_layer_get_memsize (GimpObject *object, static void gimp_layer_invalidate_preview (GimpViewable *viewable) { - GimpLayer *layer; - - layer = GIMP_LAYER (viewable); + GimpLayer *layer = GIMP_LAYER (viewable); if (GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview) GIMP_VIEWABLE_CLASS (parent_class)->invalidate_preview (viewable); @@ -749,9 +770,25 @@ gimp_layer_transform_color (GimpImage *gimage, } } -/**************************/ -/* Function definitions */ -/**************************/ +static void +gimp_layer_layer_mask_update (GimpDrawable *drawable, + gint x, + gint y, + gint width, + gint height, + GimpLayer *layer) +{ + GimpLayerMask *layer_mask = GIMP_LAYER_MASK (drawable); + + if (layer_mask->apply_mask || layer_mask->show_mask) + { + gimp_drawable_update (GIMP_DRAWABLE (layer), + x, y, width, height); + } +} + + +/* public functions */ GimpLayer * gimp_layer_new (GimpImage *gimage, @@ -906,15 +943,20 @@ gimp_layer_add_mask (GimpLayer *layer, return NULL; } - layer->mask = mask; - g_object_ref (layer->mask); - + layer->mask = g_object_ref (mask); gimp_layer_mask_set_layer (mask, layer); - gimp_drawable_update (GIMP_DRAWABLE (layer), - 0, 0, - GIMP_ITEM (layer)->width, - GIMP_ITEM (layer)->height); + if (mask->apply_mask || mask->show_mask) + { + gimp_drawable_update (GIMP_DRAWABLE (layer), + 0, 0, + GIMP_ITEM (layer)->width, + GIMP_ITEM (layer)->height); + } + + g_signal_connect (mask, "update", + G_CALLBACK (gimp_layer_layer_mask_update), + layer); if (push_undo) gimp_image_undo_push_layer_mask_add (gimage, _("Add Layer Mask"), @@ -954,9 +996,6 @@ gimp_layer_create_mask (const GimpLayer *layer, g_free (mask_name); - GIMP_ITEM (mask)->offset_x = item->offset_x; - GIMP_ITEM (mask)->offset_y = item->offset_y; - switch (add_mask_type) { case GIMP_ADD_WHITE_MASK: @@ -1126,10 +1165,9 @@ gimp_layer_apply_mask (GimpLayer *layer, } /* check if applying the mask changes the projection */ - if ((mode == GIMP_MASK_APPLY && (! layer->mask->apply_mask || - layer->mask->show_mask)) || - (mode == GIMP_MASK_DISCARD && (layer->mask->apply_mask || - layer->mask->show_mask))) + if (layer->mask->show_mask || + (mode == GIMP_MASK_APPLY && ! layer->mask->apply_mask) || + (mode == GIMP_MASK_DISCARD && layer->mask->apply_mask)) { view_changed = TRUE; } @@ -1158,6 +1196,10 @@ gimp_layer_apply_mask (GimpLayer *layer, apply_mask_to_region (&srcPR, &maskPR, OPAQUE_OPACITY); } + g_signal_handlers_disconnect_by_func (layer->mask, + gimp_layer_layer_mask_update, + layer); + g_object_unref (layer->mask); layer->mask = NULL; diff --git a/app/core/gimplayermask.c b/app/core/gimplayermask.c index 11ec002dd1..35a5f3d007 100644 --- a/app/core/gimplayermask.c +++ b/app/core/gimplayermask.c @@ -170,7 +170,7 @@ gimp_layer_mask_new (GimpImage *gimage, layer_mask = g_object_new (GIMP_TYPE_LAYER_MASK, NULL); - gimp_drawable_configure (GIMP_DRAWABLE (layer_mask), + gimp_drawable_configure (GIMP_DRAWABLE (layer_mask), gimage, 0, 0, width, height, GIMP_GRAY_IMAGE, name); @@ -192,9 +192,15 @@ gimp_layer_mask_set_layer (GimpLayerMask *layer_mask, GimpLayer *layer) { g_return_if_fail (GIMP_IS_LAYER_MASK (layer_mask)); - g_return_if_fail (! layer || GIMP_IS_LAYER (layer)); + g_return_if_fail (layer == NULL || GIMP_IS_LAYER (layer)); layer_mask->layer = layer; + + if (layer) + { + GIMP_ITEM (layer_mask)->offset_x = GIMP_ITEM (layer)->offset_x; + GIMP_ITEM (layer_mask)->offset_y = GIMP_ITEM (layer)->offset_y; + } } GimpLayer * diff --git a/app/paint/gimpink.c b/app/paint/gimpink.c index ed71b210ca..04a597d176 100644 --- a/app/paint/gimpink.c +++ b/app/paint/gimpink.c @@ -704,6 +704,8 @@ static void ink_finish (GimpInkTool *ink_tool, GimpDrawable *drawable) { + GimpImage *gimage; + gimp_drawable_push_undo (drawable, _("Ink"), ink_tool->x1, ink_tool->y1, ink_tool->x2, ink_tool->y2, @@ -712,10 +714,13 @@ ink_finish (GimpInkTool *ink_tool, tile_manager_unref (undo_tiles); undo_tiles = NULL; - /* invalidate the drawable--have to do it here, because + gimage = gimp_item_get_image (GIMP_ITEM (drawable)); + + /* invalidate the previews -- have to do it here, because * it is not done during the actual painting. */ gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable)); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); } static void @@ -1029,9 +1034,9 @@ ink_paste (GimpInkTool *ink_tool, ink_tool->x2 = MAX (ink_tool->x2, (canvas_buf->x + canvas_buf->width)); ink_tool->y2 = MAX (ink_tool->y2, (canvas_buf->y + canvas_buf->height)); - /* Update the gimage--it is important to call gimp_image_update - * instead of drawable_update because we don't want the drawable - * preview to be constantly invalidated + /* Update the gimage -- it is important to call gimp_image_update() + * instead of gimp_drawable_update() because we don't want the + * drawable and image previews to be constantly invalidated */ gimp_item_offsets (GIMP_ITEM (drawable), &offx, &offy); gimp_image_update (gimage, diff --git a/app/paint/gimppaintcore.c b/app/paint/gimppaintcore.c index a66b7512be..18aea012aa 100644 --- a/app/paint/gimppaintcore.c +++ b/app/paint/gimppaintcore.c @@ -489,10 +489,11 @@ gimp_paint_core_finish (GimpPaintCore *core, gimp_image_undo_group_end (gimage); - /* invalidate the drawable--have to do it here, because + /* invalidate the previews -- have to do it here, because * it is not done during the actual painting. */ gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable)); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); } void @@ -1622,9 +1623,9 @@ gimp_paint_core_paste (GimpPaintCore *core, core->x2 = MAX (core->x2, core->canvas_buf->x + core->canvas_buf->width); core->y2 = MAX (core->y2, core->canvas_buf->y + core->canvas_buf->height); - /* Update the gimage -- It is important to call gimp_image_update - * instead of drawable_update because we don't want the drawable - * preview to be constantly invalidated + /* Update the gimage -- It is important to call gimp_image_update() + * instead of gimp_drawable_update() because we don't want the + * drawable and image previews to be constantly invalidated */ gimp_item_offsets (GIMP_ITEM (drawable), &offx, &offy); gimp_image_update (gimage, @@ -1734,9 +1735,9 @@ gimp_paint_core_replace (GimpPaintCore *core, core->x2 = MAX (core->x2, core->canvas_buf->x + core->canvas_buf->width) ; core->y2 = MAX (core->y2, core->canvas_buf->y + core->canvas_buf->height) ; - /* Update the gimage -- It is important to call gimp_image_update - * instead of drawable_update because we don't want the drawable - * preview to be constantly invalidated + /* Update the gimage -- It is important to call gimp_image_update() + * instead of gimp_drawable_update() because we don't want the + * drawable and image previews to be constantly invalidated */ gimp_item_offsets (GIMP_ITEM (drawable), &offx, &offy); gimp_image_update (gimage, diff --git a/app/text/gimptextlayer.c b/app/text/gimptextlayer.c index 658e8ac8b4..0e5d930f1b 100644 --- a/app/text/gimptextlayer.c +++ b/app/text/gimptextlayer.c @@ -443,6 +443,11 @@ gimp_text_layer_render_now (GimpTextLayer *layer) drawable->tiles = tile_manager_new (width, height, drawable->bytes); + gimp_drawable_update (drawable, + 0, 0, + gimp_item_width (item), + gimp_item_height (item)); + gimp_viewable_size_changed (GIMP_VIEWABLE (layer)); } } @@ -508,5 +513,7 @@ gimp_text_layer_render_layout (GimpTextLayer *layer, tile_manager_unref (mask); - gimp_drawable_update (drawable, 0, 0, bitmap.width, bitmap.rows); + /* no need to gimp_drawable_update() since gimp_drawable_fill() + * did that for us. + */ } diff --git a/app/tools/gimpinktool.c b/app/tools/gimpinktool.c index ed71b210ca..04a597d176 100644 --- a/app/tools/gimpinktool.c +++ b/app/tools/gimpinktool.c @@ -704,6 +704,8 @@ static void ink_finish (GimpInkTool *ink_tool, GimpDrawable *drawable) { + GimpImage *gimage; + gimp_drawable_push_undo (drawable, _("Ink"), ink_tool->x1, ink_tool->y1, ink_tool->x2, ink_tool->y2, @@ -712,10 +714,13 @@ ink_finish (GimpInkTool *ink_tool, tile_manager_unref (undo_tiles); undo_tiles = NULL; - /* invalidate the drawable--have to do it here, because + gimage = gimp_item_get_image (GIMP_ITEM (drawable)); + + /* invalidate the previews -- have to do it here, because * it is not done during the actual painting. */ gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable)); + gimp_viewable_invalidate_preview (GIMP_VIEWABLE (gimage)); } static void @@ -1029,9 +1034,9 @@ ink_paste (GimpInkTool *ink_tool, ink_tool->x2 = MAX (ink_tool->x2, (canvas_buf->x + canvas_buf->width)); ink_tool->y2 = MAX (ink_tool->y2, (canvas_buf->y + canvas_buf->height)); - /* Update the gimage--it is important to call gimp_image_update - * instead of drawable_update because we don't want the drawable - * preview to be constantly invalidated + /* Update the gimage -- it is important to call gimp_image_update() + * instead of gimp_drawable_update() because we don't want the + * drawable and image previews to be constantly invalidated */ gimp_item_offsets (GIMP_ITEM (drawable), &offx, &offy); gimp_image_update (gimage,