[gimp] app: make painting possibly multi-drawable aware.



commit 8934d439759c49a472a42de9b4b23acb63f0c509
Author: Jehan <jehan girinstud io>
Date:   Mon Aug 16 23:46:32 2021 +0200

    app: make painting possibly multi-drawable aware.
    
    - Make the various virtual methods of GimpPaintCore use a list of
      drawables as argument instead of a single drawable.
    - gimp_brush_core_eval_transform_dynamics() can work with an image as
      argument rather than a drawable as it doesn't actually depends on
      specific drawable data.
    - New function gimp_paint_tool_enable_multi_paint() to be used in init()
      method of paint tools to announce that this tool can work with
      multiple layers selected.
    - Use gimp_paint_tool_enable_multi_paint() in the GimpSourceTool base
      class only for now.
    
    This is a first step for multi-layer drawing, but we don't want it to be
    possible in just any random cases, which is why I add a special function
    to advertize this capability. We will use it for special-casing the
    clone (as well as heal and perspective tools most likely) tool to work
    on several layers at once. At this step, it is still very bugged and not
    really working properly. In particular, since we don't process the
    drawable offset early anymore (because it makes no sense when we pass a
    list of drawables with different offsets), I suspect that all the
    offset-related code will be very broken.

 app/paint/gimpairbrush.c         |  22 ++-
 app/paint/gimpbrushcore.c        |  44 +++--
 app/paint/gimpbrushcore.h        |   2 +-
 app/paint/gimpclone.c            |   6 +-
 app/paint/gimpconvolve.c         |  11 +-
 app/paint/gimpdodgeburn.c        |  13 +-
 app/paint/gimpheal.c             |   8 +-
 app/paint/gimpink.c              |   9 +-
 app/paint/gimpmybrushcore.c      |  26 +--
 app/paint/gimppaintbrush.c       |  30 ++--
 app/paint/gimppaintcore-stroke.c |  56 +++---
 app/paint/gimppaintcore.c        | 366 +++++++++++++++++++++------------------
 app/paint/gimppaintcore.h        |  25 +--
 app/paint/gimpperspectiveclone.c |  15 +-
 app/paint/gimpsmudge.c           |  14 +-
 app/paint/gimpsourcecore.c       |  24 +--
 app/tools/gimpbrushtool.c        |  14 +-
 app/tools/gimppainttool-paint.c  | 102 +++++------
 app/tools/gimppainttool.c        | 184 +++++++++++---------
 app/tools/gimppainttool.h        |   7 +-
 app/tools/gimpsourcetool.c       |   2 +
 21 files changed, 540 insertions(+), 440 deletions(-)
---
diff --git a/app/paint/gimpairbrush.c b/app/paint/gimpairbrush.c
index 6bd9fb2806..fc61409e14 100644
--- a/app/paint/gimpairbrush.c
+++ b/app/paint/gimpairbrush.c
@@ -49,7 +49,7 @@ enum
 static void       gimp_airbrush_finalize (GObject          *object);
 
 static void       gimp_airbrush_paint    (GimpPaintCore    *paint_core,
-                                          GimpDrawable     *drawable,
+                                          GList            *drawables,
                                           GimpPaintOptions *paint_options,
                                           GimpSymmetry     *sym,
                                           GimpPaintState    paint_state,
@@ -123,7 +123,7 @@ gimp_airbrush_finalize (GObject *object)
 
 static void
 gimp_airbrush_paint (GimpPaintCore    *paint_core,
-                     GimpDrawable     *drawable,
+                     GList            *drawables,
                      GimpPaintOptions *paint_options,
                      GimpSymmetry     *sym,
                      GimpPaintState    paint_state,
@@ -133,6 +133,8 @@ gimp_airbrush_paint (GimpPaintCore    *paint_core,
   GimpAirbrushOptions *options  = GIMP_AIRBRUSH_OPTIONS (paint_options);
   GimpDynamics        *dynamics = GIMP_BRUSH_CORE (paint_core)->dynamics;
 
+  g_return_if_fail (g_list_length (drawables) == 1);
+
   if (airbrush->timeout_id)
     {
       g_source_remove (airbrush->timeout_id);
@@ -142,18 +144,18 @@ gimp_airbrush_paint (GimpPaintCore    *paint_core,
   switch (paint_state)
     {
     case GIMP_PAINT_STATE_INIT:
-      GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable,
+      GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawables,
                                                    paint_options,
                                                    sym,
                                                    paint_state, time);
       break;
 
     case GIMP_PAINT_STATE_MOTION:
-      gimp_airbrush_motion (paint_core, drawable, paint_options, sym);
+      gimp_airbrush_motion (paint_core, drawables->data, paint_options, sym);
 
       if ((options->rate != 0.0) && ! options->motion_only)
         {
-          GimpImage  *image = gimp_item_get_image (GIMP_ITEM (drawable));
+          GimpImage  *image = gimp_item_get_image (GIMP_ITEM (drawables->data));
           gdouble     fade_point;
           gdouble     dynamic_rate;
           gint        timeout;
@@ -162,7 +164,7 @@ gimp_airbrush_paint (GimpPaintCore    *paint_core,
           fade_point = gimp_paint_options_get_fade (paint_options, image,
                                                     paint_core->pixel_dist);
 
-          airbrush->drawable      = drawable;
+          airbrush->drawable      = drawables->data;
           airbrush->paint_options = paint_options;
 
           if (airbrush->sym)
@@ -191,7 +193,7 @@ gimp_airbrush_paint (GimpPaintCore    *paint_core,
       break;
 
     case GIMP_PAINT_STATE_FINISH:
-      GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable,
+      GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawables,
                                                    paint_options,
                                                    sym,
                                                    paint_state, time);
@@ -250,16 +252,20 @@ gimp_airbrush_timeout (gpointer data)
 void
 gimp_airbrush_stamp (GimpAirbrush *airbrush)
 {
+  GList *drawables;
+
   g_return_if_fail (GIMP_IS_AIRBRUSH (airbrush));
 
   gimp_symmetry_set_origin (airbrush->sym,
                             airbrush->drawable, &airbrush->coords);
 
+  drawables = g_list_prepend (NULL, airbrush->drawable),
   gimp_airbrush_paint (GIMP_PAINT_CORE (airbrush),
-                       airbrush->drawable,
+                       drawables,
                        airbrush->paint_options,
                        airbrush->sym,
                        GIMP_PAINT_STATE_MOTION, 0);
+  g_list_free (drawables);
 
   gimp_symmetry_clear_origin (airbrush->sym);
 }
diff --git a/app/paint/gimpbrushcore.c b/app/paint/gimpbrushcore.c
index 4b1e8cd3a8..d9796ae489 100644
--- a/app/paint/gimpbrushcore.c
+++ b/app/paint/gimpbrushcore.c
@@ -65,22 +65,22 @@ enum
 static void      gimp_brush_core_finalize           (GObject          *object);
 
 static gboolean  gimp_brush_core_start              (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable,
+                                                     GList            *drawables,
                                                      GimpPaintOptions *paint_options,
                                                      const GimpCoords *coords,
                                                      GError          **error);
 static gboolean  gimp_brush_core_pre_paint          (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable,
+                                                     GList            *drawables,
                                                      GimpPaintOptions *paint_options,
                                                      GimpPaintState    paint_state,
                                                      guint32           time);
 static void      gimp_brush_core_post_paint         (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable,
+                                                     GList            *drawables,
                                                      GimpPaintOptions *paint_options,
                                                      GimpPaintState    paint_state,
                                                      guint32           time);
 static void      gimp_brush_core_interpolate        (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable,
+                                                     GList            *drawables,
                                                      GimpPaintOptions *paint_options,
                                                      guint32           time);
 
@@ -249,7 +249,7 @@ gimp_brush_core_finalize (GObject *object)
 
 static gboolean
 gimp_brush_core_pre_paint (GimpPaintCore    *paint_core,
-                           GimpDrawable     *drawable,
+                           GList            *drawables,
                            GimpPaintOptions *paint_options,
                            GimpPaintState    paint_state,
                            guint32           time)
@@ -281,7 +281,7 @@ gimp_brush_core_pre_paint (GimpPaintCore    *paint_core,
       /*No drawing anything if the scale is too small*/
       if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush)
         {
-          GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
+          GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawables->data));
           gdouble    fade_point;
 
           if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_dynamic_transforming_brush)
@@ -337,7 +337,7 @@ gimp_brush_core_pre_paint (GimpPaintCore    *paint_core,
 
 static void
 gimp_brush_core_post_paint (GimpPaintCore    *paint_core,
-                            GimpDrawable     *drawable,
+                            GList            *drawables,
                             GimpPaintOptions *paint_options,
                             GimpPaintState    paint_state,
                             guint32           time)
@@ -352,13 +352,16 @@ gimp_brush_core_post_paint (GimpPaintCore    *paint_core,
 
 static gboolean
 gimp_brush_core_start (GimpPaintCore     *paint_core,
-                       GimpDrawable      *drawable,
+                       GList             *drawables,
                        GimpPaintOptions  *paint_options,
                        const GimpCoords  *coords,
                        GError           **error)
 {
   GimpBrushCore *core    = GIMP_BRUSH_CORE (paint_core);
   GimpContext   *context = GIMP_CONTEXT (paint_options);
+  GimpImage     *image   = NULL;
+
+  g_return_val_if_fail (drawables != NULL, FALSE);
 
   gimp_brush_core_set_brush (core, gimp_context_get_brush (context));
 
@@ -378,10 +381,17 @@ gimp_brush_core_start (GimpPaintCore     *paint_core,
       return FALSE;
     }
 
+  for (GList *iter = drawables; iter; iter = iter->next)
+    if (image == NULL)
+      image = gimp_item_get_image (GIMP_ITEM (iter->data));
+    else
+      g_return_val_if_fail (image == gimp_item_get_image (GIMP_ITEM (iter->data)),
+                            FALSE);
+
   if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush)
     {
       gimp_brush_core_eval_transform_dynamics (core,
-                                               drawable,
+                                               image,
                                                paint_options,
                                                coords);
 
@@ -393,8 +403,7 @@ gimp_brush_core_start (GimpPaintCore     *paint_core,
   core->brush = core->main_brush;
 
   core->jitter =
-    gimp_paint_options_get_jitter (paint_options,
-                                   gimp_item_get_image (GIMP_ITEM (drawable)));
+    gimp_paint_options_get_jitter (paint_options, image);
 
   return TRUE;
 }
@@ -427,12 +436,12 @@ gimp_avoid_exact_integer (gdouble *x)
 
 static void
 gimp_brush_core_interpolate (GimpPaintCore    *paint_core,
-                             GimpDrawable     *drawable,
+                             GList            *drawables,
                              GimpPaintOptions *paint_options,
                              guint32           time)
 {
   GimpBrushCore      *core  = GIMP_BRUSH_CORE (paint_core);
-  GimpImage          *image = gimp_item_get_image (GIMP_ITEM (drawable));
+  GimpImage          *image = gimp_item_get_image (GIMP_ITEM (drawables->data));
   GimpDynamicsOutput *spacing_output;
   GimpCoords          last_coords;
   GimpCoords          current_coords;
@@ -496,7 +505,7 @@ gimp_brush_core_interpolate (GimpPaintCore    *paint_core,
     {
       gimp_paint_core_set_last_coords (paint_core, &current_coords);
 
-      gimp_paint_core_paint (paint_core, drawable, paint_options,
+      gimp_paint_core_paint (paint_core, drawables, paint_options,
                              GIMP_PAINT_STATE_MOTION, time);
 
       paint_core->pixel_dist = pixel_initial + pixel_dist; /* Don't forget to update pixel distance*/
@@ -757,7 +766,7 @@ gimp_brush_core_interpolate (GimpPaintCore    *paint_core,
       paint_core->distance   = initial       + t * dist;
       paint_core->pixel_dist = pixel_initial + t * pixel_dist;
 
-      gimp_paint_core_paint (paint_core, drawable, paint_options,
+      gimp_paint_core_paint (paint_core, drawables, paint_options,
                              GIMP_PAINT_STATE_MOTION, time);
     }
 
@@ -1140,7 +1149,7 @@ gimp_brush_core_get_brush_pixmap (GimpBrushCore *core)
 
 void
 gimp_brush_core_eval_transform_dynamics (GimpBrushCore     *core,
-                                         GimpDrawable      *drawable,
+                                         GimpImage         *image,
                                          GimpPaintOptions  *paint_options,
                                          const GimpCoords  *coords)
 {
@@ -1186,9 +1195,8 @@ gimp_brush_core_eval_transform_dynamics (GimpBrushCore     *core,
     {
       gdouble fade_point = 1.0;
 
-      if (drawable)
+      if (image)
         {
-          GimpImage     *image      = gimp_item_get_image (GIMP_ITEM (drawable));
           GimpPaintCore *paint_core = GIMP_PAINT_CORE (core);
 
           fade_point = gimp_paint_options_get_fade (paint_options, image,
diff --git a/app/paint/gimpbrushcore.h b/app/paint/gimpbrushcore.h
index 3ba4a41984..a6ab08bdd6 100644
--- a/app/paint/gimpbrushcore.h
+++ b/app/paint/gimpbrushcore.h
@@ -140,7 +140,7 @@ const GimpTempBuf * gimp_brush_core_get_brush_pixmap
 
 void   gimp_brush_core_eval_transform_dynamics
                                       (GimpBrushCore            *core,
-                                       GimpDrawable             *drawable,
+                                       GimpImage                *image,
                                        GimpPaintOptions         *paint_options,
                                        const GimpCoords         *coords);
 void   gimp_brush_core_eval_transform_symmetry
diff --git a/app/paint/gimpclone.c b/app/paint/gimpclone.c
index 9c807f43ff..fa6daaaeef 100644
--- a/app/paint/gimpclone.c
+++ b/app/paint/gimpclone.c
@@ -46,7 +46,7 @@
 
 
 static gboolean   gimp_clone_start      (GimpPaintCore     *paint_core,
-                                         GimpDrawable      *drawable,
+                                         GList             *drawables,
                                          GimpPaintOptions  *paint_options,
                                          const GimpCoords  *coords,
                                          GError           **error);
@@ -110,14 +110,14 @@ gimp_clone_init (GimpClone *clone)
 
 static gboolean
 gimp_clone_start (GimpPaintCore     *paint_core,
-                  GimpDrawable      *drawable,
+                  GList             *drawables,
                   GimpPaintOptions  *paint_options,
                   const GimpCoords  *coords,
                   GError           **error)
 {
   GimpCloneOptions *options = GIMP_CLONE_OPTIONS (paint_options);
 
-  if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawable,
+  if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawables,
                                                      paint_options, coords,
                                                      error))
     {
diff --git a/app/paint/gimpconvolve.c b/app/paint/gimpconvolve.c
index f2eea47cb6..347c8487e4 100644
--- a/app/paint/gimpconvolve.c
+++ b/app/paint/gimpconvolve.c
@@ -47,7 +47,7 @@
 
 
 static void    gimp_convolve_paint            (GimpPaintCore    *paint_core,
-                                               GimpDrawable     *drawable,
+                                               GList            *drawables,
                                                GimpPaintOptions *paint_options,
                                                GimpSymmetry     *sym,
                                                GimpPaintState    paint_state,
@@ -101,16 +101,19 @@ gimp_convolve_init (GimpConvolve *convolve)
 
 static void
 gimp_convolve_paint (GimpPaintCore    *paint_core,
-                     GimpDrawable     *drawable,
+                     GList            *drawables,
                      GimpPaintOptions *paint_options,
                      GimpSymmetry     *sym,
                      GimpPaintState    paint_state,
                      guint32           time)
 {
+  g_return_if_fail (g_list_length (drawables) == 1);
+
   switch (paint_state)
     {
     case GIMP_PAINT_STATE_MOTION:
-      gimp_convolve_motion (paint_core, drawable, paint_options, sym);
+      for (GList *iter = drawables; iter; iter = iter->next)
+        gimp_convolve_motion (paint_core, iter->data, paint_options, sym);
       break;
 
     default:
@@ -156,7 +159,7 @@ gimp_convolve_motion (GimpPaintCore    *paint_core,
     return;
 
   gimp_brush_core_eval_transform_dynamics (GIMP_BRUSH_CORE (paint_core),
-                                           drawable,
+                                           image,
                                            paint_options,
                                            coords);
   n_strokes = gimp_symmetry_get_size (sym);
diff --git a/app/paint/gimpdodgeburn.c b/app/paint/gimpdodgeburn.c
index cdfc176443..e803970018 100644
--- a/app/paint/gimpdodgeburn.c
+++ b/app/paint/gimpdodgeburn.c
@@ -40,7 +40,7 @@
 
 
 static void   gimp_dodge_burn_paint  (GimpPaintCore    *paint_core,
-                                      GimpDrawable     *drawable,
+                                      GList            *drawables,
                                       GimpPaintOptions *paint_options,
                                       GimpSymmetry     *sym,
                                       GimpPaintState    paint_state,
@@ -86,19 +86,22 @@ gimp_dodge_burn_init (GimpDodgeBurn *dodgeburn)
 
 static void
 gimp_dodge_burn_paint (GimpPaintCore    *paint_core,
-                       GimpDrawable     *drawable,
+                       GList            *drawables,
                        GimpPaintOptions *paint_options,
                        GimpSymmetry     *sym,
                        GimpPaintState    paint_state,
                        guint32           time)
 {
+  g_return_if_fail (g_list_length (drawables) == 1);
+
   switch (paint_state)
     {
     case GIMP_PAINT_STATE_INIT:
       break;
 
     case GIMP_PAINT_STATE_MOTION:
-      gimp_dodge_burn_motion (paint_core, drawable, paint_options, sym);
+      for (GList *iter = drawables; iter; iter = iter->next)
+        gimp_dodge_burn_motion (paint_core, iter->data, paint_options, sym);
       break;
 
     case GIMP_PAINT_STATE_FINISH:
@@ -142,12 +145,12 @@ gimp_dodge_burn_motion (GimpPaintCore    *paint_core,
     return;
 
   if (paint_options->application_mode == GIMP_PAINT_CONSTANT)
-    src_buffer = gimp_paint_core_get_orig_image (paint_core);
+    src_buffer = gimp_paint_core_get_orig_image (paint_core, drawable);
   else
     src_buffer = gimp_drawable_get_buffer (drawable);
 
   gimp_brush_core_eval_transform_dynamics (brush_core,
-                                           drawable,
+                                           image,
                                            paint_options,
                                            coords);
   n_strokes = gimp_symmetry_get_size (sym);
diff --git a/app/paint/gimpheal.c b/app/paint/gimpheal.c
index 814fd26a78..625444fa5b 100644
--- a/app/paint/gimpheal.c
+++ b/app/paint/gimpheal.c
@@ -68,7 +68,7 @@
  */
 
 static gboolean     gimp_heal_start              (GimpPaintCore    *paint_core,
-                                                  GimpDrawable     *drawable,
+                                                  GList            *drawables,
                                                   GimpPaintOptions *paint_options,
                                                   const GimpCoords *coords,
                                                   GError          **error);
@@ -138,21 +138,21 @@ gimp_heal_init (GimpHeal *heal)
 
 static gboolean
 gimp_heal_start (GimpPaintCore     *paint_core,
-                 GimpDrawable      *drawable,
+                 GList             *drawables,
                  GimpPaintOptions  *paint_options,
                  const GimpCoords  *coords,
                  GError           **error)
 {
   GimpSourceCore *source_core = GIMP_SOURCE_CORE (paint_core);
 
-  if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawable,
+  if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawables,
                                                      paint_options, coords,
                                                      error))
     {
       return FALSE;
     }
 
-  if (! source_core->set_source && gimp_drawable_is_indexed (drawable))
+  if (! source_core->set_source && gimp_drawable_is_indexed (drawables->data))
     {
       g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
                            _("Healing does not operate on indexed layers."));
diff --git a/app/paint/gimpink.c b/app/paint/gimpink.c
index 10e528c6ba..9814309693 100644
--- a/app/paint/gimpink.c
+++ b/app/paint/gimpink.c
@@ -54,7 +54,7 @@
 static void         gimp_ink_finalize         (GObject           *object);
 
 static void         gimp_ink_paint            (GimpPaintCore     *paint_core,
-                                               GimpDrawable      *drawable,
+                                               GList             *drawables,
                                                GimpPaintOptions  *paint_options,
                                                GimpSymmetry      *sym,
                                                GimpPaintState     paint_state,
@@ -149,7 +149,7 @@ gimp_ink_finalize (GObject *object)
 
 static void
 gimp_ink_paint (GimpPaintCore    *paint_core,
-                GimpDrawable     *drawable,
+                GList            *drawables,
                 GimpPaintOptions *paint_options,
                 GimpSymmetry     *sym,
                 GimpPaintState    paint_state,
@@ -159,6 +159,8 @@ gimp_ink_paint (GimpPaintCore    *paint_core,
   GimpCoords *cur_coords;
   GimpCoords  last_coords;
 
+  g_return_if_fail (g_list_length (drawables) == 1);
+
   gimp_paint_core_get_last_coords (paint_core, &last_coords);
   cur_coords = gimp_symmetry_get_origin (sym);
 
@@ -215,7 +217,8 @@ gimp_ink_paint (GimpPaintCore    *paint_core,
       break;
 
     case GIMP_PAINT_STATE_MOTION:
-      gimp_ink_motion (paint_core, drawable, paint_options, sym, time);
+      for (GList *iter = drawables; iter; iter = iter->next)
+        gimp_ink_motion (paint_core, iter->data, paint_options, sym, time);
       break;
 
     case GIMP_PAINT_STATE_FINISH:
diff --git a/app/paint/gimpmybrushcore.c b/app/paint/gimpmybrushcore.c
index b0771a61af..fe54a24f22 100644
--- a/app/paint/gimpmybrushcore.c
+++ b/app/paint/gimpmybrushcore.c
@@ -62,16 +62,16 @@ struct _GimpMybrushCorePrivate
 static void      gimp_mybrush_core_finalize       (GObject           *object);
 
 static gboolean  gimp_mybrush_core_start          (GimpPaintCore     *paint_core,
-                                                   GimpDrawable      *drawable,
+                                                   GList             *drawables,
                                                    GimpPaintOptions  *paint_options,
                                                    const GimpCoords  *coords,
                                                    GError           **error);
 static void      gimp_mybrush_core_interpolate    (GimpPaintCore     *paint_core,
-                                                   GimpDrawable      *drawable,
+                                                   GList             *drawables,
                                                    GimpPaintOptions  *paint_options,
                                                    guint32            time);
 static void      gimp_mybrush_core_paint          (GimpPaintCore     *paint_core,
-                                                   GimpDrawable      *drawable,
+                                                   GList             *drawables,
                                                    GimpPaintOptions  *paint_options,
                                                    GimpSymmetry      *sym,
                                                    GimpPaintState     paint_state,
@@ -141,7 +141,7 @@ gimp_mybrush_core_finalize (GObject *object)
 
 static gboolean
 gimp_mybrush_core_start (GimpPaintCore     *paint_core,
-                         GimpDrawable      *drawable,
+                         GList             *drawables,
                          GimpPaintOptions  *paint_options,
                          const GimpCoords  *coords,
                          GError           **error)
@@ -163,7 +163,7 @@ gimp_mybrush_core_start (GimpPaintCore     *paint_core,
 
 static void
 gimp_mybrush_core_interpolate (GimpPaintCore    *paint_core,
-                               GimpDrawable     *drawable,
+                               GList            *drawables,
                                GimpPaintOptions *paint_options,
                                guint32           time)
 {
@@ -180,13 +180,13 @@ gimp_mybrush_core_interpolate (GimpPaintCore    *paint_core,
 
       mybrush->private->synthetic = TRUE;
 
-      gimp_paint_core_paint (paint_core, drawable, paint_options,
+      gimp_paint_core_paint (paint_core, drawables, paint_options,
                              GIMP_PAINT_STATE_MOTION, time);
 
       paint_core->cur_coords = saved_coords;
     }
 
-  gimp_paint_core_paint (paint_core, drawable, paint_options,
+  gimp_paint_core_paint (paint_core, drawables, paint_options,
                          GIMP_PAINT_STATE_MOTION, time);
 
   paint_core->last_coords = paint_core->cur_coords;
@@ -194,7 +194,7 @@ gimp_mybrush_core_interpolate (GimpPaintCore    *paint_core,
 
 static void
 gimp_mybrush_core_paint (GimpPaintCore    *paint_core,
-                         GimpDrawable     *drawable,
+                         GList            *drawables,
                          GimpPaintOptions *paint_options,
                          GimpSymmetry     *sym,
                          GimpPaintState    paint_state,
@@ -204,6 +204,8 @@ gimp_mybrush_core_paint (GimpPaintCore    *paint_core,
   GimpContext     *context = GIMP_CONTEXT (paint_options);
   GimpRGB          fg;
 
+  g_return_if_fail (g_list_length (drawables) == 1);
+
   switch (paint_state)
     {
     case GIMP_PAINT_STATE_INIT:
@@ -212,21 +214,21 @@ gimp_mybrush_core_paint (GimpPaintCore    *paint_core,
       gimp_symmetry_set_stateful (sym, TRUE);
 
       mybrush->private->surface =
-        gimp_mypaint_surface_new (gimp_drawable_get_buffer (drawable),
-                                  gimp_drawable_get_active_mask (drawable),
+        gimp_mypaint_surface_new (gimp_drawable_get_buffer (drawables->data),
+                                  gimp_drawable_get_active_mask (drawables->data),
                                   paint_core->mask_buffer,
                                   paint_core->mask_x_offset,
                                   paint_core->mask_y_offset,
                                   GIMP_MYBRUSH_OPTIONS (paint_options));
 
-      gimp_mybrush_core_create_brushes (mybrush, drawable, paint_options, sym);
+      gimp_mybrush_core_create_brushes (mybrush, drawables->data, paint_options, sym);
 
       mybrush->private->last_time = -1;
       mybrush->private->synthetic = FALSE;
       break;
 
     case GIMP_PAINT_STATE_MOTION:
-      gimp_mybrush_core_motion (paint_core, drawable, paint_options,
+      gimp_mybrush_core_motion (paint_core, drawables->data, paint_options,
                                 sym, time);
       break;
 
diff --git a/app/paint/gimppaintbrush.c b/app/paint/gimppaintbrush.c
index 410b02504a..25940af5cf 100644
--- a/app/paint/gimppaintbrush.c
+++ b/app/paint/gimppaintbrush.c
@@ -47,7 +47,7 @@
 
 
 static void       gimp_paintbrush_paint                        (GimpPaintCore             *paint_core,
-                                                                GimpDrawable              *drawable,
+                                                                GList                     *drawables,
                                                                 GimpPaintOptions          *paint_options,
                                                                 GimpSymmetry              *sym,
                                                                 GimpPaintState             paint_state,
@@ -104,7 +104,7 @@ gimp_paintbrush_init (GimpPaintbrush *paintbrush)
 
 static void
 gimp_paintbrush_paint (GimpPaintCore    *paint_core,
-                       GimpDrawable     *drawable,
+                       GList            *drawables,
                        GimpPaintOptions *paint_options,
                        GimpSymmetry     *sym,
                        GimpPaintState    paint_state,
@@ -112,26 +112,32 @@ gimp_paintbrush_paint (GimpPaintCore    *paint_core,
 {
   GimpPaintbrush *paintbrush = GIMP_PAINTBRUSH (paint_core);
 
+  g_return_if_fail (g_list_length (drawables) == 1);
+
   switch (paint_state)
     {
     case GIMP_PAINT_STATE_INIT:
       {
         GimpRGB color;
 
-        if (GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color &&
-            GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color (
-              paintbrush, drawable, paint_options, &color))
-          {
-            GimpContext *context = GIMP_CONTEXT (paint_options);
+        for (GList *iter = drawables; iter; iter = iter->next)
+          if (GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color &&
+              GIMP_PAINTBRUSH_GET_CLASS (paintbrush)->get_color_history_color (paintbrush,
+                                                                               iter->data,
+                                                                               paint_options,
+                                                                               &color))
+            {
+              GimpContext *context = GIMP_CONTEXT (paint_options);
 
-            gimp_palettes_add_color_history (context->gimp, &color);
-          }
+              gimp_palettes_add_color_history (context->gimp, &color);
+            }
       }
       break;
 
     case GIMP_PAINT_STATE_MOTION:
-      _gimp_paintbrush_motion (paint_core, drawable, paint_options,
-                               sym, GIMP_OPACITY_OPAQUE);
+      for (GList *iter = drawables; iter; iter = iter->next)
+        _gimp_paintbrush_motion (paint_core, iter->data, paint_options,
+                                 sym, GIMP_OPACITY_OPAQUE);
       break;
 
     case GIMP_PAINT_STATE_FINISH:
@@ -258,7 +264,7 @@ _gimp_paintbrush_motion (GimpPaintCore    *paint_core,
   if (GIMP_BRUSH_CORE_GET_CLASS (brush_core)->handles_transforming_brush)
     {
       gimp_brush_core_eval_transform_dynamics (brush_core,
-                                               drawable,
+                                               image,
                                                paint_options,
                                                coords);
     }
diff --git a/app/paint/gimppaintcore-stroke.c b/app/paint/gimppaintcore-stroke.c
index 3beac93dba..ab73977404 100644
--- a/app/paint/gimppaintcore-stroke.c
+++ b/app/paint/gimppaintcore-stroke.c
@@ -55,6 +55,9 @@ gimp_paint_core_stroke (GimpPaintCore     *core,
                         gboolean           push_undo,
                         GError           **error)
 {
+  GList    *drawables;
+  gboolean  success = FALSE;
+
   g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
   g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
@@ -63,36 +66,40 @@ gimp_paint_core_stroke (GimpPaintCore     *core,
   g_return_val_if_fail (n_strokes > 0, FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  if (gimp_paint_core_start (core, drawable, paint_options, &strokes[0],
+  drawables = g_list_prepend (NULL, drawable);
+
+  if (gimp_paint_core_start (core, drawables, paint_options, &strokes[0],
                              error))
     {
       gint i;
 
       core->last_coords = strokes[0];
 
-      gimp_paint_core_paint (core, drawable, paint_options,
+      gimp_paint_core_paint (core, drawables, paint_options,
                              GIMP_PAINT_STATE_INIT, 0);
 
-      gimp_paint_core_paint (core, drawable, paint_options,
+      gimp_paint_core_paint (core, drawables, paint_options,
                              GIMP_PAINT_STATE_MOTION, 0);
 
       for (i = 1; i < n_strokes; i++)
         {
-          gimp_paint_core_interpolate (core, drawable, paint_options,
+          gimp_paint_core_interpolate (core, drawables, paint_options,
                                        &strokes[i], 0);
         }
 
-      gimp_paint_core_paint (core, drawable, paint_options,
+      gimp_paint_core_paint (core, drawables, paint_options,
                              GIMP_PAINT_STATE_FINISH, 0);
 
-      gimp_paint_core_finish (core, drawable, push_undo);
+      gimp_paint_core_finish (core, drawables, push_undo);
 
       gimp_paint_core_cleanup (core);
 
-      return TRUE;
+      success = TRUE;
     }
 
-  return FALSE;
+  g_list_free (drawables);
+
+  return success;
 }
 
 gboolean
@@ -107,6 +114,7 @@ gimp_paint_core_stroke_boundary (GimpPaintCore      *core,
                                  gboolean            push_undo,
                                  GError            **error)
 {
+  GList        *drawables;
   GimpBoundSeg *stroke_segs;
   gint          n_stroke_segs;
   gint          off_x;
@@ -148,6 +156,8 @@ gimp_paint_core_stroke_boundary (GimpPaintCore      *core,
 
   n_coords++;
 
+  drawables = g_list_prepend (NULL, drawable);
+
   for (s = 0; s < n_stroke_segs; s++)
     {
       while (stroke_segs[seg].x1 != -1 ||
@@ -172,7 +182,7 @@ gimp_paint_core_stroke_boundary (GimpPaintCore      *core,
         gimp_paint_core_stroke_emulate_dynamics (coords, n_coords);
 
       if (initialized ||
-          gimp_paint_core_start (core, drawable, paint_options, &coords[0],
+          gimp_paint_core_start (core, drawables, paint_options, &coords[0],
                                  error))
         {
           gint i;
@@ -182,19 +192,19 @@ gimp_paint_core_stroke_boundary (GimpPaintCore      *core,
           core->cur_coords  = coords[0];
           core->last_coords = coords[0];
 
-          gimp_paint_core_paint (core, drawable, paint_options,
+          gimp_paint_core_paint (core, drawables, paint_options,
                                  GIMP_PAINT_STATE_INIT, 0);
 
-          gimp_paint_core_paint (core, drawable, paint_options,
+          gimp_paint_core_paint (core, drawables, paint_options,
                                  GIMP_PAINT_STATE_MOTION, 0);
 
           for (i = 1; i < n_coords; i++)
             {
-              gimp_paint_core_interpolate (core, drawable, paint_options,
+              gimp_paint_core_interpolate (core, drawables, paint_options,
                                            &coords[i], 0);
             }
 
-          gimp_paint_core_paint (core, drawable, paint_options,
+          gimp_paint_core_paint (core, drawables, paint_options,
                                  GIMP_PAINT_STATE_FINISH, 0);
         }
       else
@@ -214,11 +224,12 @@ gimp_paint_core_stroke_boundary (GimpPaintCore      *core,
 
   if (initialized)
     {
-      gimp_paint_core_finish (core, drawable, push_undo);
+      gimp_paint_core_finish (core, drawables, push_undo);
 
       gimp_paint_core_cleanup (core);
     }
 
+  g_list_free (drawables);
   g_free (coords);
   g_free (stroke_segs);
 
@@ -234,6 +245,7 @@ gimp_paint_core_stroke_vectors (GimpPaintCore     *core,
                                 gboolean           push_undo,
                                 GError           **error)
 {
+  GList    *drawables;
   GList    *stroke;
   gboolean  initialized = FALSE;
   gboolean  due_to_lack_of_points = FALSE;
@@ -253,6 +265,8 @@ gimp_paint_core_stroke_vectors (GimpPaintCore     *core,
   off_x -= vectors_off_x;
   off_y -= vectors_off_y;
 
+  drawables = g_list_prepend (NULL, drawable);
+
   for (stroke = vectors->strokes->head;
        stroke;
        stroke = stroke->next)
@@ -278,7 +292,7 @@ gimp_paint_core_stroke_vectors (GimpPaintCore     *core,
                                                      coords->len);
 
           if (initialized ||
-              gimp_paint_core_start (core, drawable, paint_options,
+              gimp_paint_core_start (core, drawables, paint_options,
                                      &g_array_index (coords, GimpCoords, 0),
                                      error))
             {
@@ -287,20 +301,20 @@ gimp_paint_core_stroke_vectors (GimpPaintCore     *core,
               core->cur_coords  = g_array_index (coords, GimpCoords, 0);
               core->last_coords = g_array_index (coords, GimpCoords, 0);
 
-              gimp_paint_core_paint (core, drawable, paint_options,
+              gimp_paint_core_paint (core, drawables, paint_options,
                                      GIMP_PAINT_STATE_INIT, 0);
 
-              gimp_paint_core_paint (core, drawable, paint_options,
+              gimp_paint_core_paint (core, drawables, paint_options,
                                      GIMP_PAINT_STATE_MOTION, 0);
 
               for (i = 1; i < coords->len; i++)
                 {
-                  gimp_paint_core_interpolate (core, drawable, paint_options,
+                  gimp_paint_core_interpolate (core, drawables, paint_options,
                                                &g_array_index (coords, GimpCoords, i),
                                                0);
                 }
 
-              gimp_paint_core_paint (core, drawable, paint_options,
+              gimp_paint_core_paint (core, drawables, paint_options,
                                      GIMP_PAINT_STATE_FINISH, 0);
             }
           else
@@ -322,7 +336,7 @@ gimp_paint_core_stroke_vectors (GimpPaintCore     *core,
 
   if (initialized)
     {
-      gimp_paint_core_finish (core, drawable, push_undo);
+      gimp_paint_core_finish (core, drawables, push_undo);
 
       gimp_paint_core_cleanup (core);
     }
@@ -333,6 +347,8 @@ gimp_paint_core_stroke_vectors (GimpPaintCore     *core,
                            _("Not enough points to stroke"));
     }
 
+  g_list_free (drawables);
+
   return initialized;
 }
 
diff --git a/app/paint/gimppaintcore.c b/app/paint/gimppaintcore.c
index ebf7b03ef9..14b3470701 100644
--- a/app/paint/gimppaintcore.c
+++ b/app/paint/gimppaintcore.c
@@ -80,28 +80,28 @@ static void      gimp_paint_core_get_property        (GObject          *object,
                                                       GParamSpec       *pspec);
 
 static gboolean  gimp_paint_core_real_start          (GimpPaintCore    *core,
-                                                      GimpDrawable     *drawable,
+                                                      GList            *drawables,
                                                       GimpPaintOptions *paint_options,
                                                       const GimpCoords *coords,
                                                       GError          **error);
 static gboolean  gimp_paint_core_real_pre_paint      (GimpPaintCore    *core,
-                                                      GimpDrawable     *drawable,
+                                                      GList            *drawables,
                                                       GimpPaintOptions *options,
                                                       GimpPaintState    paint_state,
                                                       guint32           time);
 static void      gimp_paint_core_real_paint          (GimpPaintCore    *core,
-                                                      GimpDrawable     *drawable,
+                                                      GList            *drawables,
                                                       GimpPaintOptions *options,
                                                       GimpSymmetry     *sym,
                                                       GimpPaintState    paint_state,
                                                       guint32           time);
 static void      gimp_paint_core_real_post_paint     (GimpPaintCore    *core,
-                                                      GimpDrawable     *drawable,
+                                                      GList            *drawables,
                                                       GimpPaintOptions *options,
                                                       GimpPaintState    paint_state,
                                                       guint32           time);
 static void      gimp_paint_core_real_interpolate    (GimpPaintCore    *core,
-                                                      GimpDrawable     *drawable,
+                                                      GList            *drawables,
                                                       GimpPaintOptions *options,
                                                       guint32           time);
 static GeglBuffer *
@@ -154,6 +154,7 @@ static void
 gimp_paint_core_init (GimpPaintCore *core)
 {
   core->ID = global_core_ID++;
+  core->undo_buffers = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
 }
 
 static void
@@ -164,6 +165,7 @@ gimp_paint_core_finalize (GObject *object)
   gimp_paint_core_cleanup (core);
 
   g_clear_pointer (&core->undo_desc, g_free);
+  g_hash_table_unref (core->undo_buffers);
 
   if (core->stroke_buffer)
     {
@@ -217,7 +219,7 @@ gimp_paint_core_get_property (GObject    *object,
 
 static gboolean
 gimp_paint_core_real_start (GimpPaintCore    *core,
-                            GimpDrawable     *drawable,
+                            GList            *drawables,
                             GimpPaintOptions *paint_options,
                             const GimpCoords *coords,
                             GError          **error)
@@ -227,7 +229,7 @@ gimp_paint_core_real_start (GimpPaintCore    *core,
 
 static gboolean
 gimp_paint_core_real_pre_paint (GimpPaintCore    *core,
-                                GimpDrawable     *drawable,
+                                GList            *drawables,
                                 GimpPaintOptions *paint_options,
                                 GimpPaintState    paint_state,
                                 guint32           time)
@@ -237,7 +239,7 @@ gimp_paint_core_real_pre_paint (GimpPaintCore    *core,
 
 static void
 gimp_paint_core_real_paint (GimpPaintCore    *core,
-                            GimpDrawable     *drawable,
+                            GList            *drawables,
                             GimpPaintOptions *paint_options,
                             GimpSymmetry     *sym,
                             GimpPaintState    paint_state,
@@ -247,7 +249,7 @@ gimp_paint_core_real_paint (GimpPaintCore    *core,
 
 static void
 gimp_paint_core_real_post_paint (GimpPaintCore    *core,
-                                 GimpDrawable     *drawable,
+                                 GList            *drawables,
                                  GimpPaintOptions *paint_options,
                                  GimpPaintState    paint_state,
                                  guint32           time)
@@ -256,11 +258,11 @@ gimp_paint_core_real_post_paint (GimpPaintCore    *core,
 
 static void
 gimp_paint_core_real_interpolate (GimpPaintCore    *core,
-                                  GimpDrawable     *drawable,
+                                  GList            *drawables,
                                   GimpPaintOptions *paint_options,
                                   guint32           time)
 {
-  gimp_paint_core_paint (core, drawable, paint_options,
+  gimp_paint_core_paint (core, drawables, paint_options,
                          GIMP_PAINT_STATE_MOTION, time);
 
   core->last_coords = core->cur_coords;
@@ -297,7 +299,7 @@ gimp_paint_core_real_push_undo (GimpPaintCore *core,
 
 void
 gimp_paint_core_paint (GimpPaintCore    *core,
-                       GimpDrawable     *drawable,
+                       GList            *drawables,
                        GimpPaintOptions *paint_options,
                        GimpPaintState    paint_state,
                        guint32           time)
@@ -305,22 +307,19 @@ gimp_paint_core_paint (GimpPaintCore    *core,
   GimpPaintCoreClass *core_class;
 
   g_return_if_fail (GIMP_IS_PAINT_CORE (core));
-  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
-  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
+  g_return_if_fail (drawables != NULL);
   g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
 
   core_class = GIMP_PAINT_CORE_GET_CLASS (core);
 
-  if (core_class->pre_paint (core, drawable,
+  if (core_class->pre_paint (core, drawables,
                              paint_options,
                              paint_state, time))
     {
       GimpSymmetry *sym;
       GimpImage    *image;
-      GimpItem     *item;
 
-      item  = GIMP_ITEM (drawable);
-      image = gimp_item_get_image (item);
+      image = gimp_item_get_image (GIMP_ITEM (drawables->data));
 
       if (paint_state == GIMP_PAINT_STATE_MOTION)
         {
@@ -330,16 +329,16 @@ gimp_paint_core_paint (GimpPaintCore    *core,
         }
 
       sym = g_object_ref (gimp_image_get_active_symmetry (image));
-      gimp_symmetry_set_origin (sym, drawable, &core->cur_coords);
+      gimp_symmetry_set_origin (sym, drawables->data, &core->cur_coords);
 
-      core_class->paint (core, drawable,
+      core_class->paint (core, drawables,
                          paint_options,
                          sym, paint_state, time);
 
       gimp_symmetry_clear_origin (sym);
       g_object_unref (sym);
 
-      core_class->post_paint (core, drawable,
+      core_class->post_paint (core, drawables,
                               paint_options,
                               paint_state, time);
     }
@@ -347,24 +346,24 @@ gimp_paint_core_paint (GimpPaintCore    *core,
 
 gboolean
 gimp_paint_core_start (GimpPaintCore     *core,
-                       GimpDrawable      *drawable,
+                       GList             *drawables,
                        GimpPaintOptions  *paint_options,
                        const GimpCoords  *coords,
                        GError           **error)
 {
   GimpImage   *image;
-  GimpItem    *item;
   GimpChannel *mask;
 
   g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
-  g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
-  g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
+  g_return_val_if_fail (g_list_length (drawables) > 0, FALSE);
   g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), FALSE);
   g_return_val_if_fail (coords != NULL, FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  item  = GIMP_ITEM (drawable);
-  image = gimp_item_get_image (item);
+  for (GList *iter = drawables; iter; iter = iter->next)
+    g_return_val_if_fail (gimp_item_is_attached (iter->data), FALSE);
+
+  image = gimp_item_get_image (GIMP_ITEM (drawables->data));
 
   if (core->stroke_buffer)
     {
@@ -378,22 +377,15 @@ gimp_paint_core_start (GimpPaintCore     *core,
 
   /* remember the last stroke's endpoint for later undo */
   core->start_coords = core->last_coords;
+  core->cur_coords   = *coords;
 
-  core->cur_coords = *coords;
-
-  if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawable,
+  if (! GIMP_PAINT_CORE_GET_CLASS (core)->start (core, drawables,
                                                  paint_options,
                                                  coords, error))
     {
       return FALSE;
     }
 
-  /*  Allocate the undo structure  */
-  if (core->undo_buffer)
-    g_object_unref (core->undo_buffer);
-
-  core->undo_buffer = gimp_gegl_buffer_dup (gimp_drawable_get_buffer (drawable));
-
   /*  Set the image pickable  */
   if (! core->show_all)
     core->image_pickable = GIMP_PICKABLE (image);
@@ -410,80 +402,86 @@ gimp_paint_core_start (GimpPaintCore     *core,
       core->saved_proj_buffer = gimp_gegl_buffer_dup (buffer);
     }
 
-  /*  Allocate the canvas blocks structure  */
-  if (core->canvas_buffer)
-    g_object_unref (core->canvas_buffer);
+  for (GList *iter = drawables; iter; iter = iter->next)
+    {
+      /*  Allocate the undo structures  */
+      g_hash_table_insert (core->undo_buffers, iter->data,
+                           gimp_gegl_buffer_dup (gimp_drawable_get_buffer (iter->data)));
 
-  core->canvas_buffer =
-    gegl_buffer_new (GEGL_RECTANGLE (0, 0,
-                                     gimp_item_get_width  (item),
-                                     gimp_item_get_height (item)),
-                     babl_format ("Y float"));
+      /*  Allocate the canvas blocks structure  */
+      if (core->canvas_buffer)
+        g_object_unref (core->canvas_buffer);
 
-  /*  Get the initial undo extents  */
+      core->canvas_buffer =
+        gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+                                         gimp_item_get_width  (iter->data),
+                                         gimp_item_get_height (iter->data)),
+                         babl_format ("Y float"));
 
-  core->x1 = core->x2 = core->cur_coords.x;
-  core->y1 = core->y2 = core->cur_coords.y;
+      /*  Get the initial undo extents  */
 
-  core->last_paint.x = -1e6;
-  core->last_paint.y = -1e6;
+      core->x1 = core->x2 = core->cur_coords.x;
+      core->y1 = core->y2 = core->cur_coords.y;
 
-  mask = gimp_image_get_mask (image);
+      core->last_paint.x = -1e6;
+      core->last_paint.y = -1e6;
 
-  /*  don't apply the mask to itself and don't apply an empty mask  */
-  if (GIMP_DRAWABLE (mask) != drawable && ! gimp_channel_is_empty (mask))
-    {
-      GeglBuffer *mask_buffer;
-      gint        offset_x;
-      gint        offset_y;
+      mask = gimp_image_get_mask (image);
 
-      mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
-      gimp_item_get_offset (item, &offset_x, &offset_y);
+      /*  don't apply the mask to itself and don't apply an empty mask  */
+      if (GIMP_DRAWABLE (mask) != iter->data && ! gimp_channel_is_empty (mask))
+        {
+          GeglBuffer *mask_buffer;
+          gint        offset_x;
+          gint        offset_y;
 
-      core->mask_buffer   = g_object_ref (mask_buffer);
-      core->mask_x_offset = -offset_x;
-      core->mask_y_offset = -offset_y;
-    }
-  else
-    {
-      core->mask_buffer = NULL;
-    }
+          mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
+          gimp_item_get_offset (iter->data, &offset_x, &offset_y);
 
-  if (paint_options->use_applicator)
-    {
-      core->applicator = gimp_applicator_new (NULL);
+          core->mask_buffer   = g_object_ref (mask_buffer);
+          core->mask_x_offset = -offset_x;
+          core->mask_y_offset = -offset_y;
+        }
+      else
+        {
+          core->mask_buffer = NULL;
+        }
 
-      if (core->mask_buffer)
+      if (paint_options->use_applicator)
         {
-          gimp_applicator_set_mask_buffer (core->applicator,
-                                           core->mask_buffer);
-          gimp_applicator_set_mask_offset (core->applicator,
-                                           core->mask_x_offset,
-                                           core->mask_y_offset);
+          core->applicator = gimp_applicator_new (NULL);
+
+          if (core->mask_buffer)
+            {
+              gimp_applicator_set_mask_buffer (core->applicator,
+                                               core->mask_buffer);
+              gimp_applicator_set_mask_offset (core->applicator,
+                                               core->mask_x_offset,
+                                               core->mask_y_offset);
+            }
+
+          gimp_applicator_set_affect (core->applicator,
+                                      gimp_drawable_get_active_mask (iter->data));
+          gimp_applicator_set_dest_buffer (core->applicator,
+                                           gimp_drawable_get_buffer (iter->data));
         }
 
-      gimp_applicator_set_affect (core->applicator,
-                                  gimp_drawable_get_active_mask (drawable));
-      gimp_applicator_set_dest_buffer (core->applicator,
-                                       gimp_drawable_get_buffer (drawable));
+      /*  Freeze the drawable preview so that it isn't constantly updated.  */
+      gimp_viewable_preview_freeze (GIMP_VIEWABLE (iter->data));
     }
 
-  /*  Freeze the drawable preview so that it isn't constantly updated.  */
-  gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));
-
   return TRUE;
 }
 
 void
 gimp_paint_core_finish (GimpPaintCore *core,
-                        GimpDrawable  *drawable,
+                        GList         *drawables,
                         gboolean       push_undo)
 {
   GimpImage *image;
+  gboolean   undo_group_started = FALSE;
 
   g_return_if_fail (GIMP_IS_PAINT_CORE (core));
-  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
-  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
 
   g_clear_object (&core->applicator);
 
@@ -495,72 +493,87 @@ gimp_paint_core_finish (GimpPaintCore *core,
 
   g_clear_object (&core->mask_buffer);
 
-  image = gimp_item_get_image (GIMP_ITEM (drawable));
+  image = gimp_item_get_image (GIMP_ITEM (drawables->data));
 
-  /*  Determine if any part of the image has been altered--
-   *  if nothing has, then just return...
-   */
-  if ((core->x2 == core->x1) || (core->y2 == core->y1))
+  for (GList *iter = drawables; iter; iter = iter->next)
     {
-      gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
-      return;
-    }
+      /*  Determine if any part of the image has been altered--
+       *  if nothing has, then just go to the next drawable...
+       */
+      if ((core->x2 == core->x1) || (core->y2 == core->y1))
+        {
+          gimp_viewable_preview_thaw (GIMP_VIEWABLE (iter->data));
+          continue;
+        }
 
-  if (push_undo)
-    {
-      GeglBuffer    *buffer;
-      GeglRectangle  rect;
+      if (push_undo)
+        {
+          GeglBuffer    *undo_buffer;
+          GeglBuffer    *buffer;
+          GeglRectangle  rect;
 
-      gimp_rectangle_intersect (core->x1, core->y1,
-                                core->x2 - core->x1, core->y2 - core->y1,
-                                0, 0,
-                                gimp_item_get_width  (GIMP_ITEM (drawable)),
-                                gimp_item_get_height (GIMP_ITEM (drawable)),
-                                &rect.x, &rect.y, &rect.width, &rect.height);
+          if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
+                                             NULL, (gpointer*) &undo_buffer))
+            {
+              g_critical ("%s: missing undo buffer for '%s'.",
+                          G_STRFUNC, gimp_object_get_name (iter->data));
+              continue;
+            }
 
-      gegl_rectangle_align_to_buffer (&rect, &rect, core->undo_buffer,
-                                      GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
+          gimp_rectangle_intersect (core->x1, core->y1,
+                                    core->x2 - core->x1, core->y2 - core->y1,
+                                    0, 0,
+                                    gimp_item_get_width  (GIMP_ITEM (iter->data)),
+                                    gimp_item_get_height (GIMP_ITEM (iter->data)),
+                                    &rect.x, &rect.y, &rect.width, &rect.height);
 
-      gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
-                                   core->undo_desc);
+          gegl_rectangle_align_to_buffer (&rect, &rect, undo_buffer,
+                                          GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
+
+          if (! undo_group_started)
+            {
+              gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_PAINT,
+                                           core->undo_desc);
+              undo_group_started = TRUE;
+            }
 
-      GIMP_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
+          GIMP_PAINT_CORE_GET_CLASS (core)->push_undo (core, image, NULL);
 
-      buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
-                                gimp_drawable_get_format (drawable));
+          buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, rect.width, rect.height),
+                                    gimp_drawable_get_format (iter->data));
 
-      gimp_gegl_buffer_copy (core->undo_buffer,
-                             &rect,
-                             GEGL_ABYSS_NONE,
-                             buffer,
-                             GEGL_RECTANGLE (0, 0, 0, 0));
+          gimp_gegl_buffer_copy (undo_buffer,
+                                 &rect,
+                                 GEGL_ABYSS_NONE,
+                                 buffer,
+                                 GEGL_RECTANGLE (0, 0, 0, 0));
 
-      gimp_drawable_push_undo (drawable, NULL,
-                               buffer, rect.x, rect.y, rect.width, rect.height);
+          gimp_drawable_push_undo (iter->data, NULL,
+                                   buffer, rect.x, rect.y, rect.width, rect.height);
 
-      g_object_unref (buffer);
+          g_object_unref (buffer);
+          g_object_unref (undo_buffer);
+        }
 
-      gimp_image_undo_group_end (image);
+      gimp_viewable_preview_thaw (GIMP_VIEWABLE (iter->data));
     }
 
   core->image_pickable = NULL;
 
-  g_clear_object (&core->undo_buffer);
   g_clear_object (&core->saved_proj_buffer);
 
-  gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
+  if (undo_group_started)
+    gimp_image_undo_group_end (image);
 }
 
 void
 gimp_paint_core_cancel (GimpPaintCore *core,
-                        GimpDrawable  *drawable)
+                        GList         *drawables)
 {
   gint x, y;
   gint width, height;
 
   g_return_if_fail (GIMP_IS_PAINT_CORE (core));
-  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
-  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
 
   /*  Determine if any part of the image has been altered--
    *  if nothing has, then just return...
@@ -568,34 +581,46 @@ gimp_paint_core_cancel (GimpPaintCore *core,
   if ((core->x2 == core->x1) || (core->y2 == core->y1))
     return;
 
-  if (gimp_rectangle_intersect (core->x1, core->y1,
-                                core->x2 - core->x1,
-                                core->y2 - core->y1,
-                                0, 0,
-                                gimp_item_get_width  (GIMP_ITEM (drawable)),
-                                gimp_item_get_height (GIMP_ITEM (drawable)),
-                                &x, &y, &width, &height))
+  for (GList *iter = drawables; iter; iter = iter->next)
     {
-      GeglRectangle rect;
-
-      gegl_rectangle_align_to_buffer (&rect,
-                                      GEGL_RECTANGLE (x, y, width, height),
-                                      gimp_drawable_get_buffer (drawable),
-                                      GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
-
-      gimp_gegl_buffer_copy (core->undo_buffer,
-                             &rect,
-                             GEGL_ABYSS_NONE,
-                             gimp_drawable_get_buffer (drawable),
-                             &rect);
-    }
+      if (gimp_rectangle_intersect (core->x1, core->y1,
+                                    core->x2 - core->x1,
+                                    core->y2 - core->y1,
+                                    0, 0,
+                                    gimp_item_get_width  (GIMP_ITEM (iter->data)),
+                                    gimp_item_get_height (GIMP_ITEM (iter->data)),
+                                    &x, &y, &width, &height))
+        {
+          GeglBuffer    *undo_buffer;
+          GeglRectangle  rect;
 
-  g_clear_object (&core->undo_buffer);
-  g_clear_object (&core->saved_proj_buffer);
+          if (! g_hash_table_steal_extended (core->undo_buffers, iter->data,
+                                             NULL, (gpointer*) &undo_buffer))
+            {
+              g_critical ("%s: missing undo buffer for '%s'.",
+                          G_STRFUNC, gimp_object_get_name (iter->data));
+              continue;
+            }
+
+          gegl_rectangle_align_to_buffer (&rect,
+                                          GEGL_RECTANGLE (x, y, width, height),
+                                          gimp_drawable_get_buffer (iter->data),
+                                          GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
+
+          gimp_gegl_buffer_copy (undo_buffer,
+                                 &rect,
+                                 GEGL_ABYSS_NONE,
+                                 gimp_drawable_get_buffer (iter->data),
+                                 &rect);
+          g_object_unref (undo_buffer);
+        }
+
+      gimp_drawable_update (iter->data, x, y, width, height);
 
-  gimp_drawable_update (drawable, x, y, width, height);
+      gimp_viewable_preview_thaw (GIMP_VIEWABLE (iter->data));
+    }
 
-  gimp_viewable_preview_thaw (GIMP_VIEWABLE (drawable));
+  g_clear_object (&core->saved_proj_buffer);
 }
 
 void
@@ -603,7 +628,8 @@ gimp_paint_core_cleanup (GimpPaintCore *core)
 {
   g_return_if_fail (GIMP_IS_PAINT_CORE (core));
 
-  g_clear_object (&core->undo_buffer);
+  g_hash_table_remove_all (core->undo_buffers);
+
   g_clear_object (&core->saved_proj_buffer);
   g_clear_object (&core->canvas_buffer);
   g_clear_object (&core->paint_buffer);
@@ -611,20 +637,19 @@ gimp_paint_core_cleanup (GimpPaintCore *core)
 
 void
 gimp_paint_core_interpolate (GimpPaintCore    *core,
-                             GimpDrawable     *drawable,
+                             GList            *drawables,
                              GimpPaintOptions *paint_options,
                              const GimpCoords *coords,
                              guint32           time)
 {
   g_return_if_fail (GIMP_IS_PAINT_CORE (core));
-  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
-  g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
+  g_return_if_fail (drawables != NULL);
   g_return_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options));
   g_return_if_fail (coords != NULL);
 
   core->cur_coords = *coords;
 
-  GIMP_PAINT_CORE_GET_CLASS (core)->interpolate (core, drawable,
+  GIMP_PAINT_CORE_GET_CLASS (core)->interpolate (core, drawables,
                                                  paint_options, time);
 }
 
@@ -779,12 +804,17 @@ gimp_paint_core_get_image_pickable (GimpPaintCore *core)
 }
 
 GeglBuffer *
-gimp_paint_core_get_orig_image (GimpPaintCore *core)
+gimp_paint_core_get_orig_image (GimpPaintCore *core,
+                                GimpDrawable  *drawable)
 {
+  GeglBuffer *undo_buffer;
+
   g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), NULL);
-  g_return_val_if_fail (core->undo_buffer != NULL, NULL);
 
-  return core->undo_buffer;
+  undo_buffer = g_hash_table_lookup (core->undo_buffers, drawable);
+  g_return_val_if_fail (undo_buffer != NULL, NULL);
+
+  return undo_buffer;
 }
 
 GeglBuffer *
@@ -807,9 +837,12 @@ gimp_paint_core_paste (GimpPaintCore            *core,
                        GimpLayerMode             paint_mode,
                        GimpPaintApplicationMode  mode)
 {
-  gint              width  = gegl_buffer_get_width  (core->paint_buffer);
-  gint              height = gegl_buffer_get_height (core->paint_buffer);
-  GimpComponentMask affect = gimp_drawable_get_active_mask (drawable);
+  gint               width  = gegl_buffer_get_width  (core->paint_buffer);
+  gint               height = gegl_buffer_get_height (core->paint_buffer);
+  GimpComponentMask  affect = gimp_drawable_get_active_mask (drawable);
+  GeglBuffer        *undo_buffer;
+
+  undo_buffer = g_hash_table_lookup (core->undo_buffers, drawable);
 
   if (! affect)
     return;
@@ -851,8 +884,7 @@ gimp_paint_core_paste (GimpPaintCore            *core,
                                 GEGL_RECTANGLE (0, 0, width, height),
                                 1.0);
 
-          gimp_applicator_set_src_buffer (core->applicator,
-                                          core->undo_buffer);
+          gimp_applicator_set_src_buffer (core->applicator, undo_buffer);
         }
       /*  Otherwise:
        *   combine the paint mask to the paint buffer directly
@@ -931,7 +963,7 @@ gimp_paint_core_paste (GimpPaintCore            *core,
           algorithms |= GIMP_PAINT_CORE_LOOPS_ALGORITHM_CANVAS_BUFFER_TO_COMP_MASK;
 
           /* undo buf -> paint_buf -> dest_buffer */
-          params.src_buffer = core->undo_buffer;
+          params.src_buffer = undo_buffer;
         }
       else
         {
@@ -998,8 +1030,9 @@ gimp_paint_core_replace (GimpPaintCore            *core,
                          gdouble                   image_opacity,
                          GimpPaintApplicationMode  mode)
 {
-  gint              width, height;
-  GimpComponentMask affect;
+  GeglBuffer        *undo_buffer;
+  gint               width, height;
+  GimpComponentMask  affect;
 
   if (! gimp_drawable_has_alpha (drawable))
     {
@@ -1022,6 +1055,8 @@ gimp_paint_core_replace (GimpPaintCore            *core,
   if (! affect)
     return;
 
+  undo_buffer = g_hash_table_lookup (core->undo_buffers, drawable);
+
   if (core->applicator)
     {
       GeglRectangle  mask_rect;
@@ -1060,8 +1095,7 @@ gimp_paint_core_replace (GimpPaintCore            *core,
                                          core->paint_buffer_y,
                                          width, height);
 
-          gimp_applicator_set_src_buffer (core->applicator,
-                                          core->undo_buffer);
+          gimp_applicator_set_src_buffer (core->applicator, undo_buffer);
         }
       /*  Otherwise:
        *   use the paint mask as the mask buffer directly
diff --git a/app/paint/gimppaintcore.h b/app/paint/gimppaintcore.h
index 6e7f4d4c4b..189fec8f6e 100644
--- a/app/paint/gimppaintcore.h
+++ b/app/paint/gimppaintcore.h
@@ -59,7 +59,7 @@ struct _GimpPaintCore
 
   GimpPickable   *image_pickable;    /*  the image pickable                  */
 
-  GeglBuffer     *undo_buffer;       /*  pixels which have been modified     */
+  GHashTable     *undo_buffers;      /*  pixels which have been modified     */
   GeglBuffer     *saved_proj_buffer; /*  proj tiles which have been modified */
   GeglBuffer     *canvas_buffer;     /*  the buffer to paint the mask to     */
   GeglBuffer     *paint_buffer;      /*  the buffer to paint pixels to       */
@@ -81,30 +81,30 @@ struct _GimpPaintCoreClass
 
   /*  virtual functions  */
   gboolean     (* start)            (GimpPaintCore    *core,
-                                     GimpDrawable     *drawable,
+                                     GList            *drawables,
                                      GimpPaintOptions *paint_options,
                                      const GimpCoords *coords,
                                      GError          **error);
 
   gboolean     (* pre_paint)        (GimpPaintCore    *core,
-                                     GimpDrawable     *drawable,
+                                     GList            *drawables,
                                      GimpPaintOptions *paint_options,
                                      GimpPaintState    paint_state,
                                      guint32           time);
   void         (* paint)            (GimpPaintCore    *core,
-                                     GimpDrawable     *drawable,
+                                     GList            *drawables,
                                      GimpPaintOptions *paint_options,
                                      GimpSymmetry     *sym,
                                      GimpPaintState    paint_state,
                                      guint32           time);
   void         (* post_paint)       (GimpPaintCore    *core,
-                                     GimpDrawable     *drawable,
+                                     GList            *drawables,
                                      GimpPaintOptions *paint_options,
                                      GimpPaintState    paint_state,
                                      guint32           time);
 
   void         (* interpolate)      (GimpPaintCore    *core,
-                                     GimpDrawable     *drawable,
+                                     GList            *drawables,
                                      GimpPaintOptions *paint_options,
                                      guint32           time);
 
@@ -127,25 +127,25 @@ struct _GimpPaintCoreClass
 GType     gimp_paint_core_get_type                  (void) G_GNUC_CONST;
 
 void      gimp_paint_core_paint                     (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable,
+                                                     GList            *drawables,
                                                      GimpPaintOptions *paint_options,
                                                      GimpPaintState    state,
                                                      guint32           time);
 
 gboolean  gimp_paint_core_start                     (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable,
+                                                     GList            *drawables,
                                                      GimpPaintOptions *paint_options,
                                                      const GimpCoords *coords,
                                                      GError          **error);
 void      gimp_paint_core_finish                    (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable,
+                                                     GList            *drawables,
                                                      gboolean          push_undo);
 void      gimp_paint_core_cancel                    (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable);
+                                                     GList            *drawables);
 void      gimp_paint_core_cleanup                   (GimpPaintCore    *core);
 
 void      gimp_paint_core_interpolate               (GimpPaintCore    *core,
-                                                     GimpDrawable     *drawable,
+                                                     GList            *drawables,
                                                      GimpPaintOptions *paint_options,
                                                      const GimpCoords *coords,
                                                      guint32           time);
@@ -186,7 +186,8 @@ GeglBuffer * gimp_paint_core_get_paint_buffer       (GimpPaintCore    *core,
 
 GimpPickable * gimp_paint_core_get_image_pickable   (GimpPaintCore    *core);
 
-GeglBuffer * gimp_paint_core_get_orig_image         (GimpPaintCore    *core);
+GeglBuffer * gimp_paint_core_get_orig_image         (GimpPaintCore    *core,
+                                                     GimpDrawable     *drawable);
 GeglBuffer * gimp_paint_core_get_orig_proj          (GimpPaintCore    *core);
 
 void      gimp_paint_core_paste             (GimpPaintCore            *core,
diff --git a/app/paint/gimpperspectiveclone.c b/app/paint/gimpperspectiveclone.c
index abb9fabb5a..17fb600d88 100644
--- a/app/paint/gimpperspectiveclone.c
+++ b/app/paint/gimpperspectiveclone.c
@@ -47,7 +47,7 @@
 
 
 static void         gimp_perspective_clone_paint      (GimpPaintCore     *paint_core,
-                                                       GimpDrawable      *drawable,
+                                                       GList             *drawables,
                                                        GimpPaintOptions  *paint_options,
                                                        GimpSymmetry      *sym,
                                                        GimpPaintState     paint_state,
@@ -119,7 +119,7 @@ gimp_perspective_clone_init (GimpPerspectiveClone *clone)
 
 static void
 gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
-                              GimpDrawable     *drawable,
+                              GList            *drawables,
                               GimpPaintOptions *paint_options,
                               GimpSymmetry     *sym,
                               GimpPaintState    paint_state,
@@ -140,7 +140,7 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
     case GIMP_PAINT_STATE_INIT:
       if (source_core->set_source)
         {
-          g_object_set (source_core, "src-drawable", drawable, NULL);
+          g_object_set (source_core, "src-drawable", drawables->data, NULL);
 
           source_core->src_x = floor (coords->x);
           source_core->src_y = floor (coords->y);
@@ -194,12 +194,12 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                 if (options->sample_merged)
                   src_pickable = GIMP_PICKABLE (src_image);
 
-                dest_image = gimp_item_get_image (GIMP_ITEM (drawable));
+                dest_image = gimp_item_get_image (GIMP_ITEM (drawables->data));
 
                 if ((options->sample_merged &&
                      (src_image != dest_image)) ||
                     (! options->sample_merged &&
-                     (source_core->src_drawable != drawable)))
+                     (source_core->src_drawable != drawables->data)))
                   {
                     orig_buffer = gimp_pickable_get_buffer (src_pickable);
                   }
@@ -208,7 +208,7 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                     if (options->sample_merged)
                       orig_buffer = gimp_paint_core_get_orig_proj (paint_core);
                     else
-                      orig_buffer = gimp_paint_core_get_orig_image (paint_core);
+                      orig_buffer = gimp_paint_core_get_orig_image (paint_core, drawables->data);
                   }
               }
               break;
@@ -326,7 +326,8 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                 }
             }
 
-          gimp_source_core_motion (source_core, drawable, paint_options, sym);
+          for (GList *iter = drawables; iter; iter = iter->next)
+            gimp_source_core_motion (source_core, iter->data, paint_options, sym);
         }
       break;
 
diff --git a/app/paint/gimpsmudge.c b/app/paint/gimpsmudge.c
index e285f4d874..a0ba1f2f4a 100644
--- a/app/paint/gimpsmudge.c
+++ b/app/paint/gimpsmudge.c
@@ -46,7 +46,7 @@
 static void       gimp_smudge_finalize     (GObject          *object);
 
 static void       gimp_smudge_paint        (GimpPaintCore    *paint_core,
-                                            GimpDrawable     *drawable,
+                                            GList            *drawables,
                                             GimpPaintOptions *paint_options,
                                             GimpSymmetry     *sym,
                                             GimpPaintState    paint_state,
@@ -133,7 +133,7 @@ gimp_smudge_finalize (GObject *object)
 
 static void
 gimp_smudge_paint (GimpPaintCore    *paint_core,
-                   GimpDrawable     *drawable,
+                   GList            *drawables,
                    GimpPaintOptions *paint_options,
                    GimpSymmetry     *sym,
                    GimpPaintState    paint_state,
@@ -141,6 +141,8 @@ gimp_smudge_paint (GimpPaintCore    *paint_core,
 {
   GimpSmudge *smudge = GIMP_SMUDGE (paint_core);
 
+  g_return_if_fail (g_list_length (drawables) == 1);
+
   switch (paint_state)
     {
     case GIMP_PAINT_STATE_INIT:
@@ -169,11 +171,11 @@ gimp_smudge_paint (GimpPaintCore    *paint_core,
     case GIMP_PAINT_STATE_MOTION:
       /* initialization fails if the user starts outside the drawable */
       if (! smudge->initialized)
-        smudge->initialized = gimp_smudge_start (paint_core, drawable,
+        smudge->initialized = gimp_smudge_start (paint_core, drawables->data,
                                                  paint_options, sym);
 
       if (smudge->initialized)
-        gimp_smudge_motion (paint_core, drawable, paint_options, sym);
+        gimp_smudge_motion (paint_core, drawables->data, paint_options, sym);
       break;
 
     case GIMP_PAINT_STATE_FINISH:
@@ -223,7 +225,7 @@ gimp_smudge_start (GimpPaintCore    *paint_core,
 
   coords = gimp_symmetry_get_origin (sym);
   gimp_brush_core_eval_transform_dynamics (brush_core,
-                                           drawable,
+                                           gimp_item_get_image (GIMP_ITEM (drawable)),
                                            paint_options,
                                            coords);
 
@@ -395,7 +397,7 @@ gimp_smudge_motion (GimpPaintCore    *paint_core,
     return;
 
   gimp_brush_core_eval_transform_dynamics (brush_core,
-                                           drawable,
+                                           image,
                                            paint_options,
                                            coords);
 
diff --git a/app/paint/gimpsourcecore.c b/app/paint/gimpsourcecore.c
index 94238ad32f..1f891a55be 100644
--- a/app/paint/gimpsourcecore.c
+++ b/app/paint/gimpsourcecore.c
@@ -60,12 +60,12 @@ static void     gimp_source_core_get_property    (GObject           *object,
                                                   GParamSpec        *pspec);
 
 static gboolean gimp_source_core_start           (GimpPaintCore     *paint_core,
-                                                  GimpDrawable      *drawable,
+                                                  GList             *drawables,
                                                   GimpPaintOptions  *paint_options,
                                                   const GimpCoords  *coords,
                                                   GError           **error);
 static void     gimp_source_core_paint           (GimpPaintCore     *paint_core,
-                                                  GimpDrawable      *drawable,
+                                                  GList             *drawables,
                                                   GimpPaintOptions  *paint_options,
                                                   GimpSymmetry      *sym,
                                                   GimpPaintState     paint_state,
@@ -213,7 +213,7 @@ gimp_source_core_get_property (GObject    *object,
 
 static gboolean
 gimp_source_core_start (GimpPaintCore     *paint_core,
-                        GimpDrawable      *drawable,
+                        GList             *drawables,
                         GimpPaintOptions  *paint_options,
                         const GimpCoords  *coords,
                         GError           **error)
@@ -221,7 +221,7 @@ gimp_source_core_start (GimpPaintCore     *paint_core,
   GimpSourceCore    *source_core = GIMP_SOURCE_CORE (paint_core);
   GimpSourceOptions *options     = GIMP_SOURCE_OPTIONS (paint_options);
 
-  if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawable,
+  if (! GIMP_PAINT_CORE_CLASS (parent_class)->start (paint_core, drawables,
                                                      paint_options, coords,
                                                      error))
     {
@@ -242,7 +242,7 @@ gimp_source_core_start (GimpPaintCore     *paint_core,
 
       if (options->sample_merged &&
           gimp_item_get_image (GIMP_ITEM (source_core->src_drawable)) ==
-          gimp_item_get_image (GIMP_ITEM (drawable)))
+          gimp_item_get_image (GIMP_ITEM (drawables->data)))
         {
           paint_core->use_saved_proj = TRUE;
         }
@@ -253,7 +253,7 @@ gimp_source_core_start (GimpPaintCore     *paint_core,
 
 static void
 gimp_source_core_paint (GimpPaintCore    *paint_core,
-                        GimpDrawable     *drawable,
+                        GList            *drawables,
                         GimpPaintOptions *paint_options,
                         GimpSymmetry     *sym,
                         GimpPaintState    paint_state,
@@ -271,7 +271,7 @@ gimp_source_core_paint (GimpPaintCore    *paint_core,
     case GIMP_PAINT_STATE_INIT:
       if (source_core->set_source)
         {
-          gimp_source_core_set_src_drawable (source_core, drawable);
+          gimp_source_core_set_src_drawable (source_core, drawables->data);
 
           /* FIXME(?): subpixel source sampling */
           source_core->src_x = floor (coords->x);
@@ -329,8 +329,9 @@ gimp_source_core_paint (GimpPaintCore    *paint_core,
           source_core->src_x = dest_x + source_core->offset_x;
           source_core->src_y = dest_y + source_core->offset_y;
 
-          gimp_source_core_motion (source_core, drawable, paint_options,
-                                   sym);
+          for (GList *iter = drawables; iter; iter = iter->next)
+            gimp_source_core_motion (source_core, iter->data,
+                                     paint_options, sym);
         }
       break;
 
@@ -430,7 +431,7 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
     }
 
   gimp_brush_core_eval_transform_dynamics (brush_core,
-                                           drawable,
+                                           image,
                                            paint_options,
                                            origin);
 
@@ -629,7 +630,8 @@ gimp_source_core_real_get_source (GimpSourceCore   *source_core,
       if (options->sample_merged)
         dest_buffer = gimp_paint_core_get_orig_proj (GIMP_PAINT_CORE (source_core));
       else
-        dest_buffer = gimp_paint_core_get_orig_image (GIMP_PAINT_CORE (source_core));
+        dest_buffer = gimp_paint_core_get_orig_image (GIMP_PAINT_CORE (source_core),
+                                                      drawable);
     }
 
   *paint_area_offset_x = x - (paint_buffer_x + src_offset_x);
diff --git a/app/tools/gimpbrushtool.c b/app/tools/gimpbrushtool.c
index 8fb3e49b07..f2a14fd0d0 100644
--- a/app/tools/gimpbrushtool.c
+++ b/app/tools/gimpbrushtool.c
@@ -156,23 +156,15 @@ gimp_brush_tool_oper_update (GimpTool         *tool,
                              GimpDisplay      *display)
 {
   GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
-  GimpDrawable     *drawable      = NULL;
-  GList            *drawables;
+  GimpImage        *image         = gimp_display_get_image (display);
 
   gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
 
   GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
                                                proximity, display);
 
-  drawables = gimp_image_get_selected_drawables (gimp_display_get_image (display));
-
-  if (drawables)
-    drawable = drawables->data;
-
-  g_list_free (drawables);
-
   if (! gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)) &&
-      drawable && proximity)
+      image && proximity)
     {
       GimpContext   *context    = GIMP_CONTEXT (paint_options);
       GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
@@ -187,7 +179,7 @@ gimp_brush_tool_oper_update (GimpTool         *tool,
       if (GIMP_BRUSH_CORE_GET_CLASS (brush_core)->handles_transforming_brush)
         {
           gimp_brush_core_eval_transform_dynamics (brush_core,
-                                                   drawable,
+                                                   image,
                                                    paint_options,
                                                    coords);
         }
diff --git a/app/tools/gimppainttool-paint.c b/app/tools/gimppainttool-paint.c
index 7c0baebe1d..ca47ac134d 100644
--- a/app/tools/gimppainttool-paint.c
+++ b/app/tools/gimppainttool-paint.c
@@ -58,8 +58,9 @@ typedef struct
 
 typedef struct
 {
-  GimpCoords coords;
-  guint32    time;
+  GList        *drawables;
+  GimpCoords    coords;
+  guint32       time;
 } InterpolateData;
 
 
@@ -159,9 +160,8 @@ gimp_paint_tool_paint_thread (gpointer data)
 static gboolean
 gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
 {
-  GimpPaintCore *core     = paint_tool->core;
-  GimpDrawable  *drawable = paint_tool->drawable;
-  gboolean       update;
+  GimpPaintCore *core   = paint_tool->core;
+  gboolean       update = FALSE;
 
   paint_timeout_pending = TRUE;
 
@@ -170,7 +170,12 @@ gimp_paint_tool_paint_timeout (GimpPaintTool *paint_tool)
   paint_tool->paint_x = core->last_paint.x;
   paint_tool->paint_y = core->last_paint.y;
 
-  update = gimp_drawable_flush_paint (drawable);
+  for (GList *iter = paint_tool->drawables; iter; iter = iter->next)
+    {
+      update |= gimp_drawable_flush_paint (iter->data);
+      if (update)
+        break;
+    }
 
   if (update && GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->paint_flush)
     GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->paint_flush (paint_tool);
@@ -205,11 +210,11 @@ gimp_paint_tool_paint_interpolate (GimpPaintTool   *paint_tool,
 {
   GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
   GimpPaintCore    *core          = paint_tool->core;
-  GimpDrawable     *drawable      = paint_tool->drawable;
 
-  gimp_paint_core_interpolate (core, drawable, paint_options,
+  gimp_paint_core_interpolate (core, data->drawables, paint_options,
                                &data->coords, data->time);
 
+  g_list_free (data->drawables);
   g_slice_free (InterpolateData, data);
 }
 
@@ -230,10 +235,9 @@ gimp_paint_tool_paint_start (GimpPaintTool     *paint_tool,
   GimpPaintCore    *core;
   GimpDisplayShell *shell;
   GimpImage        *image;
-  GimpDrawable     *drawable;
   GList            *drawables;
+  GList            *iter;
   GimpCoords        curr_coords;
-  gint              off_x, off_y;
 
   g_return_val_if_fail (GIMP_IS_PAINT_TOOL (paint_tool), FALSE);
   g_return_val_if_fail (GIMP_IS_DISPLAY (display), FALSE);
@@ -249,17 +253,12 @@ gimp_paint_tool_paint_start (GimpPaintTool     *paint_tool,
   image         = gimp_display_get_image (display);
   drawables     = gimp_image_get_selected_drawables (image);
 
-  g_return_val_if_fail (g_list_length (drawables) == 1, FALSE);
+  g_return_val_if_fail (g_list_length (drawables) == 1 ||
+                        (g_list_length (drawables) > 1 && paint_tool->can_multi_paint),
+                        FALSE);
 
   curr_coords = *coords;
 
-  drawable = drawables->data;
-  g_list_free (drawables);
-  gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
-
-  curr_coords.x -= off_x;
-  curr_coords.y -= off_y;
-
   paint_tool->paint_x = curr_coords.x;
   paint_tool->paint_y = curr_coords.y;
 
@@ -267,7 +266,8 @@ gimp_paint_tool_paint_start (GimpPaintTool     *paint_tool,
    *  paint core
    */
   if (gimp_paint_tool_paint_use_thread (paint_tool))
-    gimp_drawable_start_paint (drawable);
+    for (iter = drawables; iter; iter = iter->next)
+      gimp_drawable_start_paint (iter->data);
 
   /*  Prepare to start the paint core  */
   if (GIMP_PAINT_TOOL_GET_CLASS (paint_tool)->paint_prepare)
@@ -275,16 +275,19 @@ gimp_paint_tool_paint_start (GimpPaintTool     *paint_tool,
 
   /*  Start the paint core  */
   if (! gimp_paint_core_start (core,
-                               drawable, paint_options, &curr_coords,
+                               drawables, paint_options, &curr_coords,
                                error))
     {
-      gimp_drawable_end_paint (drawable);
+      for (iter = drawables; iter; iter = iter->next)
+        gimp_drawable_end_paint (iter->data);
+      g_list_free (drawables);
 
       return FALSE;
     }
 
   paint_tool->display  = display;
-  paint_tool->drawable = drawable;
+  g_list_free (paint_tool->drawables);
+  paint_tool->drawables = drawables;
 
   if ((display != tool->display) || ! paint_tool->draw_line)
     {
@@ -323,18 +326,18 @@ gimp_paint_tool_paint_start (GimpPaintTool     *paint_tool,
     }
 
   /*  Let the specific painting function initialize itself  */
-  gimp_paint_core_paint (core, drawable, paint_options,
+  gimp_paint_core_paint (core, drawables, paint_options,
                          GIMP_PAINT_STATE_INIT, time);
 
   /*  Paint to the image  */
   if (paint_tool->draw_line)
     {
-      gimp_paint_core_interpolate (core, drawable, paint_options,
+      gimp_paint_core_interpolate (core, drawables, paint_options,
                                    &core->cur_coords, time);
     }
   else
     {
-      gimp_paint_core_paint (core, drawable, paint_options,
+      gimp_paint_core_paint (core, drawables, paint_options,
                              GIMP_PAINT_STATE_MOTION, time);
     }
 
@@ -361,14 +364,14 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
 {
   GimpPaintOptions *paint_options;
   GimpPaintCore    *core;
-  GimpDrawable     *drawable;
+  GList            *drawables;
 
   g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
   g_return_if_fail (paint_tool->display != NULL);
 
   paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
   core          = paint_tool->core;
-  drawable      = paint_tool->drawable;
+  drawables     = paint_tool->drawables;
 
   /*  Process remaining paint items  */
   if (gimp_paint_tool_paint_use_thread (paint_tool))
@@ -414,13 +417,13 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
     }
 
   /*  Let the specific painting function finish up  */
-  gimp_paint_core_paint (core, drawable, paint_options,
+  gimp_paint_core_paint (core, drawables, paint_options,
                          GIMP_PAINT_STATE_FINISH, time);
 
   if (cancel)
-    gimp_paint_core_cancel (core, drawable);
+    gimp_paint_core_cancel (core, drawables);
   else
-    gimp_paint_core_finish (core, drawable, TRUE);
+    gimp_paint_core_finish (core, drawables, TRUE);
 
   /*  Notify subclasses  */
   if (gimp_paint_tool_paint_use_thread (paint_tool) &&
@@ -431,10 +434,11 @@ gimp_paint_tool_paint_end (GimpPaintTool *paint_tool,
 
   /*  Exit paint mode  */
   if (gimp_paint_tool_paint_use_thread (paint_tool))
-    gimp_drawable_end_paint (drawable);
+    for (GList *iter = drawables; iter; iter = iter->next)
+      gimp_drawable_end_paint (iter->data);
 
-  paint_tool->display  = NULL;
-  paint_tool->drawable = NULL;
+  paint_tool->display = NULL;
+  g_clear_pointer (&paint_tool->drawables, g_list_free);
 }
 
 gboolean
@@ -442,8 +446,13 @@ gimp_paint_tool_paint_is_active (GimpPaintTool *paint_tool)
 {
   g_return_val_if_fail (GIMP_IS_PAINT_TOOL (paint_tool), FALSE);
 
-  return paint_tool->drawable != NULL &&
-         gimp_drawable_is_painting (paint_tool->drawable);
+  for (GList *iter = paint_tool->drawables; iter; iter = iter->next)
+    {
+      if (gimp_drawable_is_painting (iter->data))
+        return TRUE;
+    }
+
+  return FALSE;
 }
 
 void
@@ -501,9 +510,8 @@ gimp_paint_tool_paint_motion (GimpPaintTool    *paint_tool,
 {
   GimpPaintOptions *paint_options;
   GimpPaintCore    *core;
-  GimpDrawable     *drawable;
+  GList            *drawables;
   InterpolateData  *data;
-  gint              off_x, off_y;
 
   g_return_if_fail (GIMP_IS_PAINT_TOOL (paint_tool));
   g_return_if_fail (coords != NULL);
@@ -511,17 +519,13 @@ gimp_paint_tool_paint_motion (GimpPaintTool    *paint_tool,
 
   paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (paint_tool);
   core          = paint_tool->core;
-  drawable      = paint_tool->drawable;
+  drawables     = paint_tool->drawables;
 
   data = g_slice_new (InterpolateData);
 
-  data->coords = *coords;
-  data->time   = time;
-
-  gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
-
-  data->coords.x -= off_x;
-  data->coords.y -= off_y;
+  data->drawables = g_list_copy (drawables);
+  data->coords    = *coords;
+  data->time      = time;
 
   paint_tool->cursor_x = data->coords.x;
   paint_tool->cursor_y = data->coords.y;
@@ -532,14 +536,14 @@ gimp_paint_tool_paint_motion (GimpPaintTool    *paint_tool,
   if (paint_tool->draw_line)
     {
       gimp_paint_core_set_current_coords (core, &data->coords);
+      g_list_free (data->drawables);
 
       g_slice_free (InterpolateData, data);
 
       return;
     }
 
-  gimp_paint_tool_paint_push (
-    paint_tool,
-    (GimpPaintToolPaintFunc) gimp_paint_tool_paint_interpolate,
-    data);
+  gimp_paint_tool_paint_push (paint_tool,
+                              (GimpPaintToolPaintFunc) gimp_paint_tool_paint_interpolate,
+                              data);
 }
diff --git a/app/tools/gimppainttool.c b/app/tools/gimppainttool.c
index 0aa2edc968..cfa01541f3 100644
--- a/app/tools/gimppainttool.c
+++ b/app/tools/gimppainttool.c
@@ -160,9 +160,10 @@ gimp_paint_tool_init (GimpPaintTool *paint_tool)
   gimp_tool_control_set_action_opacity (tool->control,
                                         "context/context-opacity-set");
 
-  paint_tool->active        = TRUE;
-  paint_tool->pick_colors   = FALSE;
-  paint_tool->draw_line     = FALSE;
+  paint_tool->active          = TRUE;
+  paint_tool->pick_colors     = FALSE;
+  paint_tool->can_multi_paint = FALSE;
+  paint_tool->draw_line       = FALSE;
 
   paint_tool->show_cursor   = TRUE;
   paint_tool->draw_brush    = TRUE;
@@ -277,7 +278,7 @@ gimp_paint_tool_button_press (GimpTool            *tool,
   GimpDisplayShell *shell      = gimp_display_get_shell (display);
   GimpImage        *image      = gimp_display_get_image (display);
   GList            *drawables;
-  GimpDrawable     *drawable;
+  GList            *iter;
   gboolean          constrain;
   GError           *error = NULL;
 
@@ -289,68 +290,76 @@ gimp_paint_tool_button_press (GimpTool            *tool,
     }
 
   drawables  = gimp_image_get_selected_drawables (image);
-  if (g_list_length (drawables) != 1)
+  if (drawables == NULL)
     {
-      if (g_list_length (drawables) > 1)
-        gimp_tool_message_literal (tool, display,
-                                   _("Cannot paint on multiple layers. Select only one layer."));
-      else
-        gimp_tool_message_literal (tool, display,
-                                   _("No selected drawables."));
+      gimp_tool_message_literal (tool, display,
+                                 _("No selected drawables."));
 
-      g_list_free (drawables);
       return;
     }
-
-  drawable = drawables->data;
-
-  if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
+  else if (! paint_tool->can_multi_paint)
     {
-      gimp_tool_message_literal (tool, display,
-                                 _("Cannot paint on layer groups."));
-      g_list_free (drawables);
+      if (g_list_length (drawables) != 1)
+        {
+          gimp_tool_message_literal (tool, display,
+                                     _("Cannot paint on multiple layers. Select only one layer."));
 
-      return;
+          g_list_free (drawables);
+          return;
+        }
     }
 
-  if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
+  for (iter = drawables; iter; iter = iter->next)
     {
-      gimp_tool_message_literal (tool, display,
-                                 _("The active layer's pixels are locked."));
-      gimp_tools_blink_lock_box (display->gimp, GIMP_ITEM (drawable));
-      g_list_free (drawables);
+      GimpDrawable *drawable = iter->data;
 
-      return;
-    }
+      if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
+        {
+          gimp_tool_message_literal (tool, display,
+                                     _("Cannot paint on layer groups."));
+          g_list_free (drawables);
 
-  if (! gimp_paint_tool_check_alpha (paint_tool, drawable, display, &error))
-    {
-      GtkWidget *options_gui;
-      GtkWidget *mode_box;
+          return;
+        }
 
-      gimp_tool_message_literal (tool, display, error->message);
+      if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
+        {
+          gimp_tool_message_literal (tool, display,
+                                     _("A selected layer's pixels are locked."));
+          gimp_tools_blink_lock_box (display->gimp, GIMP_ITEM (drawable));
+          g_list_free (drawables);
 
-      options_gui = gimp_tools_get_tool_options_gui (
-                      GIMP_TOOL_OPTIONS (options));
-      mode_box    = gimp_paint_options_gui_get_paint_mode_box (options_gui);
+          return;
+        }
 
-      if (gtk_widget_is_sensitive (mode_box))
-        gimp_widget_blink (mode_box);
+      if (! gimp_paint_tool_check_alpha (paint_tool, drawable, display, &error))
+        {
+          GtkWidget *options_gui;
+          GtkWidget *mode_box;
 
-      g_clear_error (&error);
-      g_list_free (drawables);
+          gimp_tool_message_literal (tool, display, error->message);
 
-      return;
-    }
+          options_gui = gimp_tools_get_tool_options_gui (GIMP_TOOL_OPTIONS (options));
+          mode_box    = gimp_paint_options_gui_get_paint_mode_box (options_gui);
 
-  if (! gimp_item_is_visible (GIMP_ITEM (drawable)) &&
-      ! config->edit_non_visible)
-    {
-      gimp_tool_message_literal (tool, display,
-                                 _("The active layer is not visible."));
-      g_list_free (drawables);
+          if (gtk_widget_is_sensitive (mode_box))
+            gimp_widget_blink (mode_box);
 
-      return;
+          g_clear_error (&error);
+          g_list_free (drawables);
+
+          return;
+        }
+
+      if (! gimp_item_is_visible (GIMP_ITEM (drawable)) &&
+          ! config->edit_non_visible)
+        {
+          gimp_tool_message_literal (tool, display,
+                                     _("A selected layer is not visible."));
+          g_list_free (drawables);
+
+          return;
+        }
     }
 
   if (gimp_draw_tool_is_active (draw_tool))
@@ -533,27 +542,29 @@ gimp_paint_tool_cursor_update (GimpTool         *tool,
     {
       GimpImage    *image     = gimp_display_get_image (display);
       GList        *drawables = gimp_image_get_selected_drawables (image);
-      GimpDrawable *drawable  = NULL;
+      GList        *iter;
 
       if (! drawables)
         return;
 
-      if (g_list_length (drawables) == 1)
-        drawable = drawables->data;
-
-      g_list_free (drawables);
-
-      if (! drawable                                                          ||
-          gimp_viewable_get_children (GIMP_VIEWABLE (drawable))               ||
-          gimp_item_is_content_locked (GIMP_ITEM (drawable))                  ||
-          ! gimp_paint_tool_check_alpha (paint_tool, drawable, display, NULL) ||
-          ! (gimp_item_is_visible (GIMP_ITEM (drawable)) ||
-             config->edit_non_visible))
+      for (iter = drawables; iter; iter = iter->next)
         {
-          modifier        = GIMP_CURSOR_MODIFIER_BAD;
-          toggle_modifier = GIMP_CURSOR_MODIFIER_BAD;
+          GimpDrawable *drawable = iter->data;
+
+          if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable))               ||
+              gimp_item_is_content_locked (GIMP_ITEM (drawable))                  ||
+              ! gimp_paint_tool_check_alpha (paint_tool, drawable, display, NULL) ||
+              ! (gimp_item_is_visible (GIMP_ITEM (drawable)) ||
+                 config->edit_non_visible))
+            {
+              modifier        = GIMP_CURSOR_MODIFIER_BAD;
+              toggle_modifier = GIMP_CURSOR_MODIFIER_BAD;
+              break;
+            }
         }
 
+      g_list_free (drawables);
+
       if (! paint_tool->show_cursor &&
           modifier != GIMP_CURSOR_MODIFIER_BAD)
         {
@@ -626,19 +637,16 @@ gimp_paint_tool_oper_update (GimpTool         *tool,
     }
 
   drawables = gimp_image_get_selected_drawables (image);
-  if (g_list_length (drawables) == 1 && proximity)
+
+  if ((g_list_length (drawables) == 1 ||
+       (g_list_length (drawables) > 1 && paint_tool->can_multi_paint)) &&
+      proximity)
     {
       gchar    *status;
       gboolean  constrain_mask = gimp_get_constrain_behavior_mask ();
-      gint      off_x, off_y;
 
       core->cur_coords = *coords;
 
-      gimp_item_get_offset (GIMP_ITEM (drawables->data), &off_x, &off_y);
-
-      core->cur_coords.x -= off_x;
-      core->cur_coords.y -= off_y;
-
       if (display == tool->display && (state & GIMP_PAINT_TOOL_LINE_MASK))
         {
           /*  If shift is down and this is not the first paint stroke,
@@ -725,31 +733,20 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
       ! gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (draw_tool)))
     {
       GimpPaintCore  *core       = paint_tool->core;
-      GimpImage      *image      = gimp_display_get_image (draw_tool->display);
       GimpCanvasItem *outline    = NULL;
       gboolean        line_drawn = FALSE;
       gdouble         cur_x, cur_y;
-      gint            off_x, off_y;
-      GList          *drawables  = gimp_image_get_selected_drawables (image);
-      GimpDrawable   *drawable;
-
-      g_return_if_fail (g_list_length (drawables) == 1);
-
-      drawable = drawables->data;
-      g_list_free (drawables);
-
-      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
 
       if (gimp_paint_tool_paint_is_active (paint_tool) &&
           paint_tool->snap_brush)
         {
-          cur_x = paint_tool->paint_x + off_x;
-          cur_y = paint_tool->paint_y + off_y;
+          cur_x = paint_tool->paint_x;
+          cur_y = paint_tool->paint_y;
         }
       else
         {
-          cur_x = paint_tool->cursor_x + off_x;
-          cur_y = paint_tool->cursor_y + off_y;
+          cur_x = paint_tool->cursor_x;
+          cur_y = paint_tool->cursor_y;
 
           if (paint_tool->draw_line &&
               ! gimp_tool_control_is_active (GIMP_TOOL (draw_tool)->control))
@@ -757,8 +754,8 @@ gimp_paint_tool_draw (GimpDrawTool *draw_tool)
               GimpCanvasGroup *group;
               gdouble          last_x, last_y;
 
-              last_x = core->last_coords.x + off_x;
-              last_y = core->last_coords.y + off_y;
+              last_x = core->last_coords.x;
+              last_y = core->last_coords.y;
 
               group = gimp_draw_tool_add_stroke_group (draw_tool);
               gimp_draw_tool_push_group (draw_tool, group);
@@ -1009,6 +1006,21 @@ gimp_paint_tool_enable_color_picker (GimpPaintTool       *tool,
   GIMP_COLOR_TOOL (tool)->pick_target = target;
 }
 
+/**
+ * gimp_paint_tool_enable_multi_paint:
+ * @tool: a #GimpPaintTool
+ *
+ * This is a convenience function used from the init method of paint
+ * tools that want to allow painting with several drawables.
+ **/
+void
+gimp_paint_tool_enable_multi_paint (GimpPaintTool *tool)
+{
+  g_return_if_fail (GIMP_IS_PAINT_TOOL (tool));
+
+  tool->can_multi_paint = TRUE;
+}
+
 void
 gimp_paint_tool_set_draw_fallback (GimpPaintTool *tool,
                                    gboolean       draw_fallback,
diff --git a/app/tools/gimppainttool.h b/app/tools/gimppainttool.h
index faaf9c738a..4f1375221e 100644
--- a/app/tools/gimppainttool.h
+++ b/app/tools/gimppainttool.h
@@ -42,7 +42,8 @@ struct _GimpPaintTool
   GimpColorTool  parent_instance;
 
   gboolean       active;
-  gboolean       pick_colors;  /*  pick color if ctrl is pressed   */
+  gboolean       pick_colors;      /*  pick color if ctrl is pressed           */
+  gboolean       can_multi_paint;  /*  if paint works with multiple drawables  */
   gboolean       draw_line;
 
   gboolean       show_cursor;
@@ -60,7 +61,7 @@ struct _GimpPaintTool
   GimpPaintCore *core;
 
   GimpDisplay   *display;
-  GimpDrawable  *drawable;
+  GList         *drawables;
 
   gdouble        cursor_x;
   gdouble        cursor_y;
@@ -97,6 +98,8 @@ void    gimp_paint_tool_set_active          (GimpPaintTool       *tool,
 void    gimp_paint_tool_enable_color_picker (GimpPaintTool       *tool,
                                              GimpColorPickTarget  target);
 
+void    gimp_paint_tool_enable_multi_paint  (GimpPaintTool       *tool);
+
 void    gimp_paint_tool_set_draw_fallback   (GimpPaintTool       *tool,
                                              gboolean             draw_fallback,
                                              gint                 fallback_size);
diff --git a/app/tools/gimpsourcetool.c b/app/tools/gimpsourcetool.c
index 9d9f725182..b2c5f6d44d 100644
--- a/app/tools/gimpsourcetool.c
+++ b/app/tools/gimpsourcetool.c
@@ -116,6 +116,8 @@ static void
 gimp_source_tool_init (GimpSourceTool *source)
 {
   source->show_source_outline = TRUE;
+
+  gimp_paint_tool_enable_multi_paint (GIMP_PAINT_TOOL (source));
 }
 
 static gboolean


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]