From bcacf6e2aefee6b8d888931741edefb4db40e97a Mon Sep 17 00:00:00 2001 From: Jehan Date: Sat, 4 Apr 2020 02:49:51 +0200 Subject: [PATCH] app: "active item" concept => "selected items". After much thought, tests and discussions with Aryeom, we decided adding back an active item concept additionally to the selected items ones is a bad idea as it makes only usage unecessarily complex. We will just have selected layers. Some kind of operations will work when more than one item (layers, channels, vectors) are selected while others will require exacty one item. In particular, let's replace instances of gimp_image_(s|g)et_active_*() by corresponding gimp_image_(s|g)et_selected_*(). Also replace single item in various undo classes by GList of items. Also "active-*-changed" GimpImage signals are no more, fully replaced by "selected-*s-changed". This is still work-in-progress. --- app/core/gimpchannelundo.c | 39 ++- app/core/gimpchannelundo.h | 4 +- app/core/gimpimage-duplicate.c | 78 +++-- app/core/gimpimage-quick-mask.c | 2 +- app/core/gimpimage-undo-push.c | 66 ++-- app/core/gimpimage-undo-push.h | 12 +- app/core/gimpimage.c | 408 +++++++++++++++--------- app/core/gimpimage.h | 18 +- app/core/gimpitemtree.c | 22 +- app/core/gimpitemtree.h | 4 +- app/core/gimplayer-floating-selection.c | 12 +- app/core/gimplayerundo.c | 36 ++- app/core/gimplayerundo.h | 2 +- app/display/gimpdisplayshell-handlers.c | 2 +- app/pdb/image-cmds.c | 2 +- app/tools/gimpbucketfilltool.c | 2 +- app/tools/gimpmovetool.c | 34 +- app/tools/gimpmovetool.h | 4 +- app/tools/gimptexttool.c | 20 +- app/tools/gimpvectortool.c | 2 +- app/vectors/gimpvectorsundo.c | 27 +- app/vectors/gimpvectorsundo.h | 4 +- app/widgets/gimpchanneltreeview.c | 2 +- app/widgets/gimpvectorstreeview.c | 2 +- pdb/groups/image.pdb | 2 +- 25 files changed, 499 insertions(+), 307 deletions(-) diff --git a/app/core/gimpchannelundo.c b/app/core/gimpchannelundo.c index c4ca9aa0b1..1d51e15b4e 100644 --- a/app/core/gimpchannelundo.c +++ b/app/core/gimpchannelundo.c @@ -34,11 +34,12 @@ enum PROP_0, PROP_PREV_PARENT, PROP_PREV_POSITION, - PROP_PREV_CHANNEL + PROP_PREV_CHANNELS }; static void gimp_channel_undo_constructed (GObject *object); +static void gimp_channel_undo_finalize (GObject *object); static void gimp_channel_undo_set_property (GObject *object, guint property_id, const GValue *value, @@ -69,6 +70,7 @@ gimp_channel_undo_class_init (GimpChannelUndoClass *klass) GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass); object_class->constructed = gimp_channel_undo_constructed; + object_class->finalize = gimp_channel_undo_finalize; object_class->set_property = gimp_channel_undo_set_property; object_class->get_property = gimp_channel_undo_get_property; @@ -90,17 +92,17 @@ gimp_channel_undo_class_init (GimpChannelUndoClass *klass) GIMP_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, PROP_PREV_CHANNEL, - g_param_spec_object ("prev-channel", - NULL, NULL, - GIMP_TYPE_CHANNEL, - GIMP_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_PREV_CHANNELS, + g_param_spec_pointer ("prev-channels", + NULL, NULL, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); } static void gimp_channel_undo_init (GimpChannelUndo *undo) { + undo->prev_channels = NULL; } static void @@ -111,6 +113,16 @@ gimp_channel_undo_constructed (GObject *object) gimp_assert (GIMP_IS_CHANNEL (GIMP_ITEM_UNDO (object)->item)); } +static void +gimp_channel_undo_finalize (GObject *object) +{ + GimpChannelUndo *channel_undo = GIMP_CHANNEL_UNDO (object); + + g_clear_pointer (&channel_undo->prev_channels, g_list_free); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + static void gimp_channel_undo_set_property (GObject *object, guint property_id, @@ -127,8 +139,8 @@ gimp_channel_undo_set_property (GObject *object, case PROP_PREV_POSITION: channel_undo->prev_position = g_value_get_int (value); break; - case PROP_PREV_CHANNEL: - channel_undo->prev_channel = g_value_get_object (value); + case PROP_PREV_CHANNELS: + channel_undo->prev_channels = g_list_copy (g_value_get_pointer (value)); break; default: @@ -153,8 +165,8 @@ gimp_channel_undo_get_property (GObject *object, case PROP_PREV_POSITION: g_value_set_int (value, channel_undo->prev_position); break; - case PROP_PREV_CHANNEL: - g_value_set_object (value, channel_undo->prev_channel); + case PROP_PREV_CHANNELS: + g_value_set_pointer (value, channel_undo->prev_channels); break; default: @@ -200,14 +212,15 @@ gimp_channel_undo_pop (GimpUndo *undo, channel_undo->prev_position = gimp_item_get_index (GIMP_ITEM (channel)); gimp_image_remove_channel (undo->image, channel, FALSE, - channel_undo->prev_channel); + channel_undo->prev_channels); } else { /* restore channel */ /* record the active channel */ - channel_undo->prev_channel = gimp_image_get_active_channel (undo->image); + g_clear_pointer (&channel_undo->prev_channels, g_list_free); + channel_undo->prev_channels = g_list_copy (gimp_image_get_selected_channels (undo->image)); gimp_image_add_channel (undo->image, channel, channel_undo->prev_parent, diff --git a/app/core/gimpchannelundo.h b/app/core/gimpchannelundo.h index 7bfceb96d8..985114c92e 100644 --- a/app/core/gimpchannelundo.h +++ b/app/core/gimpchannelundo.h @@ -38,8 +38,8 @@ struct _GimpChannelUndo GimpItemUndo parent_instance; GimpChannel *prev_parent; - gint prev_position; /* former position in list */ - GimpChannel *prev_channel; /* previous active channel */ + gint prev_position; /* former position in list */ + GList *prev_channels; /* previous selected channels */ }; struct _GimpChannelUndoClass diff --git a/app/core/gimpimage-duplicate.c b/app/core/gimpimage-duplicate.c index 857b71bb3f..e013cb3cb4 100644 --- a/app/core/gimpimage-duplicate.c +++ b/app/core/gimpimage-duplicate.c @@ -57,11 +57,11 @@ static void gimp_image_duplicate_colormap (GimpImage *image, GimpImage *new_image); static GimpItem * gimp_image_duplicate_item (GimpItem *item, GimpImage *new_image); -static GimpLayer * gimp_image_duplicate_layers (GimpImage *image, +static GList * gimp_image_duplicate_layers (GimpImage *image, GimpImage *new_image); -static GimpChannel * gimp_image_duplicate_channels (GimpImage *image, +static GList * gimp_image_duplicate_channels (GimpImage *image, GimpImage *new_image); -static GimpVectors * gimp_image_duplicate_vectors (GimpImage *image, +static GList * gimp_image_duplicate_vectors (GimpImage *image, GimpImage *new_image); static void gimp_image_duplicate_floating_sel (GimpImage *image, GimpImage *new_image); @@ -89,9 +89,9 @@ GimpImage * gimp_image_duplicate (GimpImage *image) { GimpImage *new_image; - GimpLayer *active_layer; - GimpChannel *active_channel; - GimpVectors *active_vectors; + GList *active_layers; + GList *active_channels; + GList *active_vectors; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); @@ -120,10 +120,10 @@ gimp_image_duplicate (GimpImage *image) gimp_image_duplicate_colormap (image, new_image); /* Copy the layers */ - active_layer = gimp_image_duplicate_layers (image, new_image); + active_layers = gimp_image_duplicate_layers (image, new_image); /* Copy the channels */ - active_channel = gimp_image_duplicate_channels (image, new_image); + active_channels = gimp_image_duplicate_channels (image, new_image); /* Copy any vectors */ active_vectors = gimp_image_duplicate_vectors (image, new_image); @@ -135,14 +135,14 @@ gimp_image_duplicate (GimpImage *image) gimp_image_duplicate_mask (image, new_image); /* Set active layer, active channel, active vectors */ - if (active_layer) - gimp_image_set_active_layer (new_image, active_layer); + if (active_layers) + gimp_image_set_selected_layers (new_image, active_layers); - if (active_channel) - gimp_image_set_active_channel (new_image, active_channel); + if (active_channels) + gimp_image_set_selected_channels (new_image, active_channels); if (active_vectors) - gimp_image_set_active_vectors (new_image, active_vectors); + gimp_image_set_selected_vectors (new_image, active_vectors); /* Copy state of all color components */ gimp_image_duplicate_components (image, new_image); @@ -221,13 +221,16 @@ gimp_image_duplicate_item (GimpItem *item, return new_item; } -static GimpLayer * +static GList * gimp_image_duplicate_layers (GimpImage *image, GimpImage *new_image) { - GimpLayer *active_layer = NULL; - GList *list; - gint count; + GList *new_selected_layers = NULL; + GList *selected_layers; + GList *list; + gint count; + + selected_layers = gimp_image_get_selected_layers (image); for (list = gimp_image_get_layer_iter (image), count = 0; list; @@ -249,23 +252,26 @@ gimp_image_duplicate_layers (GimpImage *image, gimp_object_set_name (GIMP_OBJECT (new_layer->mask), gimp_object_get_name (layer->mask)); - if (gimp_image_get_active_layer (image) == layer) - active_layer = new_layer; + if (g_list_find (selected_layers, layer)) + new_selected_layers = g_list_prepend (new_selected_layers, new_layer); gimp_image_add_layer (new_image, new_layer, NULL, count++, FALSE); } - return active_layer; + return new_selected_layers; } -static GimpChannel * +static GList * gimp_image_duplicate_channels (GimpImage *image, GimpImage *new_image) { - GimpChannel *active_channel = NULL; - GList *list; - gint count; + GList *new_selected_channels = NULL; + GList *selected_channels; + GList *list; + gint count; + + selected_channels = gimp_image_get_selected_channels (image); for (list = gimp_image_get_channel_iter (image), count = 0; list; @@ -277,23 +283,26 @@ gimp_image_duplicate_channels (GimpImage *image, new_channel = GIMP_CHANNEL (gimp_image_duplicate_item (GIMP_ITEM (channel), new_image)); - if (gimp_image_get_active_channel (image) == channel) - active_channel = new_channel; + if (g_list_find (selected_channels, channel)) + new_selected_channels = g_list_prepend (new_selected_channels, new_channel); gimp_image_add_channel (new_image, new_channel, NULL, count++, FALSE); } - return active_channel; + return new_selected_channels; } -static GimpVectors * +static GList * gimp_image_duplicate_vectors (GimpImage *image, GimpImage *new_image) { - GimpVectors *active_vectors = NULL; - GList *list; - gint count; + GList *new_selected_vectors = NULL; + GList *selected_vectors; + GList *list; + gint count; + + selected_vectors = gimp_image_get_selected_vectors (image); for (list = gimp_image_get_vectors_iter (image), count = 0; list; @@ -305,14 +314,15 @@ gimp_image_duplicate_vectors (GimpImage *image, new_vectors = GIMP_VECTORS (gimp_image_duplicate_item (GIMP_ITEM (vectors), new_image)); - if (gimp_image_get_active_vectors (image) == vectors) - active_vectors = new_vectors; + if (g_list_find (selected_vectors, vectors)) + new_selected_vectors = g_list_prepend (new_selected_vectors, new_vectors); + gimp_image_add_vectors (new_image, new_vectors, NULL, count++, FALSE); } - return active_vectors; + return new_selected_vectors; } static void diff --git a/app/core/gimpimage-quick-mask.c b/app/core/gimpimage-quick-mask.c index 9473bdee07..d9ad50319e 100644 --- a/app/core/gimpimage-quick-mask.c +++ b/app/core/gimpimage-quick-mask.c @@ -132,7 +132,7 @@ gimp_image_set_quick_mask_state (GimpImage *image, gimp_image_remove_channel (image, mask, TRUE, NULL); if (! channel_was_active) - gimp_image_unset_active_channel (image); + gimp_image_unset_selected_channels (image); gimp_image_undo_group_end (image); } diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c index 75a08d1f64..bcde9c4173 100644 --- a/app/core/gimpimage-undo-push.c +++ b/app/core/gimpimage-undo-push.c @@ -529,19 +529,22 @@ GimpUndo * gimp_image_undo_push_layer_add (GimpImage *image, const gchar *undo_desc, GimpLayer *layer, - GimpLayer *prev_layer) + GList *prev_layers) { + GList *iter; + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); g_return_val_if_fail (! gimp_item_is_attached (GIMP_ITEM (layer)), NULL); - g_return_val_if_fail (prev_layer == NULL || GIMP_IS_LAYER (prev_layer), - NULL); + + for (iter = prev_layers; iter; iter = iter->next) + g_return_val_if_fail (GIMP_IS_LAYER (iter->data), NULL); return gimp_image_undo_push (image, GIMP_TYPE_LAYER_UNDO, GIMP_UNDO_LAYER_ADD, undo_desc, GIMP_DIRTY_IMAGE_STRUCTURE, - "item", layer, - "prev-layer", prev_layer, + "item", layer, + "prev-layers", prev_layers, NULL); } @@ -551,15 +554,18 @@ gimp_image_undo_push_layer_remove (GimpImage *image, GimpLayer *layer, GimpLayer *prev_parent, gint prev_position, - GimpLayer *prev_layer) + GList *prev_layers) { + GList *iter; + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (layer)), NULL); g_return_val_if_fail (prev_parent == NULL || GIMP_IS_LAYER (prev_parent), NULL); - g_return_val_if_fail (prev_layer == NULL || GIMP_IS_LAYER (prev_layer), - NULL); + + for (iter = prev_layers; iter; iter = iter->next) + g_return_val_if_fail (GIMP_IS_LAYER (iter->data), NULL); return gimp_image_undo_push (image, GIMP_TYPE_LAYER_UNDO, GIMP_UNDO_LAYER_REMOVE, undo_desc, @@ -567,7 +573,7 @@ gimp_image_undo_push_layer_remove (GimpImage *image, "item", layer, "prev-parent", prev_parent, "prev-position", prev_position, - "prev-layer", prev_layer, + "prev-layers", prev_layers, NULL); } @@ -879,19 +885,22 @@ GimpUndo * gimp_image_undo_push_channel_add (GimpImage *image, const gchar *undo_desc, GimpChannel *channel, - GimpChannel *prev_channel) + GList *prev_channels) { + GList *iter; + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CHANNEL (channel), NULL); g_return_val_if_fail (! gimp_item_is_attached (GIMP_ITEM (channel)), NULL); - g_return_val_if_fail (prev_channel == NULL || GIMP_IS_CHANNEL (prev_channel), - NULL); + + for (iter = prev_channels; iter; iter = iter->next) + g_return_val_if_fail (GIMP_IS_CHANNEL (iter->data), NULL); return gimp_image_undo_push (image, GIMP_TYPE_CHANNEL_UNDO, GIMP_UNDO_CHANNEL_ADD, undo_desc, GIMP_DIRTY_IMAGE_STRUCTURE, - "item", channel, - "prev-channel", prev_channel, + "item", channel, + "prev-channels", prev_channels, NULL); } @@ -901,15 +910,18 @@ gimp_image_undo_push_channel_remove (GimpImage *image, GimpChannel *channel, GimpChannel *prev_parent, gint prev_position, - GimpChannel *prev_channel) + GList *prev_channels) { + GList *iter; + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_CHANNEL (channel), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (channel)), NULL); g_return_val_if_fail (prev_parent == NULL || GIMP_IS_CHANNEL (prev_parent), NULL); - g_return_val_if_fail (prev_channel == NULL || GIMP_IS_CHANNEL (prev_channel), - NULL); + + for (iter = prev_channels; iter; iter = iter->next) + g_return_val_if_fail (GIMP_IS_CHANNEL (iter->data), NULL); return gimp_image_undo_push (image, GIMP_TYPE_CHANNEL_UNDO, GIMP_UNDO_CHANNEL_REMOVE, undo_desc, @@ -917,7 +929,7 @@ gimp_image_undo_push_channel_remove (GimpImage *image, "item", channel, "prev-parent", prev_parent, "prev-position", prev_position, - "prev-channel", prev_channel, + "prev-channels", prev_channels, NULL); } @@ -946,13 +958,16 @@ GimpUndo * gimp_image_undo_push_vectors_add (GimpImage *image, const gchar *undo_desc, GimpVectors *vectors, - GimpVectors *prev_vectors) + GList *prev_vectors) { + GList *iter; + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_VECTORS (vectors), NULL); g_return_val_if_fail (! gimp_item_is_attached (GIMP_ITEM (vectors)), NULL); - g_return_val_if_fail (prev_vectors == NULL || GIMP_IS_VECTORS (prev_vectors), - NULL); + + for (iter = prev_vectors; iter; iter = iter->next) + g_return_val_if_fail (GIMP_IS_VECTORS (iter->data), NULL); return gimp_image_undo_push (image, GIMP_TYPE_VECTORS_UNDO, GIMP_UNDO_VECTORS_ADD, undo_desc, @@ -968,15 +983,18 @@ gimp_image_undo_push_vectors_remove (GimpImage *image, GimpVectors *vectors, GimpVectors *prev_parent, gint prev_position, - GimpVectors *prev_vectors) + GList *prev_vectors) { + GList *iter; + g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (GIMP_IS_VECTORS (vectors), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (vectors)), NULL); g_return_val_if_fail (prev_parent == NULL || GIMP_IS_VECTORS (prev_parent), NULL); - g_return_val_if_fail (prev_vectors == NULL || GIMP_IS_VECTORS (prev_vectors), - NULL); + + for (iter = prev_vectors; iter; iter = iter->next) + g_return_val_if_fail (GIMP_IS_VECTORS (iter->data), NULL); return gimp_image_undo_push (image, GIMP_TYPE_VECTORS_UNDO, GIMP_UNDO_VECTORS_REMOVE, undo_desc, diff --git a/app/core/gimpimage-undo-push.h b/app/core/gimpimage-undo-push.h index 6215b0d5c9..3aea6e4a1f 100644 --- a/app/core/gimpimage-undo-push.h +++ b/app/core/gimpimage-undo-push.h @@ -128,13 +128,13 @@ GimpUndo * gimp_image_undo_push_item_parasite_remove(GimpImage *image, GimpUndo * gimp_image_undo_push_layer_add (GimpImage *image, const gchar *undo_desc, GimpLayer *layer, - GimpLayer *prev_layer); + GList *prev_layers); GimpUndo * gimp_image_undo_push_layer_remove (GimpImage *image, const gchar *undo_desc, GimpLayer *layer, GimpLayer *prev_parent, gint prev_position, - GimpLayer *prev_layer); + GList *prev_layers); GimpUndo * gimp_image_undo_push_layer_mode (GimpImage *image, const gchar *undo_desc, GimpLayer *layer); @@ -214,13 +214,13 @@ GimpUndo * gimp_image_undo_push_layer_mask_show (GimpImage *image, GimpUndo * gimp_image_undo_push_channel_add (GimpImage *image, const gchar *undo_desc, GimpChannel *channel, - GimpChannel *prev_channel); + GList *prev_channels); GimpUndo * gimp_image_undo_push_channel_remove (GimpImage *image, const gchar *undo_desc, GimpChannel *channel, GimpChannel *prev_parent, gint prev_position, - GimpChannel *prev_channel); + GList *prev_channels); GimpUndo * gimp_image_undo_push_channel_color (GimpImage *image, const gchar *undo_desc, GimpChannel *channel); @@ -231,13 +231,13 @@ GimpUndo * gimp_image_undo_push_channel_color (GimpImage *image, GimpUndo * gimp_image_undo_push_vectors_add (GimpImage *image, const gchar *undo_desc, GimpVectors *vectors, - GimpVectors *prev_vectors); + GList *prev_vectors); GimpUndo * gimp_image_undo_push_vectors_remove (GimpImage *image, const gchar *undo_desc, GimpVectors *vectors, GimpVectors *prev_parent, gint prev_position, - GimpVectors *prev_vectors); + GList *prev_vectors); GimpUndo * gimp_image_undo_push_vectors_mod (GimpImage *image, const gchar *undo_desc, GimpVectors *vectors); diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index 09d970f9d5..234cfc29eb 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -99,8 +99,8 @@ enum PRECISION_CHANGED, ALPHA_CHANGED, FLOATING_SELECTION_CHANGED, - ACTIVE_CHANNEL_CHANGED, - ACTIVE_VECTORS_CHANGED, + SELECTED_CHANNELS_CHANGED, + SELECTED_VECTORS_CHANGED, SELECTED_LAYERS_CHANGED, LINKED_ITEMS_CHANGED, COMPONENT_VISIBILITY_CHANGED, @@ -255,20 +255,27 @@ static void gimp_image_channel_name_changed (GimpChannel *channel, GimpImage *image); static void gimp_image_channel_color_changed (GimpChannel *channel, GimpImage *image); -static void gimp_image_active_layer_notify (GimpItemTree *tree, - const GParamSpec *pspec, - GimpImage *image); -static void gimp_image_active_channel_notify (GimpItemTree *tree, - const GParamSpec *pspec, - GimpImage *image); -static void gimp_image_active_vectors_notify (GimpItemTree *tree, - const GParamSpec *pspec, - GimpImage *image); + +static void gimp_image_selected_layers_notify (GimpItemTree *tree, + const GParamSpec *pspec, + GimpImage *image); +static void gimp_image_selected_channels_notify (GimpItemTree *tree, + const GParamSpec *pspec, + GimpImage *image); +static void gimp_image_selected_vectors_notify (GimpItemTree *tree, + const GParamSpec *pspec, + GimpImage *image); static void gimp_image_freeze_bounding_box (GimpImage *image); static void gimp_image_thaw_bounding_box (GimpImage *image); static void gimp_image_update_bounding_box (GimpImage *image); +static gint gimp_image_layer_stack_cmp (GList *layers1, + GList *layers2); +static void gimp_image_remove_from_layer_stack (GimpImage *image, + GimpLayer *layer); +static gint gimp_image_selected_is_descendant (GimpViewable *selected, + GimpViewable *viewable); G_DEFINE_TYPE_WITH_CODE (GimpImage, gimp_image, GIMP_TYPE_VIEWABLE, G_ADD_PRIVATE (GimpImage) @@ -331,19 +338,19 @@ gimp_image_class_init (GimpImageClass *klass) NULL, NULL, NULL, G_TYPE_NONE, 0); - gimp_image_signals[ACTIVE_CHANNEL_CHANGED] = - g_signal_new ("active-channel-changed", + gimp_image_signals[SELECTED_CHANNELS_CHANGED] = + g_signal_new ("selected-channels-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_channel_changed), + G_STRUCT_OFFSET (GimpImageClass, selected_channels_changed), NULL, NULL, NULL, G_TYPE_NONE, 0); - gimp_image_signals[ACTIVE_VECTORS_CHANGED] = - g_signal_new ("active-vectors-changed", + gimp_image_signals[SELECTED_VECTORS_CHANGED] = + g_signal_new ("selected-vectors-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (GimpImageClass, active_vectors_changed), + G_STRUCT_OFFSET (GimpImageClass, selected_vectors_changed), NULL, NULL, NULL, G_TYPE_NONE, 0); @@ -584,8 +591,9 @@ gimp_image_class_init (GimpImageClass *klass) klass->precision_changed = gimp_image_real_precision_changed; klass->alpha_changed = NULL; klass->floating_selection_changed = NULL; - klass->active_channel_changed = NULL; - klass->active_vectors_changed = NULL; + klass->selected_layers_changed = NULL; + klass->selected_channels_changed = NULL; + klass->selected_vectors_changed = NULL; klass->linked_items_changed = NULL; klass->component_visibility_changed = NULL; klass->component_active_changed = NULL; @@ -770,13 +778,13 @@ gimp_image_init (GimpImage *image) image); g_signal_connect (private->layers, "notify::selected-items", - G_CALLBACK (gimp_image_active_layer_notify), + G_CALLBACK (gimp_image_selected_layers_notify), image); g_signal_connect (private->channels, "notify::selected-items", - G_CALLBACK (gimp_image_active_channel_notify), + G_CALLBACK (gimp_image_selected_channels_notify), image); g_signal_connect (private->vectors, "notify::selected-items", - G_CALLBACK (gimp_image_active_vectors_notify), + G_CALLBACK (gimp_image_selected_vectors_notify), image); g_signal_connect_swapped (private->layers->container, "update", @@ -1110,7 +1118,8 @@ gimp_image_finalize (GObject *object) if (private->layer_stack) { - g_slist_free (private->layer_stack); + g_slist_free_full (private->layer_stack, + (GDestroyNotify) g_list_free); private->layer_stack = NULL; } @@ -1721,45 +1730,56 @@ gimp_image_channel_color_changed (GimpChannel *channel, } static void -gimp_image_active_layer_notify (GimpItemTree *tree, - const GParamSpec *pspec, - GimpImage *image) +gimp_image_selected_layers_notify (GimpItemTree *tree, + const GParamSpec *pspec, + GimpImage *image) { GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image); - GimpLayer *layer = gimp_image_get_active_layer (image); + GList *layers = gimp_image_get_selected_layers (image); - if (layer) + if (layers) { /* Configure the layer stack to reflect this change */ - private->layer_stack = g_slist_remove (private->layer_stack, layer); - private->layer_stack = g_slist_prepend (private->layer_stack, layer); + GSList *prev_layers; + + prev_layers = g_slist_find_custom (private->layer_stack, layers, + (GCompareFunc) gimp_image_layer_stack_cmp); + + if (prev_layers) + { + g_list_free (prev_layers->data); + private->layer_stack = g_slist_delete_link (private->layer_stack, + prev_layers); + } + private->layer_stack = g_slist_prepend (private->layer_stack, + g_list_copy (layers)); } g_signal_emit (image, gimp_image_signals[SELECTED_LAYERS_CHANGED], 0); - if (layer && gimp_image_get_active_channel (image)) - gimp_image_set_active_channel (image, NULL); + if (layers && gimp_image_get_selected_channels (image)) + gimp_image_set_selected_channels (image, NULL); } static void -gimp_image_active_channel_notify (GimpItemTree *tree, - const GParamSpec *pspec, - GimpImage *image) +gimp_image_selected_channels_notify (GimpItemTree *tree, + const GParamSpec *pspec, + GimpImage *image) { - GimpChannel *channel = gimp_image_get_active_channel (image); + GList *channels = gimp_image_get_selected_channels (image); - g_signal_emit (image, gimp_image_signals[ACTIVE_CHANNEL_CHANGED], 0); + g_signal_emit (image, gimp_image_signals[SELECTED_CHANNELS_CHANGED], 0); - if (channel && gimp_image_get_active_layer (image)) - gimp_image_set_active_layer (image, NULL); + if (channels && gimp_image_get_selected_layers (image)) + gimp_image_set_selected_layers (image, NULL); } static void -gimp_image_active_vectors_notify (GimpItemTree *tree, - const GParamSpec *pspec, - GimpImage *image) +gimp_image_selected_vectors_notify (GimpItemTree *tree, + const GParamSpec *pspec, + GimpImage *image) { - g_signal_emit (image, gimp_image_signals[ACTIVE_VECTORS_CHANGED], 0); + g_signal_emit (image, gimp_image_signals[SELECTED_VECTORS_CHANGED], 0); } static void @@ -1838,6 +1858,96 @@ gimp_image_update_bounding_box (GimpImage *image) } } +static gint +gimp_image_layer_stack_cmp (GList *layers1, + GList *layers2) +{ + if (g_list_length (layers1) != g_list_length (layers2)) + { + /* We don't really need to order lists of layers, and only care + * about identity. + */ + return 1; + } + else + { + GList *iter; + + for (iter = layers1; iter; iter = iter->next) + { + if (! g_list_find (layers2, iter)) + return 1; + } + return 0; + } +} + +static void +gimp_image_remove_from_layer_stack (GimpImage *image, + GimpLayer *layer) +{ + GimpImagePrivate *private; + GSList *slist; + + g_return_if_fail (GIMP_IS_IMAGE (image)); + g_return_if_fail (GIMP_IS_LAYER (layer)); + + private = GIMP_IMAGE_GET_PRIVATE (image); + + /* Remove layer itself from the MRU layer stack. */ + for (slist = private->layer_stack; slist; slist = slist->next) + { + GList *layers = slist->data; + + layers = g_list_remove (layers, layer); + if (layers == NULL) + private->layer_stack = g_slist_delete_link (private->layer_stack, slist); + else + slist->data = layers; + } + + /* Also remove all children of a group layer from the layer_stack */ + if (gimp_viewable_get_children (GIMP_VIEWABLE (layer))) + { + GimpContainer *stack = gimp_viewable_get_children (GIMP_VIEWABLE (layer)); + GList *children; + GList *list; + + children = gimp_item_stack_get_item_list (GIMP_ITEM_STACK (stack)); + + for (list = children; list; list = g_list_next (list)) + { + GimpLayer *child = list->data; + + for (slist = private->layer_stack; slist; slist = slist->next) + { + GList *layers = slist->data; + + layers = g_list_remove (layers, child); + if (layers == NULL) + private->layer_stack = g_slist_delete_link (private->layer_stack, slist); + else + slist->data = layers; + } + } + + g_list_free (children); + } +} + +static gint +gimp_image_selected_is_descendant (GimpViewable *selected, + GimpViewable *viewable) +{ + /* Used as a GCompareFunc to g_list_find_custom() in order to know if + * one of the selected items is a descendant to @viewable. + */ + if (gimp_viewable_is_ancestor (viewable, selected)) + return 0; + else + return 1; +} + /* public functions */ @@ -3076,7 +3186,7 @@ gimp_image_set_component_active (GimpImage *image, /* If there is an active channel and we mess with the components, * the active channel gets unset... */ - gimp_image_unset_active_channel (image); + gimp_image_unset_selected_channels (image); g_signal_emit (image, gimp_image_signals[COMPONENT_ACTIVE_CHANGED], 0, @@ -4266,7 +4376,6 @@ gimp_image_set_active_layer (GimpImage *image, GimpLayer *layer) { GList *layers = NULL; - GList *new_layers; GimpLayer *active_layer; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); @@ -4278,11 +4387,11 @@ gimp_image_set_active_layer (GimpImage *image, if (layer) layers = g_list_prepend (NULL, layer); - new_layers = gimp_image_set_selected_layers (image, layers); + gimp_image_set_selected_layers (image, layers); g_list_free (layers); - active_layer = g_list_length (new_layers) == 1 ? new_layers->data : NULL; - g_list_free (new_layers); + layers = gimp_image_get_selected_layers (image); + active_layer = g_list_length (layers) == 1 ? layers->data : NULL; return active_layer; } @@ -4293,7 +4402,6 @@ gimp_image_set_active_channel (GimpImage *image, { GimpChannel *active_channel; GList *channels = NULL; - GList *new_channels; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); g_return_val_if_fail (channel == NULL || GIMP_IS_CHANNEL (channel), NULL); @@ -4309,36 +4417,34 @@ gimp_image_set_active_channel (GimpImage *image, if (channel) channels = g_list_prepend (NULL, channel); - new_channels = gimp_image_set_selected_channels (image, channels); + gimp_image_set_selected_channels (image, channels); g_list_free (channels); - active_channel = g_list_length (new_channels) == 1 ? new_channels->data : NULL; - g_list_free (new_channels); + channels = gimp_image_get_selected_channels (image); + active_channel = g_list_length (channels) == 1 ? channels->data : NULL; return active_channel; } -GimpChannel * -gimp_image_unset_active_channel (GimpImage *image) +void +gimp_image_unset_selected_channels (GimpImage *image) { GimpImagePrivate *private; - GimpChannel *channel; + GList *channels; - g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_if_fail (GIMP_IS_IMAGE (image)); private = GIMP_IMAGE_GET_PRIVATE (image); - channel = gimp_image_get_active_channel (image); + channels = gimp_image_get_selected_channels (image); - if (channel) + if (channels) { - gimp_image_set_active_channel (image, NULL); + gimp_image_set_selected_channels (image, NULL); if (private->layer_stack) - gimp_image_set_active_layer (image, private->layer_stack->data); + gimp_image_set_selected_layers (image, private->layer_stack->data); } - - return channel; } GimpVectors * @@ -4346,7 +4452,6 @@ gimp_image_set_active_vectors (GimpImage *image, GimpVectors *vectors) { GList *all_vectors = NULL; - GList *new_vectors; GimpVectors *active_vectors; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); @@ -4358,11 +4463,11 @@ gimp_image_set_active_vectors (GimpImage *image, if (vectors) all_vectors = g_list_prepend (NULL, vectors); - new_vectors = gimp_image_set_selected_vectors (image, all_vectors); + gimp_image_set_selected_vectors (image, all_vectors); g_list_free (all_vectors); - active_vectors = (g_list_length (new_vectors) == 1 ? new_vectors->data : NULL); - g_list_free (new_vectors); + all_vectors = gimp_image_get_selected_vectors (image); + active_vectors = (g_list_length (all_vectors) == 1 ? all_vectors->data : NULL); return active_vectors; } @@ -4403,25 +4508,24 @@ gimp_image_get_selected_vectors (GimpImage *image) return gimp_item_tree_get_selected_items (private->vectors); } -GList * +void gimp_image_set_selected_layers (GimpImage *image, GList *layers) { GimpImagePrivate *private; GimpLayer *floating_sel; - GimpLayer *active_layer; GList *selected_layers; GList *layers2; GList *iter; gboolean selection_changed = TRUE; - g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_if_fail (GIMP_IS_IMAGE (image)); layers2 = g_list_copy (layers); for (iter = layers; iter; iter = iter->next) { - g_return_val_if_fail (GIMP_IS_LAYER (iter->data), NULL); - g_return_val_if_fail (gimp_item_get_image (GIMP_ITEM (iter->data)) == image, NULL); + g_return_if_fail (GIMP_IS_LAYER (iter->data)); + g_return_if_fail (gimp_item_get_image (GIMP_ITEM (iter->data)) == image); /* Silently remove non-attached layers from selection. Do not * error out on it as it may happen for instance when selection @@ -4437,10 +4541,9 @@ gimp_image_set_selected_layers (GimpImage *image, /* Make sure the floating_sel always is the active layer */ if (floating_sel && (g_list_length (layers2) != 1 || layers2->data != floating_sel)) - return g_list_prepend (NULL, floating_sel); + return; selected_layers = gimp_image_get_selected_layers (image); - active_layer = gimp_image_get_active_layer (image); if (g_list_length (layers2) == g_list_length (selected_layers)) { @@ -4458,8 +4561,8 @@ gimp_image_set_selected_layers (GimpImage *image, if (selection_changed) { /* Don't cache selection info for the previous active layer */ - if (active_layer) - gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (active_layer)); + if (selected_layers) + gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (selected_layers->data)); gimp_item_tree_set_selected_items (private->layers, layers2); } @@ -4467,57 +4570,51 @@ gimp_image_set_selected_layers (GimpImage *image, { g_list_free (layers2); } - - return g_list_copy (gimp_image_get_selected_layers (image)); } -GList * +void gimp_image_set_selected_channels (GimpImage *image, GList *channels) { GimpImagePrivate *private; GList *iter; - g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_if_fail (GIMP_IS_IMAGE (image)); for (iter = channels; iter; iter = iter->next) { - g_return_val_if_fail (GIMP_IS_CHANNEL (iter->data), NULL); - g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (iter->data)) && - gimp_item_get_image (GIMP_ITEM (iter->data)) == image, NULL); + g_return_if_fail (GIMP_IS_CHANNEL (iter->data)); + g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (iter->data)) && + gimp_item_get_image (GIMP_ITEM (iter->data)) == image); } private = GIMP_IMAGE_GET_PRIVATE (image); /* Not if there is a floating selection */ if (g_list_length (channels) > 0 && gimp_image_get_floating_selection (image)) - return NULL; + return; gimp_item_tree_set_selected_items (private->channels, g_list_copy (channels)); - - return g_list_copy (gimp_image_get_selected_channels (image)); } -GList * +void gimp_image_set_selected_vectors (GimpImage *image, GList *vectors) { GimpImagePrivate *private; GList *iter; - g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); + g_return_if_fail (GIMP_IS_IMAGE (image)); for (iter = vectors; iter; iter = iter->next) { - g_return_val_if_fail (GIMP_IS_VECTORS (iter->data), NULL); - g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (iter->data)) && - gimp_item_get_image (GIMP_ITEM (iter->data)) == image, NULL); + g_return_if_fail (GIMP_IS_VECTORS (iter->data)); + g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (iter->data)) && + gimp_item_get_image (GIMP_ITEM (iter->data)) == image); } private = GIMP_IMAGE_GET_PRIVATE (image); gimp_item_tree_set_selected_items (private->vectors, g_list_copy (vectors)); - - return g_list_copy (gimp_image_get_selected_vectors (image)); } @@ -4759,6 +4856,7 @@ gimp_image_add_layer (GimpImage *image, gboolean push_undo) { GimpImagePrivate *private; + GList *selected_layers; gboolean old_has_alpha; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); @@ -4787,12 +4885,14 @@ gimp_image_add_layer (GimpImage *image, if (push_undo) gimp_image_undo_push_layer_add (image, C_("undo-type", "Add Layer"), layer, - gimp_image_get_active_layer (image)); + gimp_image_get_selected_layers (image)); gimp_item_tree_add_item (private->layers, GIMP_ITEM (layer), GIMP_ITEM (parent), position); - gimp_image_set_active_layer (image, layer); + selected_layers = g_list_prepend (NULL, layer); + gimp_image_set_selected_layers (image, selected_layers); + g_list_free (selected_layers); /* If the layer is a floating selection, attach it to the drawable */ if (gimp_layer_is_floating_sel (layer)) @@ -4809,10 +4909,10 @@ void gimp_image_remove_layer (GimpImage *image, GimpLayer *layer, gboolean push_undo, - GimpLayer *new_active) + GList *new_selected) { GimpImagePrivate *private; - GimpLayer *active_layer; + GList *selected_layers; gboolean old_has_alpha; const gchar *undo_desc; @@ -4846,7 +4946,7 @@ gimp_image_remove_layer (GimpImage *image, TRUE, NULL); } - active_layer = gimp_image_get_active_layer (image); + selected_layers = g_list_copy (gimp_image_get_selected_layers (image)); old_has_alpha = gimp_image_has_alpha (image); @@ -4865,38 +4965,20 @@ gimp_image_remove_layer (GimpImage *image, gimp_image_undo_push_layer_remove (image, undo_desc, layer, gimp_layer_get_parent (layer), gimp_item_get_index (GIMP_ITEM (layer)), - active_layer); + selected_layers); g_object_ref (layer); /* Make sure we're not caching any old selection info */ - if (layer == active_layer) + if (g_list_find (selected_layers, layer)) gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (layer)); - private->layer_stack = g_slist_remove (private->layer_stack, layer); + /* Remove layer and its children from the MRU layer stack. */ + gimp_image_remove_from_layer_stack (image, layer); - /* Also remove all children of a group layer from the layer_stack */ - if (gimp_viewable_get_children (GIMP_VIEWABLE (layer))) - { - GimpContainer *stack = gimp_viewable_get_children (GIMP_VIEWABLE (layer)); - GList *children; - GList *list; - - children = gimp_item_stack_get_item_list (GIMP_ITEM_STACK (stack)); - - for (list = children; list; list = g_list_next (list)) - { - private->layer_stack = g_slist_remove (private->layer_stack, - list->data); - } - - g_list_free (children); - } - - new_active = - GIMP_LAYER (gimp_item_tree_remove_item (private->layers, - GIMP_ITEM (layer), - GIMP_ITEM (new_active))); + new_selected = gimp_item_tree_remove_item (private->layers, + GIMP_ITEM (layer), + new_selected); if (gimp_layer_is_floating_sel (layer)) { @@ -4904,17 +4986,20 @@ gimp_image_remove_layer (GimpImage *image, */ floating_sel_activate_drawable (layer); } - else if (active_layer && - (layer == active_layer || - gimp_viewable_is_ancestor (GIMP_VIEWABLE (layer), - GIMP_VIEWABLE (active_layer)))) + else if (selected_layers && + (g_list_find (selected_layers, layer) || + g_list_find_custom (selected_layers, layer, + (GCompareFunc) gimp_image_selected_is_descendant))) { - gimp_image_set_active_layer (image, new_active); + gimp_image_set_selected_layers (image, new_selected); } gimp_item_end_move (GIMP_ITEM (layer), push_undo); g_object_unref (layer); + g_list_free (selected_layers); + if (new_selected) + g_list_free (new_selected); if (old_has_alpha != gimp_image_has_alpha (image)) private->flush_accum.alpha_changed = TRUE; @@ -4989,7 +5074,7 @@ gimp_image_add_layers (GimpImage *image, } if (layers) - gimp_image_set_active_layer (image, layers->data); + gimp_image_set_selected_layers (image, layers); gimp_image_undo_group_end (image); } @@ -5005,6 +5090,7 @@ gimp_image_add_channel (GimpImage *image, gboolean push_undo) { GimpImagePrivate *private; + GList *channels; g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE); @@ -5021,12 +5107,14 @@ gimp_image_add_channel (GimpImage *image, if (push_undo) gimp_image_undo_push_channel_add (image, C_("undo-type", "Add Channel"), channel, - gimp_image_get_active_channel (image)); + gimp_image_get_selected_channels (image)); gimp_item_tree_add_item (private->channels, GIMP_ITEM (channel), GIMP_ITEM (parent), position); - gimp_image_set_active_channel (image, channel); + channels = g_list_prepend (NULL, channel); + gimp_image_set_selected_channels (image, channels); + g_list_free (channels); return TRUE; } @@ -5035,10 +5123,10 @@ void gimp_image_remove_channel (GimpImage *image, GimpChannel *channel, gboolean push_undo, - GimpChannel *new_active) + GList *new_selected) { GimpImagePrivate *private; - GimpChannel *active_channel; + GList *selected_channels; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (GIMP_IS_CHANNEL (channel)); @@ -5068,35 +5156,36 @@ gimp_image_remove_channel (GimpImage *image, private = GIMP_IMAGE_GET_PRIVATE (image); - active_channel = gimp_image_get_active_channel (image); + selected_channels = gimp_image_get_selected_channels (image); if (push_undo) gimp_image_undo_push_channel_remove (image, C_("undo-type", "Remove Channel"), channel, gimp_channel_get_parent (channel), gimp_item_get_index (GIMP_ITEM (channel)), - active_channel); + selected_channels); g_object_ref (channel); - new_active = - GIMP_CHANNEL (gimp_item_tree_remove_item (private->channels, - GIMP_ITEM (channel), - GIMP_ITEM (new_active))); + new_selected = gimp_item_tree_remove_item (private->channels, + GIMP_ITEM (channel), + new_selected); - if (active_channel && - (channel == active_channel || - gimp_viewable_is_ancestor (GIMP_VIEWABLE (channel), - GIMP_VIEWABLE (active_channel)))) + if (selected_channels && + (g_list_find (selected_channels, channel) || + g_list_find_custom (selected_channels, channel, + (GCompareFunc) gimp_image_selected_is_descendant))) { - if (new_active) - gimp_image_set_active_channel (image, new_active); + if (new_selected) + gimp_image_set_selected_channels (image, new_selected); else - gimp_image_unset_active_channel (image); + gimp_image_unset_selected_channels (image); } gimp_item_end_move (GIMP_ITEM (channel), push_undo); g_object_unref (channel); + if (new_selected) + g_list_free (new_selected); if (push_undo) gimp_image_undo_group_end (image); @@ -5129,7 +5218,7 @@ gimp_image_add_vectors (GimpImage *image, if (push_undo) gimp_image_undo_push_vectors_add (image, C_("undo-type", "Add Path"), vectors, - gimp_image_get_active_vectors (image)); + gimp_image_get_selected_vectors (image)); gimp_item_tree_add_item (private->vectors, GIMP_ITEM (vectors), GIMP_ITEM (parent), position); @@ -5143,10 +5232,10 @@ void gimp_image_remove_vectors (GimpImage *image, GimpVectors *vectors, gboolean push_undo, - GimpVectors *new_active) + GList *new_selected) { GimpImagePrivate *private; - GimpVectors *active_vectors; + GList *selected_vectors; g_return_if_fail (GIMP_IS_IMAGE (image)); g_return_if_fail (GIMP_IS_VECTORS (vectors)); @@ -5161,32 +5250,33 @@ gimp_image_remove_vectors (GimpImage *image, gimp_item_start_move (GIMP_ITEM (vectors), push_undo); - active_vectors = gimp_image_get_active_vectors (image); + selected_vectors = gimp_image_get_selected_vectors (image); if (push_undo) gimp_image_undo_push_vectors_remove (image, C_("undo-type", "Remove Path"), vectors, gimp_vectors_get_parent (vectors), gimp_item_get_index (GIMP_ITEM (vectors)), - active_vectors); + selected_vectors); g_object_ref (vectors); - new_active = - GIMP_VECTORS (gimp_item_tree_remove_item (private->vectors, - GIMP_ITEM (vectors), - GIMP_ITEM (new_active))); + new_selected = gimp_item_tree_remove_item (private->vectors, + GIMP_ITEM (vectors), + new_selected); - if (active_vectors && - (vectors == active_vectors || - gimp_viewable_is_ancestor (GIMP_VIEWABLE (vectors), - GIMP_VIEWABLE (active_vectors)))) + if (selected_vectors && + (g_list_find (selected_vectors, vectors) || + g_list_find_custom (selected_vectors, vectors, + (GCompareFunc) gimp_image_selected_is_descendant))) { - gimp_image_set_active_vectors (image, new_active); + gimp_image_set_selected_vectors (image, new_selected); } gimp_item_end_move (GIMP_ITEM (vectors), push_undo); g_object_unref (vectors); + if (new_selected) + g_list_free (new_selected); if (push_undo) gimp_image_undo_group_end (image); diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h index fc09fe5f80..33d973a3ba 100644 --- a/app/core/gimpimage.h +++ b/app/core/gimpimage.h @@ -54,8 +54,8 @@ struct _GimpImageClass void (* precision_changed) (GimpImage *image); void (* alpha_changed) (GimpImage *image); void (* floating_selection_changed) (GimpImage *image); - void (* active_channel_changed) (GimpImage *image); - void (* active_vectors_changed) (GimpImage *image); + void (* selected_channels_changed) (GimpImage *image); + void (* selected_vectors_changed) (GimpImage *image); void (* selected_layers_changed) (GimpImage *image); void (* linked_items_changed) (GimpImage *image); void (* component_visibility_changed) (GimpImage *image, @@ -375,7 +375,7 @@ GimpLayer * gimp_image_set_active_layer (GimpImage *image, GimpLayer *layer); GimpChannel * gimp_image_set_active_channel (GimpImage *image, GimpChannel *channel); -GimpChannel * gimp_image_unset_active_channel (GimpImage *image); +void gimp_image_unset_selected_channels (GimpImage *image); GimpVectors * gimp_image_set_active_vectors (GimpImage *image, GimpVectors *vectors); @@ -383,11 +383,11 @@ GList * gimp_image_get_selected_layers (GimpImage *image); GList * gimp_image_get_selected_channels (GimpImage *image); GList * gimp_image_get_selected_vectors (GimpImage *image); -GList * gimp_image_set_selected_layers (GimpImage *image, +void gimp_image_set_selected_layers (GimpImage *image, GList *layers); -GList * gimp_image_set_selected_channels (GimpImage *image, +void gimp_image_set_selected_channels (GimpImage *image, GList *channels); -GList * gimp_image_set_selected_vectors (GimpImage *image, +void gimp_image_set_selected_vectors (GimpImage *image, GList *vectors); GimpLayer * gimp_image_get_layer_by_tattoo (GimpImage *image, @@ -429,7 +429,7 @@ gboolean gimp_image_add_layer (GimpImage *image, void gimp_image_remove_layer (GimpImage *image, GimpLayer *layer, gboolean push_undo, - GimpLayer *new_active); + GList *new_selected); void gimp_image_add_layers (GimpImage *image, GList *layers, @@ -449,7 +449,7 @@ gboolean gimp_image_add_channel (GimpImage *image, void gimp_image_remove_channel (GimpImage *image, GimpChannel *channel, gboolean push_undo, - GimpChannel *new_active); + GList *new_selected); gboolean gimp_image_add_vectors (GimpImage *image, GimpVectors *vectors, @@ -459,7 +459,7 @@ gboolean gimp_image_add_vectors (GimpImage *image, void gimp_image_remove_vectors (GimpImage *image, GimpVectors *vectors, gboolean push_undo, - GimpVectors *new_active); + GList *new_selected); gboolean gimp_image_coords_in_active_pickable (GimpImage *image, const GimpCoords *coords, diff --git a/app/core/gimpitemtree.c b/app/core/gimpitemtree.c index 4cceaaf2cc..c83821d927 100644 --- a/app/core/gimpitemtree.c +++ b/app/core/gimpitemtree.c @@ -565,10 +565,10 @@ gimp_item_tree_add_item (GimpItemTree *tree, gimp_item_unset_removed (item); } -GimpItem * +GList * gimp_item_tree_remove_item (GimpItemTree *tree, GimpItem *item, - GimpItem *new_active) + GList *new_selected) { GimpItemTreePrivate *private; GimpItem *parent; @@ -615,26 +615,34 @@ gimp_item_tree_remove_item (GimpItemTree *tree, gimp_item_removed (item); - if (! new_active) + if (! new_selected) { - gint n_children = gimp_container_get_n_children (container); + GimpItem *selected = NULL; + gint n_children = gimp_container_get_n_children (container); if (n_children > 0) { index = CLAMP (index, 0, n_children - 1); - new_active = + selected = GIMP_ITEM (gimp_container_get_child_by_index (container, index)); } else if (parent) { - new_active = parent; + selected = parent; } + + if (selected) + new_selected = g_list_prepend (NULL, selected); + } + else + { + new_selected = g_list_copy (new_selected); } g_object_unref (item); - return new_active; + return new_selected; } gboolean diff --git a/app/core/gimpitemtree.h b/app/core/gimpitemtree.h index 0678999826..2367a9b9b8 100644 --- a/app/core/gimpitemtree.h +++ b/app/core/gimpitemtree.h @@ -72,9 +72,9 @@ void gimp_item_tree_add_item (GimpItemTree *tree, GimpItem *item, GimpItem *parent, gint position); -GimpItem * gimp_item_tree_remove_item (GimpItemTree *tree, +GList * gimp_item_tree_remove_item (GimpItemTree *tree, GimpItem *item, - GimpItem *new_active); + GList *new_selected); gboolean gimp_item_tree_reorder_item (GimpItemTree *tree, GimpItem *item, diff --git a/app/core/gimplayer-floating-selection.c b/app/core/gimplayer-floating-selection.c index 80222a2b0c..cb0a482cdf 100644 --- a/app/core/gimplayer-floating-selection.c +++ b/app/core/gimplayer-floating-selection.c @@ -228,11 +228,19 @@ floating_sel_activate_drawable (GimpLayer *layer) } else if (GIMP_IS_CHANNEL (drawable)) { - gimp_image_set_active_channel (image, GIMP_CHANNEL (drawable)); + GList *channels = g_list_prepend (NULL, drawable); + + gimp_image_set_selected_channels (image, channels); + + g_list_free (channels); } else { - gimp_image_set_active_layer (image, GIMP_LAYER (drawable)); + GList *layers = g_list_prepend (NULL, drawable); + + gimp_image_set_selected_layers (image, layers); + + g_list_free (layers); } } diff --git a/app/core/gimplayerundo.c b/app/core/gimplayerundo.c index 66abf8b208..2cae9ce81c 100644 --- a/app/core/gimplayerundo.c +++ b/app/core/gimplayerundo.c @@ -34,11 +34,12 @@ enum PROP_0, PROP_PREV_PARENT, PROP_PREV_POSITION, - PROP_PREV_LAYER + PROP_PREV_LAYERS }; static void gimp_layer_undo_constructed (GObject *object); +static void gimp_layer_undo_finalize (GObject *object); static void gimp_layer_undo_set_property (GObject *object, guint property_id, const GValue *value, @@ -69,6 +70,7 @@ gimp_layer_undo_class_init (GimpLayerUndoClass *klass) GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass); object_class->constructed = gimp_layer_undo_constructed; + object_class->finalize = gimp_layer_undo_finalize; object_class->set_property = gimp_layer_undo_set_property; object_class->get_property = gimp_layer_undo_get_property; @@ -89,16 +91,16 @@ gimp_layer_undo_class_init (GimpLayerUndoClass *klass) GIMP_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - g_object_class_install_property (object_class, PROP_PREV_LAYER, - g_param_spec_object ("prev-layer", NULL, NULL, - GIMP_TYPE_LAYER, - GIMP_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, PROP_PREV_LAYERS, + g_param_spec_pointer ("prev-layers", NULL, NULL, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); } static void gimp_layer_undo_init (GimpLayerUndo *undo) { + undo->prev_layers = NULL; } static void @@ -109,6 +111,15 @@ gimp_layer_undo_constructed (GObject *object) gimp_assert (GIMP_IS_LAYER (GIMP_ITEM_UNDO (object)->item)); } +static void +gimp_layer_undo_finalize (GObject *object) +{ + GimpLayerUndo *undo = GIMP_LAYER_UNDO (object); + + g_clear_pointer (&undo->prev_layers, g_list_free); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} static void gimp_layer_undo_set_property (GObject *object, guint property_id, @@ -125,8 +136,8 @@ gimp_layer_undo_set_property (GObject *object, case PROP_PREV_POSITION: layer_undo->prev_position = g_value_get_int (value); break; - case PROP_PREV_LAYER: - layer_undo->prev_layer = g_value_get_object (value); + case PROP_PREV_LAYERS: + layer_undo->prev_layers = g_list_copy (g_value_get_pointer (value)); break; default: @@ -151,8 +162,8 @@ gimp_layer_undo_get_property (GObject *object, case PROP_PREV_POSITION: g_value_set_int (value, layer_undo->prev_position); break; - case PROP_PREV_LAYER: - g_value_set_object (value, layer_undo->prev_layer); + case PROP_PREV_LAYERS: + g_value_set_pointer (value, layer_undo->prev_layers); break; default: @@ -198,14 +209,15 @@ gimp_layer_undo_pop (GimpUndo *undo, layer_undo->prev_position = gimp_item_get_index (GIMP_ITEM (layer)); gimp_image_remove_layer (undo->image, layer, FALSE, - layer_undo->prev_layer); + layer_undo->prev_layers); } else { /* restore layer */ /* record the active layer */ - layer_undo->prev_layer = gimp_image_get_active_layer (undo->image); + g_clear_pointer (&layer_undo->prev_layers, g_list_free); + layer_undo->prev_layers = g_list_copy (gimp_image_get_selected_layers (undo->image)); gimp_image_add_layer (undo->image, layer, layer_undo->prev_parent, diff --git a/app/core/gimplayerundo.h b/app/core/gimplayerundo.h index 700fce87ae..5d99b2773d 100644 --- a/app/core/gimplayerundo.h +++ b/app/core/gimplayerundo.h @@ -39,7 +39,7 @@ struct _GimpLayerUndo GimpLayer *prev_parent; gint prev_position; /* former position in list */ - GimpLayer *prev_layer; /* previous active layer */ + GList *prev_layers; /* previous selected layers */ }; struct _GimpLayerUndoClass diff --git a/app/display/gimpdisplayshell-handlers.c b/app/display/gimpdisplayshell-handlers.c index 2d7e65e89b..f1d340f913 100644 --- a/app/display/gimpdisplayshell-handlers.c +++ b/app/display/gimpdisplayshell-handlers.c @@ -295,7 +295,7 @@ gimp_display_shell_connect (GimpDisplayShell *shell) G_CALLBACK (gimp_display_shell_exported_handler), shell); - g_signal_connect (image, "active-vectors-changed", + g_signal_connect (image, "selected-vectors-changed", G_CALLBACK (gimp_display_shell_active_vectors_handler), shell); diff --git a/app/pdb/image-cmds.c b/app/pdb/image-cmds.c index 1ab6ce4bdc..2d814403e3 100644 --- a/app/pdb/image-cmds.c +++ b/app/pdb/image-cmds.c @@ -593,7 +593,7 @@ image_unset_active_channel_invoker (GimpProcedure *procedure, if (success) { - gimp_image_unset_active_channel (image); + gimp_image_unset_selected_channels (image); } return gimp_procedure_get_return_values (procedure, success, diff --git a/app/tools/gimpbucketfilltool.c b/app/tools/gimpbucketfilltool.c index acab6f2d03..3c988f6af0 100644 --- a/app/tools/gimpbucketfilltool.c +++ b/app/tools/gimpbucketfilltool.c @@ -961,7 +961,7 @@ gimp_bucket_fill_tool_reset_line_art (GimpBucketFillTool *tool) g_signal_connect_swapped (image, "selected-layers-changed", G_CALLBACK (gimp_bucket_fill_tool_reset_line_art), tool); - g_signal_connect_swapped (image, "active-channel-changed", + g_signal_connect_swapped (image, "selected-channels-changed", G_CALLBACK (gimp_bucket_fill_tool_reset_line_art), tool); diff --git a/app/tools/gimpmovetool.c b/app/tools/gimpmovetool.c index 8d1d617199..0b750a252b 100644 --- a/app/tools/gimpmovetool.c +++ b/app/tools/gimpmovetool.c @@ -155,8 +155,8 @@ gimp_move_tool_init (GimpMoveTool *move_tool) move_tool->saved_type = GIMP_TRANSFORM_TYPE_LAYER; - move_tool->old_active_layer = NULL; - move_tool->old_active_vectors = NULL; + move_tool->old_selected_layers = NULL; + move_tool->old_selected_vectors = NULL; } static void @@ -165,6 +165,8 @@ gimp_move_tool_finalize (GObject *object) GimpMoveTool *move = GIMP_MOVE_TOOL (object); g_clear_pointer (&move->guides, g_list_free); + g_clear_pointer (&move->old_selected_layers, g_list_free); + g_clear_pointer (&move->old_selected_vectors, g_list_free); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -206,10 +208,13 @@ gimp_move_tool_button_press (GimpTool *tool, FUNSCALEY (shell, snap_distance)); if (vectors) { - move->old_active_vectors = - gimp_image_get_active_vectors (image); + GList *new_selected_vectors = g_list_prepend (NULL, vectors); - gimp_image_set_active_vectors (image, vectors); + move->old_selected_vectors = + g_list_copy (gimp_image_get_selected_vectors (image)); + + gimp_image_set_selected_vectors (image, new_selected_vectors); + g_list_free (new_selected_vectors); } else { @@ -254,9 +259,12 @@ gimp_move_tool_button_press (GimpTool *tool, } else { - move->old_active_layer = gimp_image_get_active_layer (image); + GList *new_selected_layers = g_list_prepend (NULL, layer); - gimp_image_set_active_layer (image, layer); + move->old_selected_layers = g_list_copy (gimp_image_get_selected_layers (image)); + + gimp_image_set_selected_layers (image, new_selected_layers); + g_list_free (new_selected_layers); } } else @@ -388,18 +396,18 @@ gimp_move_tool_button_release (GimpTool *tool, if (! config->move_tool_changes_active || (release_type == GIMP_BUTTON_RELEASE_CANCEL)) { - if (move->old_active_layer) + if (move->old_selected_layers) { - gimp_image_set_active_layer (image, move->old_active_layer); - move->old_active_layer = NULL; + gimp_image_set_selected_layers (image, move->old_selected_layers); + g_clear_pointer (&move->old_selected_layers, g_list_free); flush = TRUE; } - if (move->old_active_vectors) + if (move->old_selected_vectors) { - gimp_image_set_active_vectors (image, move->old_active_vectors); - move->old_active_vectors = NULL; + gimp_image_set_selected_vectors (image, move->old_selected_vectors); + g_clear_pointer (&move->old_selected_vectors, g_list_free); flush = TRUE; } diff --git a/app/tools/gimpmovetool.h b/app/tools/gimpmovetool.h index a597e0124f..5f51b7f510 100644 --- a/app/tools/gimpmovetool.h +++ b/app/tools/gimpmovetool.h @@ -44,8 +44,8 @@ struct _GimpMoveTool GimpTransformType saved_type; - GimpLayer *old_active_layer; - GimpVectors *old_active_vectors; + GList *old_selected_layers; + GList *old_selected_vectors; }; struct _GimpMoveToolClass diff --git a/app/tools/gimptexttool.c b/app/tools/gimptexttool.c index b5172c17d0..37d0d4ca7d 100644 --- a/app/tools/gimptexttool.c +++ b/app/tools/gimptexttool.c @@ -487,12 +487,15 @@ gimp_text_tool_button_press (GimpTool *tool, if (text_layer && text_layer != text_tool->layer) { + GList *selection = g_list_prepend (NULL, text_layer); + if (text_tool->image == image) g_signal_handlers_block_by_func (image, gimp_text_tool_layer_changed, text_tool); - gimp_image_set_active_layer (image, GIMP_LAYER (text_layer)); + gimp_image_set_selected_layers (image, selection); + g_list_free (selection); if (text_tool->image == image) g_signal_handlers_unblock_by_func (image, @@ -1806,18 +1809,27 @@ static void gimp_text_tool_layer_changed (GimpImage *image, GimpTextTool *text_tool) { - GimpLayer *layer = gimp_image_get_active_layer (image); + GList *layers = gimp_image_get_selected_layers (image); - if (layer != GIMP_LAYER (text_tool->layer)) + if (g_list_length (layers) != 1 || layers->data != text_tool->layer) { GimpTool *tool = GIMP_TOOL (text_tool); GimpDisplay *display = tool->display; if (display) { + GimpLayer *layer = NULL; + gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display); - if (gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), + if (g_list_length (layers) == 1) + layer = layers->data; + + /* The tool can only be started when a single layer is + * selected and this is a text layer. + */ + if (layer && + gimp_text_tool_set_drawable (text_tool, GIMP_DRAWABLE (layer), FALSE) && GIMP_LAYER (text_tool->layer) == layer) { diff --git a/app/tools/gimpvectortool.c b/app/tools/gimpvectortool.c index 3040a2a25a..76789cfd45 100644 --- a/app/tools/gimpvectortool.c +++ b/app/tools/gimpvectortool.c @@ -609,7 +609,7 @@ gimp_vector_tool_set_vectors (GimpVectorTool *vector_tool, vector_tool->vectors = g_object_ref (vectors); - g_signal_connect_object (gimp_item_get_image (item), "active-vectors-changed", + g_signal_connect_object (gimp_item_get_image (item), "selected-vectors-changed", G_CALLBACK (gimp_vector_tool_vectors_changed), vector_tool, 0); g_signal_connect_object (vectors, "removed", diff --git a/app/vectors/gimpvectorsundo.c b/app/vectors/gimpvectorsundo.c index 39857ecf60..e947fd59ff 100644 --- a/app/vectors/gimpvectorsundo.c +++ b/app/vectors/gimpvectorsundo.c @@ -40,6 +40,7 @@ enum static void gimp_vectors_undo_constructed (GObject *object); +static void gimp_vectors_undo_finalize (GObject *object); static void gimp_vectors_undo_set_property (GObject *object, guint property_id, const GValue *value, @@ -70,6 +71,7 @@ gimp_vectors_undo_class_init (GimpVectorsUndoClass *klass) GimpUndoClass *undo_class = GIMP_UNDO_CLASS (klass); object_class->constructed = gimp_vectors_undo_constructed; + object_class->finalize = gimp_vectors_undo_finalize; object_class->set_property = gimp_vectors_undo_set_property; object_class->get_property = gimp_vectors_undo_get_property; @@ -91,15 +93,15 @@ gimp_vectors_undo_class_init (GimpVectorsUndoClass *klass) G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_PREV_VECTORS, - g_param_spec_object ("prev-vectors", NULL, NULL, - GIMP_TYPE_VECTORS, - GIMP_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY)); + g_param_spec_pointer ("prev-vectors", NULL, NULL, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); } static void gimp_vectors_undo_init (GimpVectorsUndo *undo) { + undo->prev_vectors = NULL; } static void @@ -110,6 +112,16 @@ gimp_vectors_undo_constructed (GObject *object) gimp_assert (GIMP_IS_VECTORS (GIMP_ITEM_UNDO (object)->item)); } +static void +gimp_vectors_undo_finalize (GObject *object) +{ + GimpVectorsUndo *undo = GIMP_VECTORS_UNDO (object); + + g_clear_pointer (&undo->prev_vectors, g_list_free); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + static void gimp_vectors_undo_set_property (GObject *object, guint property_id, @@ -127,7 +139,7 @@ gimp_vectors_undo_set_property (GObject *object, vectors_undo->prev_position = g_value_get_int (value); break; case PROP_PREV_VECTORS: - vectors_undo->prev_vectors = g_value_get_object (value); + vectors_undo->prev_vectors = g_list_copy (g_value_get_pointer (value)); break; default: @@ -153,7 +165,7 @@ gimp_vectors_undo_get_property (GObject *object, g_value_set_int (value, vectors_undo->prev_position); break; case PROP_PREV_VECTORS: - g_value_set_object (value, vectors_undo->prev_vectors); + g_value_set_pointer (value, vectors_undo->prev_vectors); break; default: @@ -206,7 +218,8 @@ gimp_vectors_undo_pop (GimpUndo *undo, /* restore vectors */ /* record the active vectors */ - vectors_undo->prev_vectors = gimp_image_get_active_vectors (undo->image); + g_clear_pointer (&vectors_undo->prev_vectors, g_list_free); + vectors_undo->prev_vectors = g_list_copy (gimp_image_get_selected_vectors (undo->image)); gimp_image_add_vectors (undo->image, vectors, vectors_undo->prev_parent, diff --git a/app/vectors/gimpvectorsundo.h b/app/vectors/gimpvectorsundo.h index 9b5434669b..3df54f2228 100644 --- a/app/vectors/gimpvectorsundo.h +++ b/app/vectors/gimpvectorsundo.h @@ -38,8 +38,8 @@ struct _GimpVectorsUndo GimpItemUndo parent_instance; GimpVectors *prev_parent; - gint prev_position; /* former position in list */ - GimpVectors *prev_vectors; /* previous active vectors */ + gint prev_position; /* former position in list */ + GList *prev_vectors; /* previous selected vectors */ }; struct _GimpVectorsUndoClass diff --git a/app/widgets/gimpchanneltreeview.c b/app/widgets/gimpchanneltreeview.c index a6fb415fe4..4f97fb090b 100644 --- a/app/widgets/gimpchanneltreeview.c +++ b/app/widgets/gimpchanneltreeview.c @@ -105,7 +105,7 @@ gimp_channel_tree_view_class_init (GimpChannelTreeViewClass *klass) iv_class->set_image = gimp_channel_tree_view_set_image; iv_class->item_type = GIMP_TYPE_CHANNEL; - iv_class->signal_name = "active-channel-changed"; + iv_class->signal_name = "selected-channels-changed"; iv_class->get_container = gimp_image_get_channels; iv_class->get_active_item = (GimpGetItemFunc) gimp_image_get_active_channel; diff --git a/app/widgets/gimpvectorstreeview.c b/app/widgets/gimpvectorstreeview.c index d1e9fb6496..6b4d2eedfc 100644 --- a/app/widgets/gimpvectorstreeview.c +++ b/app/widgets/gimpvectorstreeview.c @@ -88,7 +88,7 @@ gimp_vectors_tree_view_class_init (GimpVectorsTreeViewClass *klass) view_class->drop_svg = gimp_vectors_tree_view_drop_svg; iv_class->item_type = GIMP_TYPE_VECTORS; - iv_class->signal_name = "active-vectors-changed"; + iv_class->signal_name = "selected-vectors-changed"; iv_class->get_container = gimp_image_get_vectors; iv_class->get_active_item = (GimpGetItemFunc) gimp_image_get_active_vectors; diff --git a/pdb/groups/image.pdb b/pdb/groups/image.pdb index bf94632432..9b5011aa94 100644 --- a/pdb/groups/image.pdb +++ b/pdb/groups/image.pdb @@ -387,7 +387,7 @@ HELP %invoke = ( code => <<'CODE' { - gimp_image_unset_active_channel (image); + gimp_image_unset_selected_channels (image); } CODE );