[gimp/multi-stroke: 9/31] app: s/GimpMultiStroke/GimpSymmetry/



commit 57326b1640e6f8b20923af8fe3ce4a7ea6cc9ecf
Author: Jehan <jehan girinstud io>
Date:   Sun Mar 22 00:01:51 2015 +0100

    app: s/GimpMultiStroke/GimpSymmetry/
    
    As proposed by Mitch. Not sure that's a better naming, but he seemed
    to hate "Multi-Stroke".
    Also the base and child classes are moved to core/.

 app/config/gimpguiconfig.c                         |   16 +-
 app/config/gimpguiconfig.h                         |    2 +-
 app/config/gimprc-blurbs.h                         |    4 +-
 app/core/Makefile.am                               |    8 +
 app/core/core-types.h                              |    6 +
 app/core/gimpcontext.c                             |   11 +-
 app/core/gimpimage-private.h                       |    6 +-
 app/core/gimpimage-symmetry.c                      |  210 +++++++++++
 app/core/gimpimage-symmetry.h                      |   40 ++
 app/core/gimpimage.c                               |  175 +---------
 app/core/gimpimage.h                               |   14 -
 .../gimpmirror.c => core/gimpsymmetry-mirror.c}    |  206 ++++++------
 .../gimpmirror.h => core/gimpsymmetry-mirror.h}    |    8 +-
 .../gimptiling.c => core/gimpsymmetry-tiling.c}    |  191 +++++-----
 .../gimptiling.h => core/gimpsymmetry-tiling.h}    |   18 +-
 app/core/gimpsymmetry.c                            |  374 ++++++++++++++++++++
 app/core/gimpsymmetry.h                            |   92 +++++
 app/dialogs/preferences-dialog.c                   |    4 +-
 app/paint/Makefile.am                              |   10 +-
 app/paint/gimpairbrush.c                           |   37 +-
 app/paint/gimpairbrush.h                           |    2 +-
 app/paint/gimpclone.c                              |    2 +-
 app/paint/gimpconvolve.c                           |   23 +-
 app/paint/gimpdodgeburn.c                          |   23 +-
 app/paint/gimperaser.c                             |   37 +-
 app/paint/gimpink.c                                |   23 +-
 app/paint/gimpmultistroke-info.c                   |   61 ----
 app/paint/gimpmultistroke-info.h                   |   29 --
 app/paint/gimpmultistroke.c                        |  374 --------------------
 app/paint/gimpmultistroke.h                        |   94 -----
 app/paint/gimppaintbrush.c                         |   23 +-
 app/paint/gimppaintbrush.h                         |    2 +-
 app/paint/gimppaintcore.c                          |   27 +-
 app/paint/gimppaintcore.h                          |    2 +-
 app/paint/gimppaintoptions.c                       |   43 ++--
 app/paint/gimppaintoptions.h                       |    2 +-
 app/paint/gimpperspectiveclone.c                   |   14 +-
 app/paint/gimpsmudge.c                             |   33 +-
 app/paint/gimpsourcecore.c                         |   26 +-
 app/paint/gimpsourcecore.h                         |    2 +-
 app/paint/paint-types.h                            |    5 -
 app/tools/gimppaintoptions-gui.c                   |  102 +++---
 app/xcf/xcf-load.c                                 |   59 ++--
 app/xcf/xcf-private.h                              |    2 +-
 app/xcf/xcf-save.c                                 |   71 ++--
 devel-docs/xcf.txt                                 |   16 +-
 46 files changed, 1257 insertions(+), 1272 deletions(-)
---
diff --git a/app/config/gimpguiconfig.c b/app/config/gimpguiconfig.c
index 8b5c6fa..b376585 100644
--- a/app/config/gimpguiconfig.c
+++ b/app/config/gimpguiconfig.c
@@ -82,9 +82,9 @@ enum
 
   PROP_PLAYGROUND_NPD_TOOL,
   PROP_PLAYGROUND_HANDLE_TRANSFORM_TOOL,
-  PROP_PLAYGROUND_MULTI_STROKE,
   PROP_PLAYGROUND_MYBRUSH_TOOL,
   PROP_PLAYGROUND_SEAMLESS_CLONE_TOOL,
+  PROP_PLAYGROUND_SYMMETRY,
 
   PROP_HIDE_DOCKS,
   PROP_SINGLE_WINDOW_MODE,
@@ -292,9 +292,9 @@ gimp_gui_config_class_init (GimpGuiConfigClass *klass)
                                     GIMP_PARAM_STATIC_STRINGS |
                                     GIMP_CONFIG_PARAM_RESTART);
   GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class,
-                                    PROP_PLAYGROUND_MULTI_STROKE,
-                                    "playground-multi-stroke",
-                                    PLAYGROUND_MULTI_STROKE_BLURB,
+                                    PROP_PLAYGROUND_SYMMETRY,
+                                    "playground-symmetry",
+                                    PLAYGROUND_SYMMETRY_BLURB,
                                     FALSE,
                                     GIMP_PARAM_STATIC_STRINGS |
                                     GIMP_CONFIG_PARAM_RESTART);
@@ -523,8 +523,8 @@ gimp_gui_config_set_property (GObject      *object,
     case PROP_PLAYGROUND_HANDLE_TRANSFORM_TOOL:
       gui_config->playground_handle_transform_tool = g_value_get_boolean (value);
       break;
-    case PROP_PLAYGROUND_MULTI_STROKE:
-      gui_config->playground_multi_stroke = g_value_get_boolean (value);
+    case PROP_PLAYGROUND_SYMMETRY:
+      gui_config->playground_symmetry = g_value_get_boolean (value);
       break;
     case PROP_PLAYGROUND_MYBRUSH_TOOL:
       gui_config->playground_mybrush_tool = g_value_get_boolean (value);
@@ -673,8 +673,8 @@ gimp_gui_config_get_property (GObject    *object,
     case PROP_PLAYGROUND_HANDLE_TRANSFORM_TOOL:
       g_value_set_boolean (value, gui_config->playground_handle_transform_tool);
       break;
-    case PROP_PLAYGROUND_MULTI_STROKE:
-      g_value_set_boolean (value, gui_config->playground_multi_stroke);
+    case PROP_PLAYGROUND_SYMMETRY:
+      g_value_set_boolean (value, gui_config->playground_symmetry);
       break;
     case PROP_PLAYGROUND_MYBRUSH_TOOL:
       g_value_set_boolean (value, gui_config->playground_mybrush_tool);
diff --git a/app/config/gimpguiconfig.h b/app/config/gimpguiconfig.h
index 8b3a80d..c04c444 100644
--- a/app/config/gimpguiconfig.h
+++ b/app/config/gimpguiconfig.h
@@ -76,9 +76,9 @@ struct _GimpGuiConfig
   /* experimental playground */
   gboolean             playground_npd_tool;
   gboolean             playground_handle_transform_tool;
-  gboolean             playground_multi_stroke;
   gboolean             playground_mybrush_tool;
   gboolean             playground_seamless_clone_tool;
+  gboolean             playground_symmetry;
 
   /* saved in sessionrc */
   gboolean             hide_docks;
diff --git a/app/config/gimprc-blurbs.h b/app/config/gimprc-blurbs.h
index a71acac..71a5d77 100644
--- a/app/config/gimprc-blurbs.h
+++ b/app/config/gimprc-blurbs.h
@@ -388,8 +388,8 @@ _("Enable the N-Point Deformation tool.")
 #define PLAYGROUND_HANDLE_TRANSFORM_TOOL_BLURB \
 _("Enable the Handle Transform tool.")
 
-#define PLAYGROUND_MULTI_STROKE_BLURB \
-_("Enable the Multi Stroke on painting.")
+#define PLAYGROUND_SYMMETRY_BLURB \
+_("Enable symmetry on painting.")
 
 #define PLAYGROUND_MYBRUSH_TOOL_BLURB \
 _("Enable the MyPaint Brush tool.")
diff --git a/app/core/Makefile.am b/app/core/Makefile.am
index f4836a3..a1a01af 100644
--- a/app/core/Makefile.am
+++ b/app/core/Makefile.am
@@ -258,6 +258,8 @@ libappcore_a_sources = \
        gimpimage-scale.h                       \
        gimpimage-snap.c                        \
        gimpimage-snap.h                        \
+       gimpimage-symmetry.c                    \
+       gimpimage-symmetry.h                    \
        gimpimage-undo.c                        \
        gimpimage-undo.h                        \
        gimpimage-undo-push.c                   \
@@ -361,6 +363,12 @@ libappcore_a_sources = \
        gimpstrokeoptions.h                     \
        gimpsubprogress.c                       \
        gimpsubprogress.h                       \
+       gimpsymmetry.c                  \
+       gimpsymmetry.h                  \
+       gimpsymmetry-mirror.c           \
+       gimpsymmetry-mirror.h   \
+       gimpsymmetry-tiling.c           \
+       gimpsymmetry-tiling.h   \
        gimptag.c                               \
        gimptag.h                               \
        gimptagcache.c                          \
diff --git a/app/core/core-types.h b/app/core/core-types.h
index 7fe6afb..d0699e3 100644
--- a/app/core/core-types.h
+++ b/app/core/core-types.h
@@ -174,6 +174,12 @@ typedef struct _GimpUndoStack         GimpUndoStack;
 typedef struct _GimpUndoAccumulator   GimpUndoAccumulator;
 
 
+/* Symmetry transformations */
+
+typedef struct _GimpSymmetry        GimpSymmetry;
+typedef struct _GimpMirror          GimpMirror;
+typedef struct _GimpTiling          GimpTiling;
+
 /*  misc objects  */
 
 typedef struct _GimpBuffer          GimpBuffer;
diff --git a/app/core/gimpcontext.c b/app/core/gimpcontext.c
index eea358f..ac27061 100644
--- a/app/core/gimpcontext.c
+++ b/app/core/gimpcontext.c
@@ -43,15 +43,16 @@
 #include "gimpimagefile.h"
 #include "gimpgradient.h"
 #include "gimpimage.h"
+#include "gimpimage-symmetry.h"
 #include "gimpmarshal.h"
 #include "gimppaintinfo.h"
 #include "gimppalette.h"
 #include "gimppattern.h"
+#include "gimpsymmetry.h"
 #include "gimptemplate.h"
 #include "gimptoolinfo.h"
 #include "gimptoolpreset.h"
 
-#include "paint/gimpmultistroke.h"
 #include "paint/gimppaintoptions.h"
 
 #include "text/gimpfont.h"
@@ -1930,15 +1931,15 @@ gimp_context_real_set_image (GimpContext *context,
       GIMP_IS_PAINT_OPTIONS (context->tool_info->tool_options))
     {
       GimpPaintOptions *paint_options;
-      GimpMultiStroke  *mstroke = NULL;
+      GimpSymmetry  *sym = NULL;
 
       paint_options = GIMP_PAINT_OPTIONS (context->tool_info->tool_options);
 
       if (image)
-        mstroke = gimp_image_get_selected_multi_stroke (image);
+        sym = gimp_image_get_selected_symmetry (image);
 
-      g_object_set (paint_options, "multi-stroke",
-                    mstroke ? mstroke->type : G_TYPE_NONE,
+      g_object_set (paint_options, "symmetry",
+                    sym ? sym->type : G_TYPE_NONE,
                     NULL);
     }
 
diff --git a/app/core/gimpimage-private.h b/app/core/gimpimage-private.h
index 3ed271d..5b4029c 100644
--- a/app/core/gimpimage-private.h
+++ b/app/core/gimpimage-private.h
@@ -87,9 +87,9 @@ struct _GimpImagePrivate
   GeglNode          *graph;                 /*  GEGL projection graph        */
   GeglNode          *visible_mask;          /*  component visibility node    */
 
-  GList             *transformations;       /* Multi-Stroke transformations  */
-  GimpMultiStroke   *selected_transform;    /* Selected transformation       */
-  GimpMultiStroke   *single_stroke;         /* The base "Single" stroke      */
+  GList             *symmetries;            /*  Painting symmetries          */
+  GimpSymmetry      *selected_symmetry;     /*  Selected symmetry            */
+  GimpSymmetry      *id_symmetry;           /*  The base "Single" stroke     */
 
   GList             *guides;                /*  guides                       */
   GimpGrid          *grid;                  /*  grid                         */
diff --git a/app/core/gimpimage-symmetry.c b/app/core/gimpimage-symmetry.c
new file mode 100644
index 0000000..dff9aa7
--- /dev/null
+++ b/app/core/gimpimage-symmetry.c
@@ -0,0 +1,210 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpimage-symmetry.c
+ * Copyright (C) 2015 Jehan <jehan gimp org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "core-types.h"
+
+#include "gimpsymmetry.h"
+#include "gimpimage.h"
+#include "gimpimage-private.h"
+#include "gimpimage-symmetry.h"
+#include "gimpsymmetry-mirror.h"
+#include "gimpsymmetry-tiling.h"
+
+GList *
+gimp_image_symmetry_list (void)
+{
+  GList *list = NULL;
+
+  list = g_list_prepend (list, GINT_TO_POINTER (GIMP_TYPE_MIRROR));
+  list = g_list_prepend (list, GINT_TO_POINTER (GIMP_TYPE_TILING));
+  return list;
+}
+
+GimpSymmetry *
+gimp_image_symmetry_new (GimpImage *image,
+                         GType      type)
+{
+  GimpSymmetry *sym = NULL;
+
+  g_return_val_if_fail (g_type_is_a (type, GIMP_TYPE_SYMMETRY),
+                        NULL);
+
+  if (type != G_TYPE_NONE)
+    {
+      sym = g_object_new (type,
+                          "image", image,
+                          NULL);
+      sym->type = type;
+    }
+
+  return sym;
+}
+
+/**
+ * gimp_image_add_symmetry:
+ * @image:   the #GimpImage
+ * @sym: the #GimpSymmetry
+ *
+ * Add a symmetry transformation to @image and make it the
+ * selected transformation.
+ **/
+void
+gimp_image_add_symmetry (GimpImage    *image,
+                         GimpSymmetry *sym)
+{
+  GimpImagePrivate *private;
+
+  g_return_if_fail (GIMP_IS_IMAGE (image));
+  g_return_if_fail (GIMP_IS_SYMMETRY (sym));
+
+  private = GIMP_IMAGE_GET_PRIVATE (image);
+
+  private->symmetries = g_list_prepend (private->symmetries,
+                                        g_object_ref (sym));
+  private->selected_symmetry = sym;
+}
+
+/**
+ * gimp_image_remove_symmetry:
+ * @image:   the #GimpImage
+ * @sym: the #GimpSymmetry
+ *
+ * Remove @sym from the list of symmetries of @image.
+ * If it was the selected transformation, unselect it first.
+ **/
+void
+gimp_image_remove_symmetry (GimpImage    *image,
+                            GimpSymmetry *sym)
+{
+  GimpImagePrivate *private;
+
+  g_return_if_fail (GIMP_IS_SYMMETRY (sym));
+  g_return_if_fail (GIMP_IS_IMAGE (image));
+
+  private = GIMP_IMAGE_GET_PRIVATE (image);
+
+  if (private->selected_symmetry == sym)
+    private->selected_symmetry = NULL;
+  private->symmetries = g_list_remove (private->symmetries,
+                                       sym);
+  g_object_unref (sym);
+}
+
+/**
+ * gimp_image_get_symmetry:
+ * @image: the #GimpImage
+ *
+ * Returns a list of #GimpSymmetry set on @image.
+ * The returned list belongs to @image and should not be freed.
+ **/
+GList *
+gimp_image_get_symmetrys (GimpImage *image)
+{
+  GimpImagePrivate *private;
+
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
+
+  private = GIMP_IMAGE_GET_PRIVATE (image);
+
+  return private->symmetries;
+}
+
+/**
+ * gimp_image_select_symmetry:
+ * @image: the #GimpImage
+ * @type:  the #GType of the symmetry
+ *
+ * Select the symmetry of type @type.
+ * Using the GType allows to select a transformation without
+ * knowing whether one of the same @type was already created.
+ *
+ * Returns TRUE on success, FALSE if no such symmetry was found.
+ **/
+gboolean
+gimp_image_select_symmetry (GimpImage *image,
+                            GType      type)
+{
+  GimpImagePrivate *private;
+  GList *iter;
+
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
+
+  private = GIMP_IMAGE_GET_PRIVATE (image);
+
+  if (type == G_TYPE_NONE)
+    {
+      private->selected_symmetry = NULL;
+      return TRUE;
+    }
+  else
+    {
+      for (iter = private->symmetries; iter; iter = g_list_next (iter))
+        {
+          GimpSymmetry *sym = iter->data;
+          if (g_type_is_a (sym->type, type))
+            {
+              private->selected_symmetry = iter->data;
+              return TRUE;
+            }
+        }
+    }
+  return FALSE;
+}
+
+/**
+ * gimp_image_get_selected_symmetry:
+ * @image: the #GimpImage
+ *
+ * Returns the #GimpSymmetry transformation selected on @image.
+ **/
+GimpSymmetry *
+gimp_image_get_selected_symmetry (GimpImage *image)
+{
+  GimpImagePrivate *private;
+
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
+
+  private = GIMP_IMAGE_GET_PRIVATE (image);
+
+  return private->selected_symmetry;
+}
+
+/**
+ * gimp_image_symmetry_get_id:
+ * @image: the #GimpImage
+ *
+ * Returns the basic "single stroke" #GimpSymmetry.
+ **/
+GimpSymmetry *
+gimp_image_symmetry_get_id (GimpImage *image)
+{
+  GimpImagePrivate *private;
+
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
+
+  private = GIMP_IMAGE_GET_PRIVATE (image);
+
+  return private->id_symmetry;
+}
diff --git a/app/core/gimpimage-symmetry.h b/app/core/gimpimage-symmetry.h
new file mode 100644
index 0000000..7ebeaf7
--- /dev/null
+++ b/app/core/gimpimage-symmetry.h
@@ -0,0 +1,40 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpimage-symmetry.h
+ * Copyright (C) 2015 Jehan <jehan gimp org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_IMAGE_SYMMETRY_H__
+#define __GIMP_IMAGE_SYMMETRY_H__
+
+GList        * gimp_image_symmetry_list (void);
+
+GimpSymmetry * gimp_image_symmetry_new          (GimpImage    *image,
+                                                 GType         type);
+
+void           gimp_image_add_symmetry          (GimpImage    *image,
+                                                 GimpSymmetry *sym);
+void           gimp_image_remove_symmetry       (GimpImage    *image,
+                                                 GimpSymmetry *sym);
+GList        * gimp_image_get_symmetrys         (GimpImage    *image);
+
+gboolean       gimp_image_select_symmetry       (GimpImage    *image,
+                                                 GType         type);
+GimpSymmetry * gimp_image_get_selected_symmetry (GimpImage    *image);
+GimpSymmetry * gimp_image_symmetry_get_id       (GimpImage    *image);
+
+#endif  /*  __GIMP_IMAGE_SYMMETRY_H__  */
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index c4c9eee..38d6a08 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -36,9 +36,6 @@
 
 #include "gegl/gimp-babl.h"
 
-#include "paint/gimpmultistroke.h"
-#include "paint/gimpmultistroke-info.h"
-
 #include "gimp.h"
 #include "gimp-memsize.h"
 #include "gimp-parasites.h"
@@ -58,6 +55,7 @@
 #include "gimpimage-preview.h"
 #include "gimpimage-private.h"
 #include "gimpimage-quick-mask.h"
+#include "gimpimage-symmetry.h"
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
 #include "gimpitemtree.h"
@@ -71,6 +69,7 @@
 #include "gimpprojection.h"
 #include "gimpsamplepoint.h"
 #include "gimpselection.h"
+#include "gimpsymmetry.h"
 #include "gimptempbuf.h"
 #include "gimptemplate.h"
 #include "gimpundostack.h"
@@ -700,10 +699,10 @@ gimp_image_init (GimpImage *image)
 
   private->projection          = gimp_projection_new (GIMP_PROJECTABLE (image));
 
-  private->transformations     = NULL;
-  private->selected_transform  = NULL;
-  private->single_stroke       = gimp_multi_stroke_new (GIMP_TYPE_MULTI_STROKE,
-                                                        image);
+  private->symmetries          = NULL;
+  private->selected_symmetry   = NULL;
+  private->id_symmetry         = gimp_image_symmetry_new (image,
+                                                          GIMP_TYPE_SYMMETRY);
 
   private->guides              = NULL;
   private->grid                = NULL;
@@ -1059,16 +1058,16 @@ gimp_image_finalize (GObject *object)
       private->guides = NULL;
     }
 
-  if (private->transformations)
+  if (private->symmetries)
     {
-      g_list_free_full (private->transformations, g_object_unref);
-      private->transformations = NULL;
+      g_list_free_full (private->symmetries, g_object_unref);
+      private->symmetries = NULL;
     }
 
-  if (private->single_stroke)
+  if (private->id_symmetry)
     {
-      g_object_unref (private->single_stroke);
-      private->single_stroke = NULL;
+      g_object_unref (private->id_symmetry);
+      private->id_symmetry = NULL;
     }
 
   if (private->grid)
@@ -2356,8 +2355,8 @@ gimp_image_get_xcf_version (GimpImage    *image,
   if (zlib_compression)
     version = MAX (8, version);
 
-  /* need version 9 for Multi-Stroke */
-  if (private->transformations)
+  /* need version 9 for symmetry */
+  if (private->symmetries)
     {
       version = MAX (9, version);
     }
@@ -4601,149 +4600,3 @@ gimp_image_invalidate_previews (GimpImage *image)
   gimp_item_stack_invalidate_previews (channels);
 }
 
-/**
- * gimp_image_add_multi_stroke:
- * @image:   the #GimpImage
- * @mstroke: the #GimpMultiStroke
- *
- * Add a multi-stroke transformation to @image and make it the
- * selected transformation.
- **/
-void
-gimp_image_add_multi_stroke (GimpImage       *image,
-                             GimpMultiStroke *mstroke)
-{
-  GimpImagePrivate *private;
-
-  g_return_if_fail (GIMP_IS_IMAGE (image));
-  g_return_if_fail (GIMP_IS_MULTI_STROKE (mstroke));
-
-  private = GIMP_IMAGE_GET_PRIVATE (image);
-
-  private->transformations = g_list_prepend (private->transformations,
-                                             g_object_ref (mstroke));
-  private->selected_transform = mstroke;
-}
-
-/**
- * gimp_image_remove_multi_stroke:
- * @image:   the #GimpImage
- * @mstroke: the #GimpMultiStroke
- *
- * Remove @mstroke from the list of transformations of @image.
- * If it was the selected transformation, unselect it first.
- **/
-void
-gimp_image_remove_multi_stroke (GimpImage       *image,
-                                GimpMultiStroke *mstroke)
-{
-  GimpImagePrivate *private;
-
-  g_return_if_fail (GIMP_IS_MULTI_STROKE (mstroke));
-  g_return_if_fail (GIMP_IS_IMAGE (image));
-
-  private = GIMP_IMAGE_GET_PRIVATE (image);
-
-  if (private->selected_transform == mstroke)
-    private->selected_transform = NULL;
-  private->transformations = g_list_remove (private->transformations,
-                                            mstroke);
-  g_object_unref (mstroke);
-}
-
-/**
- * gimp_image_get_multi_stroke:
- * @image: the #GimpImage
- *
- * Returns a list of #GimpMultiStroke set on @image.
- * The returned list belongs to @image and should not be freed.
- **/
-GList *
-gimp_image_get_multi_strokes (GimpImage *image)
-{
-  GimpImagePrivate *private;
-
-  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
-
-  private = GIMP_IMAGE_GET_PRIVATE (image);
-
-  return private->transformations;
-}
-
-/**
- * gimp_image_select_multi_stroke:
- * @image: the #GimpImage
- * @type:  the #GType of the multi-stroke
- *
- * Select the multi-stroke of type @type.
- * Using the GType allows to select a transformation without
- * knowing whether one of the same @type was already created.
- *
- * Returns TRUE on success, FALSE if no such multi-stroke was found.
- **/
-gboolean
-gimp_image_select_multi_stroke (GimpImage *image,
-                                GType      type)
-{
-  GimpImagePrivate *private;
-  GList *iter;
-
-  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
-
-  private = GIMP_IMAGE_GET_PRIVATE (image);
-
-  if (type == G_TYPE_NONE)
-    {
-      private->selected_transform = NULL;
-      return TRUE;
-    }
-  else
-    {
-      for (iter = private->transformations; iter; iter = g_list_next (iter))
-        {
-          GimpMultiStroke *mstroke = iter->data;
-          if (g_type_is_a (mstroke->type, type))
-            {
-              private->selected_transform = iter->data;
-              return TRUE;
-            }
-        }
-    }
-  return FALSE;
-}
-
-/**
- * gimp_image_get_selected_multi_stroke:
- * @image: the #GimpImage
- *
- * Returns the #GimpMultiStroke transformation selected on @image.
- **/
-GimpMultiStroke *
-gimp_image_get_selected_multi_stroke (GimpImage *image)
-{
-  GimpImagePrivate *private;
-
-  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
-
-  private = GIMP_IMAGE_GET_PRIVATE (image);
-
-  return private->selected_transform;
-}
-
-/**
- * gimp_image_get_single_stroke:
- * @image: the #GimpImage
- *
- * Returns the basic "single stroke" #GimpMultiStroke.
- **/
-GimpMultiStroke *
-gimp_image_get_single_stroke (GimpImage *image)
-{
-  GimpImagePrivate *private;
-
-  g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
-
-  private = GIMP_IMAGE_GET_PRIVATE (image);
-
-  return private->single_stroke;
-}
diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h
index c11a8af..28d7554 100644
--- a/app/core/gimpimage.h
+++ b/app/core/gimpimage.h
@@ -435,19 +435,5 @@ gboolean    gimp_image_coords_in_active_pickable (GimpImage          *image,
 
 void            gimp_image_invalidate_previews   (GimpImage          *image);
 
-/* Painting Transformations */
-
-void            gimp_image_add_multi_stroke      (GimpImage       *image,
-                                                  GimpMultiStroke *mstroke);
-void            gimp_image_remove_multi_stroke   (GimpImage       *image,
-                                                  GimpMultiStroke *mstroke);
-GList         * gimp_image_get_multi_strokes     (GimpImage       *image);
-
-gboolean        gimp_image_select_multi_stroke   (GimpImage       *image,
-                                                  GType            type);
-GimpMultiStroke *
-            gimp_image_get_selected_multi_stroke (GimpImage       *image);
-GimpMultiStroke * gimp_image_get_single_stroke   (GimpImage       *image);
-
 
 #endif /* __GIMP_IMAGE_H__ */
diff --git a/app/paint/gimpmirror.c b/app/core/gimpsymmetry-mirror.c
similarity index 88%
rename from app/paint/gimpmirror.c
rename to app/core/gimpsymmetry-mirror.c
index ce1808d..0819d3f 100644
--- a/app/paint/gimpmirror.c
+++ b/app/core/gimpsymmetry-mirror.c
@@ -1,7 +1,7 @@
 /* GIMP - The GNU Image Manipulation Program
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
- * gimpmirror.c
+ * gimpsymmetry-mirror.c
  * Copyright (C) 2015 Jehan <jehan gimp org>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -27,18 +27,16 @@
 
 #include "libgimpconfig/gimpconfig.h"
 
-#include "paint-types.h"
+#include "core-types.h"
 
-#include "core/gimp.h"
-#include "core/gimpbrush.h"
-#include "core/gimpmirrorguide.h"
-#include "core/gimpimage.h"
-#include "core/gimpimage-guides.h"
-#include "core/gimpitem.h"
-
-#include "gimpbrushcore.h"
-#include "gimpmirror.h"
-#include "gimpsourcecore.h"
+#include "gimp.h"
+#include "gimpbrush.h"
+#include "gimpmirrorguide.h"
+#include "gimpimage.h"
+#include "gimpimage-guides.h"
+#include "gimpimage-symmetry.h"
+#include "gimpitem.h"
+#include "gimpsymmetry-mirror.h"
 
 #include "gimp-intl.h"
 
@@ -56,44 +54,44 @@ enum
 
 /* Local function prototypes */
 
-static void       gimp_mirror_finalize            (GObject         *object);
-static void       gimp_mirror_set_property        (GObject         *object,
-                                                   guint            property_id,
-                                                   const GValue    *value,
-                                                   GParamSpec      *pspec);
-static void       gimp_mirror_get_property        (GObject         *object,
-                                                   guint            property_id,
-                                                   GValue          *value,
-                                                   GParamSpec      *pspec);
-
-static void       gimp_mirror_update_strokes      (GimpMultiStroke *mirror,
-                                                   GimpDrawable    *drawable,
-                                                   GimpCoords      *origin);
-static void       gimp_mirror_prepare_operations  (GimpMirror      *mirror,
-                                                   gint             paint_width,
-                                                   gint             paint_height);
-static GeglNode * gimp_mirror_get_operation       (GimpMultiStroke *mirror,
-                                                   gint             stroke,
-                                                   gint             paint_width,
-                                                   gint             paint_height);
-static void       gimp_mirror_reset               (GimpMirror      *mirror);
-static void       gimp_mirror_guide_removed_cb    (GObject         *object,
-                                                   GimpMirror      *mirror);
-static void       gimp_mirror_guide_position_cb   (GObject         *object,
-                                                   GParamSpec      *pspec,
-                                                   GimpMirror      *mirror);
-static GParamSpec ** gimp_mirror_get_settings     (GimpMultiStroke *mstroke,
-                                                   guint           *nsettings);
-static GParamSpec ** gimp_mirror_get_xcf_settings (GimpMultiStroke *mstroke,
-                                                   guint           *nsettings);
-static void  gimp_mirror_set_horizontal_symmetry  (GimpMirror      *mirror,
-                                                   gboolean         active);
-static void    gimp_mirror_set_vertical_symmetry  (GimpMirror      *mirror,
-                                                   gboolean         active);
-static void       gimp_mirror_set_point_symmetry  (GimpMirror      *mirror,
-                                                   gboolean         active);
-
-G_DEFINE_TYPE (GimpMirror, gimp_mirror, GIMP_TYPE_MULTI_STROKE)
+static void       gimp_mirror_finalize            (GObject      *object);
+static void       gimp_mirror_set_property        (GObject      *object,
+                                                   guint         property_id,
+                                                   const GValue *value,
+                                                   GParamSpec   *pspec);
+static void       gimp_mirror_get_property        (GObject      *object,
+                                                   guint         property_id,
+                                                   GValue       *value,
+                                                   GParamSpec   *pspec);
+
+static void       gimp_mirror_update_strokes      (GimpSymmetry *mirror,
+                                                   GimpDrawable *drawable,
+                                                   GimpCoords   *origin);
+static void       gimp_mirror_prepare_operations  (GimpMirror   *mirror,
+                                                   gint          paint_width,
+                                                   gint          paint_height);
+static GeglNode * gimp_mirror_get_operation       (GimpSymmetry *mirror,
+                                                   gint          stroke,
+                                                   gint          paint_width,
+                                                   gint          paint_height);
+static void       gimp_mirror_reset               (GimpMirror   *mirror);
+static void       gimp_mirror_guide_removed_cb    (GObject      *object,
+                                                   GimpMirror   *mirror);
+static void       gimp_mirror_guide_position_cb   (GObject      *object,
+                                                   GParamSpec   *pspec,
+                                                   GimpMirror   *mirror);
+static GParamSpec ** gimp_mirror_get_settings     (GimpSymmetry *sym,
+                                                   guint        *nsettings);
+static GParamSpec ** gimp_mirror_get_xcf_settings (GimpSymmetry *sym,
+                                                   guint        *nsettings);
+static void  gimp_mirror_set_horizontal_symmetry  (GimpMirror   *mirror,
+                                                   gboolean      active);
+static void    gimp_mirror_set_vertical_symmetry  (GimpMirror   *mirror,
+                                                   gboolean      active);
+static void       gimp_mirror_set_point_symmetry  (GimpMirror   *mirror,
+                                                   gboolean      active);
+
+G_DEFINE_TYPE (GimpMirror, gimp_mirror, GIMP_TYPE_SYMMETRY)
 
 #define parent_class gimp_mirror_parent_class
 
@@ -101,17 +99,17 @@ static void
 gimp_mirror_class_init (GimpMirrorClass *klass)
 {
   GObjectClass         *object_class       = G_OBJECT_CLASS (klass);
-  GimpMultiStrokeClass *multi_stroke_class = GIMP_MULTI_STROKE_CLASS (klass);
+  GimpSymmetryClass *symmetry_class = GIMP_SYMMETRY_CLASS (klass);
 
   object_class->finalize               = gimp_mirror_finalize;
   object_class->set_property           = gimp_mirror_set_property;
   object_class->get_property           = gimp_mirror_get_property;
 
-  multi_stroke_class->label            = "Mirror";
-  multi_stroke_class->update_strokes   = gimp_mirror_update_strokes;
-  multi_stroke_class->get_operation    = gimp_mirror_get_operation;
-  multi_stroke_class->get_settings     = gimp_mirror_get_settings;
-  multi_stroke_class->get_xcf_settings = gimp_mirror_get_xcf_settings;
+  symmetry_class->label            = "Mirror";
+  symmetry_class->update_strokes   = gimp_mirror_update_strokes;
+  symmetry_class->get_operation    = gimp_mirror_get_operation;
+  symmetry_class->get_settings     = gimp_mirror_get_settings;
+  symmetry_class->get_xcf_settings = gimp_mirror_get_xcf_settings;
 
   /* Properties for user settings */
   GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_HORIZONTAL_SYMMETRY,
@@ -265,15 +263,15 @@ gimp_mirror_get_property (GObject    *object,
 }
 
 static void
-gimp_mirror_update_strokes (GimpMultiStroke *mstroke,
-                            GimpDrawable    *drawable,
-                            GimpCoords      *origin)
+gimp_mirror_update_strokes (GimpSymmetry *sym,
+                            GimpDrawable *drawable,
+                            GimpCoords   *origin)
 {
   GList      *strokes = NULL;
-  GimpMirror *mirror  = GIMP_MIRROR (mstroke);
+  GimpMirror *mirror  = GIMP_MIRROR (sym);
   GimpCoords *coords;
 
-  g_list_free_full (mstroke->strokes, g_free);
+  g_list_free_full (sym->strokes, g_free);
   strokes = g_list_prepend (strokes,
                             g_memdup (origin, sizeof (GimpCoords)));
 
@@ -296,9 +294,9 @@ gimp_mirror_update_strokes (GimpMultiStroke *mstroke,
       coords->y = 2.0 * mirror->horizontal_position - origin->y;
       strokes = g_list_prepend (strokes, coords);
     }
-  mstroke->strokes = g_list_reverse (strokes);
+  sym->strokes = g_list_reverse (strokes);
 
-  g_signal_emit_by_name (mstroke, "strokes-updated", mstroke->image);
+  g_signal_emit_by_name (sym, "strokes-updated", sym->image);
 }
 
 static void gimp_mirror_prepare_operations (GimpMirror *mirror,
@@ -355,16 +353,16 @@ static void gimp_mirror_prepare_operations (GimpMirror *mirror,
 }
 
 static GeglNode *
-gimp_mirror_get_operation (GimpMultiStroke *mstroke,
-                           gint             stroke,
-                           gint             paint_width,
-                           gint             paint_height)
+gimp_mirror_get_operation (GimpSymmetry *sym,
+                           gint          stroke,
+                           gint          paint_width,
+                           gint          paint_height)
 {
-  GimpMirror *mirror  = GIMP_MIRROR (mstroke);
+  GimpMirror *mirror  = GIMP_MIRROR (sym);
   GeglNode   *op;
 
   g_return_val_if_fail (stroke >= 0 &&
-                        stroke < g_list_length (mstroke->strokes), NULL);
+                        stroke < g_list_length (sym->strokes), NULL);
 
   gimp_mirror_prepare_operations (mirror, paint_width, paint_height);
 
@@ -387,16 +385,16 @@ gimp_mirror_get_operation (GimpMultiStroke *mstroke,
 static void
 gimp_mirror_reset (GimpMirror *mirror)
 {
-  GimpMultiStroke *mstroke;
+  GimpSymmetry *sym;
 
   g_return_if_fail (GIMP_IS_MIRROR (mirror));
 
-  mstroke = GIMP_MULTI_STROKE (mirror);
+  sym = GIMP_SYMMETRY (mirror);
 
-  if (mstroke->origin)
+  if (sym->origin)
     {
-      gimp_multi_stroke_set_origin (mstroke, mstroke->drawable,
-                                    mstroke->origin);
+      gimp_symmetry_set_origin (sym, sym->drawable,
+                                sym->origin);
     }
 }
 
@@ -433,11 +431,11 @@ gimp_mirror_guide_removed_cb (GObject    *object,
   if (mirror->horizontal_guide == NULL &&
       mirror->vertical_guide   == NULL)
     {
-      GimpMultiStroke *mstroke;
+      GimpSymmetry *sym;
 
-      mstroke = GIMP_MULTI_STROKE (mirror);
-      gimp_image_remove_multi_stroke (mstroke->image,
-                                      GIMP_MULTI_STROKE (mirror));
+      sym = GIMP_SYMMETRY (mirror);
+      gimp_image_remove_symmetry (sym->image,
+                                  GIMP_SYMMETRY (mirror));
     }
   else
     {
@@ -465,47 +463,47 @@ gimp_mirror_guide_position_cb (GObject    *object,
 }
 
 static GParamSpec **
-gimp_mirror_get_settings (GimpMultiStroke *mstroke,
-                          guint           *nsettings)
+gimp_mirror_get_settings (GimpSymmetry *sym,
+                          guint        *nsettings)
 {
   GParamSpec **pspecs;
 
   *nsettings = 5;
   pspecs = g_new (GParamSpec*, 5);
 
-  pspecs[0] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[0] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "horizontal-symmetry");
-  pspecs[1] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[1] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "vertical-symmetry");
-  pspecs[2] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[2] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "point-symmetry");
   pspecs[3] = NULL;
-  pspecs[4] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[4] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "disable-transformation");
 
   return pspecs;
 }
 
 static GParamSpec **
-gimp_mirror_get_xcf_settings (GimpMultiStroke *mstroke,
-                              guint           *nsettings)
+gimp_mirror_get_xcf_settings (GimpSymmetry *sym,
+                              guint        *nsettings)
 {
   GParamSpec **pspecs;
 
   *nsettings = 6;
   pspecs = g_new (GParamSpec*, 6);
 
-  pspecs[0] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[0] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "horizontal-symmetry");
-  pspecs[1] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[1] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "vertical-symmetry");
-  pspecs[2] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[2] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "point-symmetry");
-  pspecs[3] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[3] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "horizontal-position");
-  pspecs[4] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[4] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "vertical-position");
-  pspecs[5] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[5] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "disable-transformation");
 
   return pspecs;
@@ -515,13 +513,13 @@ static void
 gimp_mirror_set_horizontal_symmetry (GimpMirror *mirror,
                                      gboolean    active)
 {
-  GimpMultiStroke *mstroke;
-  GimpImage       *image;
+  GimpSymmetry *sym;
+  GimpImage    *image;
 
   g_return_if_fail (GIMP_IS_MIRROR (mirror));
 
-  mstroke = GIMP_MULTI_STROKE (mirror);
-  image   = mstroke->image;
+  sym   = GIMP_SYMMETRY (mirror);
+  image = sym->image;
 
   if (active == mirror->horizontal_mirror)
     return;
@@ -574,13 +572,13 @@ static void
 gimp_mirror_set_vertical_symmetry (GimpMirror *mirror,
                                    gboolean    active)
 {
-  GimpMultiStroke *mstroke;
-  GimpImage       *image;
+  GimpSymmetry *sym;
+  GimpImage    *image;
 
   g_return_if_fail (GIMP_IS_MIRROR (mirror));
 
-  mstroke = GIMP_MULTI_STROKE (mirror);
-  image   = mstroke->image;
+  sym   = GIMP_SYMMETRY (mirror);
+  image = sym->image;
 
   if (active == mirror->vertical_mirror)
     return;
@@ -633,13 +631,13 @@ static void
 gimp_mirror_set_point_symmetry (GimpMirror *mirror,
                                 gboolean    active)
 {
-  GimpMultiStroke *mstroke;
-  GimpImage       *image;
+  GimpSymmetry *sym;
+  GimpImage    *image;
 
   g_return_if_fail (GIMP_IS_MIRROR (mirror));
 
-  mstroke = GIMP_MULTI_STROKE (mirror);
-  image   = mstroke->image;
+  sym   = GIMP_SYMMETRY (mirror);
+  image = sym->image;
 
   if (active == mirror->point_symmetry)
     return;
diff --git a/app/paint/gimpmirror.h b/app/core/gimpsymmetry-mirror.h
similarity index 94%
rename from app/paint/gimpmirror.h
rename to app/core/gimpsymmetry-mirror.h
index 9e0004c..abe6e51 100644
--- a/app/paint/gimpmirror.h
+++ b/app/core/gimpsymmetry-mirror.h
@@ -1,7 +1,7 @@
 /* GIMP - The GNU Image Manipulation Program
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
- * gimpmirror.h
+ * gimpsymmetry-mirror.h
  * Copyright (C) 2015 Jehan <jehan gimp org>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -22,7 +22,7 @@
 #define __GIMP_MIRROR_H__
 
 
-#include "gimpmultistroke.h"
+#include "gimpsymmetry.h"
 
 
 #define GIMP_TYPE_MIRROR            (gimp_mirror_get_type ())
@@ -36,7 +36,7 @@ typedef struct _GimpMirrorClass GimpMirrorClass;
 
 struct _GimpMirror
 {
-  GimpMultiStroke  parent_instance;
+  GimpSymmetry     parent_instance;
 
   gboolean         horizontal_mirror;
   gboolean         vertical_mirror;
@@ -58,7 +58,7 @@ struct _GimpMirror
 
 struct _GimpMirrorClass
 {
-  GimpMultiStrokeClass  parent_class;
+  GimpSymmetryClass  parent_class;
 };
 
 
diff --git a/app/paint/gimptiling.c b/app/core/gimpsymmetry-tiling.c
similarity index 68%
rename from app/paint/gimptiling.c
rename to app/core/gimpsymmetry-tiling.c
index 379868d..a6ef8c9 100644
--- a/app/paint/gimptiling.c
+++ b/app/core/gimpsymmetry-tiling.c
@@ -1,7 +1,7 @@
 /* GIMP - The GNU Image Manipulation Program
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
- * gimptiling.c
+ * gimpsymmetry-tiling.c
  * Copyright (C) 2015 Jehan <jehan gimp org>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -27,14 +27,13 @@
 
 #include "libgimpconfig/gimpconfig.h"
 
-#include "paint-types.h"
+#include "core-types.h"
 
-#include "core/gimp.h"
-#include "core/gimpdrawable.h"
-#include "core/gimpimage.h"
-#include "core/gimpitem.h"
-
-#include "gimptiling.h"
+#include "gimp.h"
+#include "gimpdrawable.h"
+#include "gimpimage.h"
+#include "gimpitem.h"
+#include "gimpsymmetry-tiling.h"
 
 #include "gimp-intl.h"
 
@@ -54,35 +53,35 @@ enum
 
 /* Local function prototypes */
 
-static void       gimp_tiling_constructed        (GObject         *object);
-static void       gimp_tiling_finalize           (GObject         *object);
-static void       gimp_tiling_set_property       (GObject         *object,
-                                                  guint            property_id,
-                                                  const GValue    *value,
-                                                  GParamSpec      *pspec);
-static void       gimp_tiling_get_property       (GObject         *object,
-                                                  guint            property_id,
-                                                  GValue          *value,
-                                                  GParamSpec      *pspec);
-
-static void       gimp_tiling_update_strokes     (GimpMultiStroke *tiling,
-                                                  GimpDrawable    *drawable,
-                                                  GimpCoords      *origin);
-static GeglNode * gimp_tiling_get_operation      (GimpMultiStroke *tiling,
-                                                  gint             stroke,
-                                                  gint             paint_width,
-                                                  gint             paint_height);
-static GParamSpec ** gimp_tiling_get_settings    (GimpMultiStroke *mstroke,
-                                                  guint           *nsettings);
+static void       gimp_tiling_constructed        (GObject      *object);
+static void       gimp_tiling_finalize           (GObject      *object);
+static void       gimp_tiling_set_property       (GObject      *object,
+                                                  guint         property_id,
+                                                  const GValue *value,
+                                                  GParamSpec   *pspec);
+static void       gimp_tiling_get_property       (GObject      *object,
+                                                  guint         property_id,
+                                                  GValue       *value,
+                                                  GParamSpec   *pspec);
+
+static void       gimp_tiling_update_strokes     (GimpSymmetry *tiling,
+                                                  GimpDrawable *drawable,
+                                                  GimpCoords   *origin);
+static GeglNode * gimp_tiling_get_operation      (GimpSymmetry *tiling,
+                                                  gint          stroke,
+                                                  gint          paint_width,
+                                                  gint          paint_height);
+static GParamSpec ** gimp_tiling_get_settings    (GimpSymmetry *sym,
+                                                  guint        *nsettings);
 static void
-               gimp_tiling_image_size_changed_cb (GimpImage       *image ,
-                                                  gint             previous_origin_x,
-                                                  gint             previous_origin_y,
-                                                  gint             previous_width,
-                                                  gint             previous_height,
-                                                  GimpMultiStroke *mstroke);
+               gimp_tiling_image_size_changed_cb (GimpImage    *image ,
+                                                  gint          previous_origin_x,
+                                                  gint          previous_origin_y,
+                                                  gint          previous_width,
+                                                  gint          previous_height,
+                                                  GimpSymmetry *sym);
 
-G_DEFINE_TYPE (GimpTiling, gimp_tiling, GIMP_TYPE_MULTI_STROKE)
+G_DEFINE_TYPE (GimpTiling, gimp_tiling, GIMP_TYPE_SYMMETRY)
 
 #define parent_class gimp_tiling_parent_class
 
@@ -90,18 +89,18 @@ static void
 gimp_tiling_class_init (GimpTilingClass *klass)
 {
   GObjectClass         *object_class       = G_OBJECT_CLASS (klass);
-  GimpMultiStrokeClass *multi_stroke_class = GIMP_MULTI_STROKE_CLASS (klass);
+  GimpSymmetryClass *symmetry_class = GIMP_SYMMETRY_CLASS (klass);
 
   object_class->constructed            = gimp_tiling_constructed;
   object_class->finalize               = gimp_tiling_finalize;
   object_class->set_property           = gimp_tiling_set_property;
   object_class->get_property           = gimp_tiling_get_property;
 
-  multi_stroke_class->label            = "Tiling";
-  multi_stroke_class->update_strokes   = gimp_tiling_update_strokes;
-  multi_stroke_class->get_operation    = gimp_tiling_get_operation;
-  multi_stroke_class->get_settings     = gimp_tiling_get_settings;
-  multi_stroke_class->get_xcf_settings = gimp_tiling_get_settings;
+  symmetry_class->label            = "Tiling";
+  symmetry_class->update_strokes   = gimp_tiling_update_strokes;
+  symmetry_class->get_operation    = gimp_tiling_get_operation;
+  symmetry_class->get_settings     = gimp_tiling_get_settings;
+  symmetry_class->get_xcf_settings = gimp_tiling_get_settings;
 
   GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_X_INTERVAL,
                                    "x-interval", _("Intervals on x-axis (pixels)"),
@@ -136,10 +135,10 @@ gimp_tiling_init (GimpTiling *tiling)
 static void
 gimp_tiling_constructed (GObject *object)
 {
-  GimpMultiStroke  *mstroke;
+  GimpSymmetry     *sym;
   GParamSpecDouble *dspec;
 
-  mstroke = GIMP_MULTI_STROKE (object);
+  sym = GIMP_SYMMETRY (object);
 
   // TODO: can I have it in property and still save it in parent? Test.
   // Also connect on image changing size.
@@ -149,19 +148,19 @@ gimp_tiling_constructed (GObject *object)
   /* Update property values to actual image size. */
   dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
                                                              "x-interval"));
-  dspec->maximum = gimp_image_get_width (mstroke->image);
+  dspec->maximum = gimp_image_get_width (sym->image);
 
   dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
                                                              "shift"));
-  dspec->maximum = gimp_image_get_width (mstroke->image);
+  dspec->maximum = gimp_image_get_width (sym->image);
 
   dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (object),
                                                              "y-interval"));
-  dspec->maximum = gimp_image_get_height (mstroke->image);
+  dspec->maximum = gimp_image_get_height (sym->image);
 
-  g_signal_connect (mstroke->image, "size-changed-detailed",
+  g_signal_connect (sym->image, "size-changed-detailed",
                     G_CALLBACK (gimp_tiling_image_size_changed_cb),
-                    mstroke);
+                    sym);
 }
 
 static void
@@ -176,17 +175,17 @@ gimp_tiling_set_property (GObject      *object,
                           const GValue *value,
                           GParamSpec   *pspec)
 {
-  GimpTiling      *tiling = GIMP_TILING (object);
-  GimpMultiStroke *mstroke = GIMP_MULTI_STROKE (tiling);
+  GimpTiling   *tiling = GIMP_TILING (object);
+  GimpSymmetry *sym = GIMP_SYMMETRY (tiling);
 
   switch (property_id)
     {
     case PROP_X_INTERVAL:
-      if (mstroke->image)
+      if (sym->image)
         {
           gdouble new_x = g_value_get_double (value);
 
-          if (new_x < gimp_image_get_width (mstroke->image))
+          if (new_x < gimp_image_get_width (sym->image))
             {
               tiling->interval_x = new_x;
 
@@ -198,8 +197,8 @@ gimp_tiling_set_property (GObject      *object,
                   g_value_set_double (&val, 0.0);
                   g_object_set_property (G_OBJECT (object), "shift", &val);
                 }
-              else if (mstroke->drawable)
-                gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+              else if (sym->drawable)
+                gimp_tiling_update_strokes (sym, sym->drawable, sym->origin);
             }
         }
       break;
@@ -207,7 +206,7 @@ gimp_tiling_set_property (GObject      *object,
         {
           gdouble new_y = g_value_get_double (value);
 
-          if (new_y < gimp_image_get_height (mstroke->image))
+          if (new_y < gimp_image_get_height (sym->image))
             {
               tiling->interval_y = new_y;
 
@@ -219,8 +218,8 @@ gimp_tiling_set_property (GObject      *object,
                   g_value_set_double (&val, 0.0);
                   g_object_set_property (G_OBJECT (object), "shift", &val);
                 }
-              else if (mstroke->drawable)
-                gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+              else if (sym->drawable)
+                gimp_tiling_update_strokes (sym, sym->drawable, sym->origin);
             }
         }
       break;
@@ -232,20 +231,20 @@ gimp_tiling_set_property (GObject      *object,
               (tiling->interval_y != 0.0 && new_shift < tiling->interval_x))
             {
               tiling->shift = new_shift;
-              if (mstroke->drawable)
-                gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+              if (sym->drawable)
+                gimp_tiling_update_strokes (sym, sym->drawable, sym->origin);
             }
         }
       break;
     case PROP_X_MAX:
       tiling->max_x = g_value_get_uint (value);
-      if (mstroke->drawable)
-        gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+      if (sym->drawable)
+        gimp_tiling_update_strokes (sym, sym->drawable, sym->origin);
       break;
     case PROP_Y_MAX:
       tiling->max_y = g_value_get_uint (value);
-      if (mstroke->drawable)
-        gimp_tiling_update_strokes (mstroke, mstroke->drawable, mstroke->origin);
+      if (sym->drawable)
+        gimp_tiling_update_strokes (sym, sym->drawable, sym->origin);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -285,12 +284,12 @@ gimp_tiling_get_property (GObject    *object,
 }
 
 static void
-gimp_tiling_update_strokes (GimpMultiStroke *mstroke,
-                            GimpDrawable    *drawable,
-                            GimpCoords      *origin)
+gimp_tiling_update_strokes (GimpSymmetry *sym,
+                            GimpDrawable *drawable,
+                            GimpCoords   *origin)
 {
   GList            *strokes = NULL;
-  GimpTiling       *tiling  = GIMP_TILING (mstroke);
+  GimpTiling       *tiling  = GIMP_TILING (sym);
   GimpCoords       *coords;
   gint              width;
   gint              height;
@@ -302,10 +301,10 @@ gimp_tiling_update_strokes (GimpMultiStroke *mstroke,
   gint              y_count;
 
   g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
-  g_return_if_fail (GIMP_IS_MULTI_STROKE (mstroke));
+  g_return_if_fail (GIMP_IS_SYMMETRY (sym));
 
-  g_list_free_full (mstroke->strokes, g_free);
-  mstroke->strokes = NULL;
+  g_list_free_full (sym->strokes, g_free);
+  sym->strokes = NULL;
 
   width  = gimp_item_get_width (GIMP_ITEM (drawable));
   height = gimp_item_get_height (GIMP_ITEM (drawable));
@@ -337,73 +336,73 @@ gimp_tiling_update_strokes (GimpMultiStroke *mstroke,
       else
         startx = startx - tiling->interval_x + tiling->shift;
     }
-  mstroke->strokes = strokes;
+  sym->strokes = strokes;
 
-  g_signal_emit_by_name (mstroke, "strokes-updated", mstroke->image);
+  g_signal_emit_by_name (sym, "strokes-updated", sym->image);
 }
 
 static GeglNode *
-gimp_tiling_get_operation (GimpMultiStroke *mstroke,
-                           gint             stroke,
-                           gint             paint_width,
-                           gint             paint_height)
+gimp_tiling_get_operation (GimpSymmetry *sym,
+                           gint          stroke,
+                           gint          paint_width,
+                           gint          paint_height)
 {
   /* No buffer transformation happens for tiling. */
   return NULL;
 }
 
 static GParamSpec **
-gimp_tiling_get_settings (GimpMultiStroke *mstroke,
-                          guint           *nsettings)
+gimp_tiling_get_settings (GimpSymmetry *sym,
+                          guint        *nsettings)
 {
   GParamSpec **pspecs;
 
   *nsettings = 6;
   pspecs = g_new (GParamSpec*, 6);
 
-  pspecs[0] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[0] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "x-interval");
-  pspecs[1] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[1] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "y-interval");
-  pspecs[2] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[2] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "shift");
   pspecs[3] = NULL;
-  pspecs[4] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[4] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "x-max");
-  pspecs[5] = g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+  pspecs[5] = g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                             "y-max");
 
   return pspecs;
 }
 
 static void
-gimp_tiling_image_size_changed_cb (GimpImage       *image,
-                                   gint             previous_origin_x,
-                                   gint             previous_origin_y,
-                                   gint             previous_width,
-                                   gint             previous_height,
-                                   GimpMultiStroke *mstroke)
+gimp_tiling_image_size_changed_cb (GimpImage    *image,
+                                   gint          previous_origin_x,
+                                   gint          previous_origin_y,
+                                   gint          previous_width,
+                                   gint          previous_height,
+                                   GimpSymmetry *sym)
 {
   GParamSpecDouble *dspec;
 
   if (previous_width != gimp_image_get_width (image))
     {
-      dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+      dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                                                  "x-interval"));
-      dspec->maximum = gimp_image_get_width (mstroke->image);
+      dspec->maximum = gimp_image_get_width (sym->image);
 
-      dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+      dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                                                  "shift"));
-      dspec->maximum = gimp_image_get_width (mstroke->image);
+      dspec->maximum = gimp_image_get_width (sym->image);
     }
   if (previous_height != gimp_image_get_height (image))
     {
-      dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (mstroke),
+      dspec = G_PARAM_SPEC_DOUBLE (g_object_class_find_property (G_OBJECT_GET_CLASS (sym),
                                                                  "y-interval"));
-      dspec->maximum = gimp_image_get_height (mstroke->image);
+      dspec->maximum = gimp_image_get_height (sym->image);
     }
 
   if (previous_width != gimp_image_get_width (image) ||
       previous_height != gimp_image_get_height (image))
-    g_signal_emit_by_name (mstroke, "update-ui", mstroke->image);
+    g_signal_emit_by_name (sym, "update-ui", sym->image);
 }
diff --git a/app/paint/gimptiling.h b/app/core/gimpsymmetry-tiling.h
similarity index 86%
rename from app/paint/gimptiling.h
rename to app/core/gimpsymmetry-tiling.h
index 7f60185..15401b7 100644
--- a/app/paint/gimptiling.h
+++ b/app/core/gimpsymmetry-tiling.h
@@ -1,7 +1,7 @@
 /* GIMP - The GNU Image Manipulation Program
  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  *
- * gimptiling.h
+ * gimpsymmetry-tiling.h
  * Copyright (C) 2015 Jehan <jehan gimp org>
  * 
  * This program is free software: you can redistribute it and/or modify
@@ -22,7 +22,7 @@
 #define __GIMP_TILING_H__
 
 
-#include "gimpmultistroke.h"
+#include "gimpsymmetry.h"
 
 
 #define GIMP_TYPE_TILING            (gimp_tiling_get_type ())
@@ -36,18 +36,18 @@ typedef struct _GimpTilingClass GimpTilingClass;
 
 struct _GimpTiling
 {
-  GimpMultiStroke  parent_instance;
+  GimpSymmetry  parent_instance;
 
-  gdouble          interval_x;
-  gdouble          interval_y;
-  gdouble          shift;
-  guint            max_x;
-  guint            max_y;
+  gdouble       interval_x;
+  gdouble       interval_y;
+  gdouble       shift;
+  guint         max_x;
+  guint         max_y;
 };
 
 struct _GimpTilingClass
 {
-  GimpMultiStrokeClass  parent_class;
+  GimpSymmetryClass  parent_class;
 };
 
 GType        gimp_tiling_get_type                (void) G_GNUC_CONST;
diff --git a/app/core/gimpsymmetry.c b/app/core/gimpsymmetry.c
new file mode 100644
index 0000000..ec3feab
--- /dev/null
+++ b/app/core/gimpsymmetry.c
@@ -0,0 +1,374 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpsymmetry.c
+ * Copyright (C) 2015 Jehan <jehan gimp org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "core-types.h"
+
+#include "gimpdrawable.h"
+#include "gimpimage.h"
+#include "gimpitem.h"
+#include "gimpsymmetry.h"
+
+#include "gimp-intl.h"
+
+enum
+{
+  STROKES_UPDATED,
+  UPDATE_UI,
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_IMAGE,
+};
+
+/* Local function prototypes */
+
+static void gimp_symmetry_finalize        (GObject      *object);
+static void gimp_symmetry_set_property    (GObject      *object,
+                                           guint         property_id,
+                                           const GValue *value,
+                                           GParamSpec   *pspec);
+static void gimp_symmetry_get_property    (GObject      *object,
+                                           guint         property_id,
+                                           GValue       *value,
+                                           GParamSpec   *pspec);
+
+static void
+        gimp_symmetry_real_update_strokes (GimpSymmetry *sym,
+                                           GimpDrawable *drawable,
+                                           GimpCoords   *origin);
+static GeglNode *
+            gimp_symmetry_real_get_op     (GimpSymmetry *sym,
+                                           gint          stroke,
+                                           gint          paint_width,
+                                           gint          paint_height);
+static GParamSpec **
+          gimp_symmetry_real_get_settings (GimpSymmetry *sym,
+                                           guint        *nproperties);
+
+G_DEFINE_TYPE (GimpSymmetry, gimp_symmetry, GIMP_TYPE_OBJECT)
+
+#define parent_class gimp_symmetry_parent_class
+
+static guint gimp_symmetry_signals[LAST_SIGNAL] = { 0 };
+
+static void
+gimp_symmetry_class_init (GimpSymmetryClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  /* This signal should likely be emitted at the end of update_strokes()
+   * if stroke coordinates were changed. */
+  gimp_symmetry_signals[STROKES_UPDATED] =
+    g_signal_new ("strokes-updated",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  0,
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  1, GIMP_TYPE_IMAGE);
+  /* This signal should be emitted when you request a change in
+   * the settings UI. For instance adding some settings (therefore having a
+   * dynamic UI), or changing scale min/max extremes, etc. */
+  gimp_symmetry_signals[UPDATE_UI] =
+    g_signal_new ("update-ui",
+                  G_TYPE_FROM_CLASS (klass),
+                  G_SIGNAL_RUN_FIRST,
+                  0,
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE,
+                  1, GIMP_TYPE_IMAGE);
+
+
+  object_class->finalize     = gimp_symmetry_finalize;
+  object_class->set_property = gimp_symmetry_set_property;
+  object_class->get_property = gimp_symmetry_get_property;
+
+  klass->label               = "None";
+  klass->update_strokes      = gimp_symmetry_real_update_strokes;
+  klass->get_operation       = gimp_symmetry_real_get_op;
+  klass->get_settings        = gimp_symmetry_real_get_settings;
+  klass->get_xcf_settings    = gimp_symmetry_real_get_settings;
+
+  g_object_class_install_property (object_class, PROP_IMAGE,
+                                   g_param_spec_object ("image",
+                                                        NULL, NULL,
+                                                        GIMP_TYPE_IMAGE,
+                                                        GIMP_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY));
+}
+
+
+static void
+gimp_symmetry_init (GimpSymmetry *sym)
+{
+  sym->image    = NULL;
+  sym->drawable = NULL;
+  sym->origin   = NULL;
+  sym->strokes  = NULL;
+  sym->type     = G_TYPE_NONE;
+}
+
+static void
+gimp_symmetry_finalize (GObject *object)
+{
+  GimpSymmetry *sym = GIMP_SYMMETRY (object);
+
+  if (sym->drawable)
+    g_object_unref (sym->drawable);
+
+  g_free (sym->origin);
+  sym->origin = NULL;
+
+  g_list_free_full (sym->strokes, g_free);
+  sym->strokes = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_symmetry_set_property (GObject      *object,
+                            guint         property_id,
+                            const GValue *value,
+                            GParamSpec   *pspec)
+{
+  GimpSymmetry *sym = GIMP_SYMMETRY (object);
+
+  switch (property_id)
+    {
+    case PROP_IMAGE:
+      sym->image = g_value_get_object (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_symmetry_get_property (GObject    *object,
+                            guint       property_id,
+                            GValue     *value,
+                            GParamSpec *pspec)
+{
+  GimpSymmetry *sym = GIMP_SYMMETRY (object);
+
+  switch (property_id)
+    {
+    case PROP_IMAGE:
+      g_value_set_object (value, sym->image);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_symmetry_real_update_strokes (GimpSymmetry *sym,
+                                   GimpDrawable *drawable,
+                                   GimpCoords   *origin)
+{
+  /* The basic symmetry just uses the origin as is. */
+  sym->strokes = g_list_prepend (sym->strokes,
+                                     g_memdup (origin, sizeof (GimpCoords)));
+}
+
+static GeglNode *
+gimp_symmetry_real_get_op (GimpSymmetry *sym,
+                           gint          stroke,
+                           gint          paint_width,
+                           gint          paint_height)
+{
+  /* The basic symmetry just returns NULL, since no transformation of the
+   * brush painting happen. */
+  return NULL;
+}
+
+static GParamSpec **
+gimp_symmetry_real_get_settings (GimpSymmetry *sym,
+                                 guint        *nproperties)
+{
+  *nproperties = 0;
+
+  return NULL;
+}
+
+/***** Public Functions *****/
+
+/**
+ * gimp_symmetry_set_origin:
+ * @sym:      the #GimpSymmetry
+ * @drawable: the #GimpDrawable where painting will happen
+ * @origin:   new base coordinates.
+ *
+ * Set the symmetry to new origin coordinates and drawable.
+ **/
+void
+gimp_symmetry_set_origin (GimpSymmetry *sym,
+                          GimpDrawable *drawable,
+                          GimpCoords   *origin)
+{
+  g_return_if_fail (GIMP_IS_SYMMETRY (sym));
+  g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
+  g_return_if_fail (gimp_item_get_image (GIMP_ITEM (drawable)) == sym->image);
+
+  if (drawable != sym->drawable)
+    {
+      if (sym->drawable)
+        g_object_unref (sym->drawable);
+      sym->drawable = g_object_ref (drawable);
+    }
+
+  if (origin != sym->origin)
+    {
+      g_free (sym->origin);
+      sym->origin = g_memdup (origin, sizeof (GimpCoords));
+    }
+
+  g_list_free_full (sym->strokes, g_free);
+  sym->strokes = NULL;
+
+  GIMP_SYMMETRY_GET_CLASS (sym)->update_strokes (sym,
+                                                 drawable,
+                                                 origin);
+}
+
+/**
+ * gimp_symmetry_get_origin:
+ * @sym: the #GimpSymmetry
+ *
+ * Returns the origin stroke coordinates.
+ * The returned value is owned by the #GimpSymmetry and must not be freed.
+ **/
+GimpCoords *
+gimp_symmetry_get_origin (GimpSymmetry *sym)
+{
+  g_return_val_if_fail (GIMP_IS_SYMMETRY (sym), NULL);
+
+  return sym->origin;
+}
+
+/**
+ * gimp_symmetry_get_size:
+ * @sym: the #GimpSymmetry
+ *
+ * Returns the total number of strokes.
+ **/
+gint
+gimp_symmetry_get_size (GimpSymmetry *sym)
+{
+  g_return_val_if_fail (GIMP_IS_SYMMETRY (sym), 0);
+
+  return g_list_length (sym->strokes);
+}
+
+/**
+ * gimp_symmetry_get_coords:
+ * @sym:    the #GimpSymmetry
+ * @stroke: the stroke number
+ *
+ * Returns the coordinates of the stroke number @stroke.
+ * The returned value is owned by the #GimpSymmetry and must not be freed.
+ **/
+GimpCoords *
+gimp_symmetry_get_coords (GimpSymmetry *sym,
+                          gint          stroke)
+{
+  g_return_val_if_fail (GIMP_IS_SYMMETRY (sym), NULL);
+
+  return g_list_nth_data (sym->strokes, stroke);
+}
+
+/**
+ * gimp_symmetry_get_operation:
+ * @sym:          the #GimpSymmetry
+ * @stroke:       the stroke number
+ * @paint_width:  the width of the painting area
+ * @paint_height: the height of the painting area
+ *
+ * Returns the operation to apply to the paint buffer for stroke number @stroke.
+ * NULL means to copy the original stroke as-is.
+ **/
+GeglNode *
+gimp_symmetry_get_operation (GimpSymmetry *sym,
+                             gint          stroke,
+                             gint          paint_width,
+                             gint          paint_height)
+{
+  g_return_val_if_fail (GIMP_IS_SYMMETRY (sym), NULL);
+
+  return GIMP_SYMMETRY_GET_CLASS (sym)->get_operation (sym,
+                                                       stroke,
+                                                       paint_width,
+                                                       paint_height);
+}
+
+/**
+ * gimp_symmetry_get_settings:
+ * @sym:     the #GimpSymmetry
+ * @nproperties: the number of properties in the returned array
+ *
+ * Returns an array of the symmetry properties which are supposed to
+ * be settable by the user.
+ * The returned array must be freed by the caller.
+ **/
+GParamSpec **
+gimp_symmetry_get_settings (GimpSymmetry *sym,
+                            guint        *nproperties)
+{
+  g_return_val_if_fail (GIMP_IS_SYMMETRY (sym), NULL);
+
+  return GIMP_SYMMETRY_GET_CLASS (sym)->get_settings (sym,
+                                                      nproperties);
+}
+
+/**
+ * gimp_symmetry_get_xcf_settings:
+ * @sym:         the #GimpSymmetry
+ * @nproperties: the number of properties in the returned array
+ *
+ * Returns an array of the symmetry properties which are to be serialized
+ * when saving to XCF.
+ * These properties may be different to `gimp_symmetry_get_settings()`
+ * (for instance some properties are not meant to be user-changeable but
+ * still saved)
+ * The returned array must be freed by the caller.
+ **/
+GParamSpec **
+gimp_symmetry_get_xcf_settings (GimpSymmetry *sym,
+                                guint        *nproperties)
+{
+  g_return_val_if_fail (GIMP_IS_SYMMETRY (sym), NULL);
+
+  return GIMP_SYMMETRY_GET_CLASS (sym)->get_xcf_settings (sym,
+                                                          nproperties);
+}
diff --git a/app/core/gimpsymmetry.h b/app/core/gimpsymmetry.h
new file mode 100644
index 0000000..d702126
--- /dev/null
+++ b/app/core/gimpsymmetry.h
@@ -0,0 +1,92 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpsymmetry.h
+ * Copyright (C) 2015 Jehan <jehan gimp org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_SYMMETRY_H__
+#define __GIMP_SYMMETRY_H__
+
+
+#include "gimpobject.h"
+
+
+#define GIMP_TYPE_SYMMETRY            (gimp_symmetry_get_type ())
+#define GIMP_SYMMETRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_SYMMETRY, GimpSymmetry))
+#define GIMP_SYMMETRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_SYMMETRY, 
GimpSymmetryClass))
+#define GIMP_IS_SYMMETRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_SYMMETRY))
+#define GIMP_IS_SYMMETRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_SYMMETRY))
+#define GIMP_SYMMETRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_SYMMETRY, 
GimpSymmetryClass))
+
+typedef struct _GimpSymmetryClass   GimpSymmetryClass;
+
+struct _GimpSymmetry
+{
+  GimpObject    parent_instance;
+
+  GimpImage    *image;
+  GimpDrawable *drawable;
+  GimpCoords   *origin;
+
+  GList        *strokes;
+
+  GType         type;
+};
+
+struct _GimpSymmetryClass
+{
+  GimpObjectClass  parent_class;
+
+  const gchar * label;
+
+  /* Virtual functions */
+  void       (* update_strokes)             (GimpSymmetry *sym,
+                                             GimpDrawable *drawable,
+                                             GimpCoords   *origin);
+  GeglNode * (* get_operation)              (GimpSymmetry *sym,
+                                             gint          stroke,
+                                             gint          paint_width,
+                                             gint          paint_height);
+  GParamSpec **
+             (* get_settings)               (GimpSymmetry *sym,
+                                             guint        *nproperties);
+  GParamSpec **
+             (* get_xcf_settings)           (GimpSymmetry *sym,
+                                             guint        *nproperties);
+};
+
+
+GType        gimp_symmetry_get_type         (void) G_GNUC_CONST;
+
+void         gimp_symmetry_set_origin       (GimpSymmetry *sym,
+                                             GimpDrawable *drawable,
+                                             GimpCoords   *origin);
+
+GimpCoords * gimp_symmetry_get_origin       (GimpSymmetry *sym);
+gint         gimp_symmetry_get_size         (GimpSymmetry *sym);
+GimpCoords * gimp_symmetry_get_coords       (GimpSymmetry *sym,
+                                             gint          stroke);
+GeglNode   * gimp_symmetry_get_operation    (GimpSymmetry *sym,
+                                             gint          stroke,
+                                             gint          paint_width,
+                                             gint          paint_height);
+GParamSpec ** gimp_symmetry_get_settings     (GimpSymmetry *sym,
+                                              guint        *nproperties);
+GParamSpec ** gimp_symmetry_get_xcf_settings (GimpSymmetry *sym,
+                                              guint        *nproperties);
+
+#endif  /*  __GIMP_SYMMETRY_H__  */
diff --git a/app/dialogs/preferences-dialog.c b/app/dialogs/preferences-dialog.c
index 3e55f14..1062d00 100644
--- a/app/dialogs/preferences-dialog.c
+++ b/app/dialogs/preferences-dialog.c
@@ -1556,8 +1556,8 @@ prefs_dialog_new (Gimp       *gimp,
       button = prefs_check_button_add (object, "playground-seamless-clone-tool",
                                        _("_Seamless Clone tool"),
                                        GTK_BOX (vbox2));
-      button = prefs_check_button_add (object, "playground-multi-stroke",
-                                       _("_Multi-Stroke Painting"),
+      button = prefs_check_button_add (object, "playground-symmetry",
+                                       _("_Symmetry Painting"),
                                        GTK_BOX (vbox2));
     }
 
diff --git a/app/paint/Makefile.am b/app/paint/Makefile.am
index 7b7bd98..22e4b25 100644
--- a/app/paint/Makefile.am
+++ b/app/paint/Makefile.am
@@ -52,12 +52,6 @@ libapppaint_a_sources = \
        gimpinkoptions.h                \
        gimpinkundo.c                   \
        gimpinkundo.h                   \
-       gimpmirror.c                    \
-       gimpmirror.h                    \
-       gimpmultistroke.c                       \
-       gimpmultistroke.h                       \
-       gimpmultistroke-info.c                  \
-       gimpmultistroke-info.h                  \
        gimpmybrush.c                   \
        gimpmybrush.h                   \
        gimpmybrushoptions.c            \
@@ -89,9 +83,7 @@ libapppaint_a_sources = \
        gimpsourcecore.c                \
        gimpsourcecore.h                \
        gimpsourceoptions.c             \
-       gimpsourceoptions.h             \
-       gimptiling.c                    \
-       gimptiling.h
+       gimpsourceoptions.h
 
 libapppaint_a_built_sources = paint-enums.c
 
diff --git a/app/paint/gimpairbrush.c b/app/paint/gimpairbrush.c
index 4c0fdfc..29dcc85 100644
--- a/app/paint/gimpairbrush.c
+++ b/app/paint/gimpairbrush.c
@@ -28,8 +28,7 @@
 #include "core/gimpdynamics.h"
 #include "core/gimpgradient.h"
 #include "core/gimpimage.h"
-
-#include "gimpmultistroke.h"
+#include "core/gimpsymmetry.h"
 
 #include "gimpairbrush.h"
 #include "gimpairbrushoptions.h"
@@ -42,13 +41,13 @@ static void       gimp_airbrush_finalize (GObject          *object);
 static void       gimp_airbrush_paint    (GimpPaintCore    *paint_core,
                                           GimpDrawable     *drawable,
                                           GimpPaintOptions *paint_options,
-                                          GimpMultiStroke  *mstroke,
+                                          GimpSymmetry     *sym,
                                           GimpPaintState    paint_state,
                                           guint32           time);
 static void       gimp_airbrush_motion   (GimpPaintCore    *paint_core,
                                           GimpDrawable     *drawable,
                                           GimpPaintOptions *paint_options,
-                                          GimpMultiStroke  *mstroke);
+                                          GimpSymmetry     *sym);
 static gboolean   gimp_airbrush_timeout  (gpointer          data);
 
 
@@ -84,7 +83,7 @@ static void
 gimp_airbrush_init (GimpAirbrush *airbrush)
 {
   airbrush->timeout_id = 0;
-  airbrush->mstroke    = NULL;
+  airbrush->sym    = NULL;
 }
 
 static void
@@ -98,8 +97,8 @@ gimp_airbrush_finalize (GObject *object)
       airbrush->timeout_id = 0;
     }
 
-  if (airbrush->mstroke)
-    g_object_unref (airbrush->mstroke);
+  if (airbrush->sym)
+    g_object_unref (airbrush->sym);
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -108,7 +107,7 @@ static void
 gimp_airbrush_paint (GimpPaintCore    *paint_core,
                      GimpDrawable     *drawable,
                      GimpPaintOptions *paint_options,
-                     GimpMultiStroke  *mstroke,
+                     GimpSymmetry     *sym,
                      GimpPaintState    paint_state,
                      guint32           time)
 {
@@ -127,7 +126,7 @@ gimp_airbrush_paint (GimpPaintCore    *paint_core,
 
       GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable,
                                                    paint_options,
-                                                   mstroke,
+                                                   sym,
                                                    paint_state, time);
       break;
 
@@ -138,7 +137,7 @@ gimp_airbrush_paint (GimpPaintCore    *paint_core,
           airbrush->timeout_id = 0;
         }
 
-      gimp_airbrush_motion (paint_core, drawable, paint_options, mstroke);
+      gimp_airbrush_motion (paint_core, drawable, paint_options, sym);
 
       if ((options->rate != 0.0) && (!options->motion_only))
         {
@@ -154,12 +153,12 @@ gimp_airbrush_paint (GimpPaintCore    *paint_core,
           airbrush->drawable      = drawable;
           airbrush->paint_options = paint_options;
 
-          if (airbrush->mstroke)
-            g_object_unref (airbrush->mstroke);
-          airbrush->mstroke = g_object_ref (mstroke);
+          if (airbrush->sym)
+            g_object_unref (airbrush->sym);
+          airbrush->sym = g_object_ref (sym);
 
           /* Base our timeout on the original stroke. */
-          coords = gimp_multi_stroke_get_origin (mstroke);
+          coords = gimp_symmetry_get_origin (sym);
 
           dynamic_rate = gimp_dynamics_get_linear_value (dynamics,
                                                          GIMP_DYNAMICS_OUTPUT_RATE,
@@ -184,7 +183,7 @@ gimp_airbrush_paint (GimpPaintCore    *paint_core,
 
       GIMP_PAINT_CORE_CLASS (parent_class)->paint (paint_core, drawable,
                                                    paint_options,
-                                                   mstroke,
+                                                   sym,
                                                    paint_state, time);
       break;
     }
@@ -194,7 +193,7 @@ static void
 gimp_airbrush_motion (GimpPaintCore    *paint_core,
                       GimpDrawable     *drawable,
                       GimpPaintOptions *paint_options,
-                      GimpMultiStroke  *mstroke)
+                      GimpSymmetry     *sym)
 
 {
   GimpAirbrushOptions *options  = GIMP_AIRBRUSH_OPTIONS (paint_options);
@@ -207,7 +206,7 @@ gimp_airbrush_motion (GimpPaintCore    *paint_core,
   fade_point = gimp_paint_options_get_fade (paint_options, image,
                                             paint_core->pixel_dist);
 
-  coords = gimp_multi_stroke_get_origin (mstroke);
+  coords = gimp_symmetry_get_origin (sym);
 
   opacity = (options->flow / 100.0 *
              gimp_dynamics_get_linear_value (dynamics,
@@ -217,7 +216,7 @@ gimp_airbrush_motion (GimpPaintCore    *paint_core,
                                              fade_point));
 
   _gimp_paintbrush_motion (paint_core, drawable, paint_options,
-                           mstroke, opacity);
+                           sym, opacity);
 }
 
 static gboolean
@@ -228,7 +227,7 @@ gimp_airbrush_timeout (gpointer data)
   gimp_airbrush_paint (GIMP_PAINT_CORE (airbrush),
                        airbrush->drawable,
                        airbrush->paint_options,
-                       airbrush->mstroke,
+                       airbrush->sym,
                        GIMP_PAINT_STATE_MOTION, 0);
 
   gimp_image_flush (gimp_item_get_image (GIMP_ITEM (airbrush->drawable)));
diff --git a/app/paint/gimpairbrush.h b/app/paint/gimpairbrush.h
index c97910c..a3f9a8a 100644
--- a/app/paint/gimpairbrush.h
+++ b/app/paint/gimpairbrush.h
@@ -38,7 +38,7 @@ struct _GimpAirbrush
 
   guint             timeout_id;
 
-  GimpMultiStroke  *mstroke;
+  GimpSymmetry     *sym;
   GimpDrawable     *drawable;
   GimpPaintOptions *paint_options;
 };
diff --git a/app/paint/gimpclone.c b/app/paint/gimpclone.c
index 3380f17..ec54fac 100644
--- a/app/paint/gimpclone.c
+++ b/app/paint/gimpclone.c
@@ -34,10 +34,10 @@
 #include "core/gimpimage.h"
 #include "core/gimppattern.h"
 #include "core/gimppickable.h"
+#include "core/gimpsymmetry.h"
 
 #include "gimpclone.h"
 #include "gimpcloneoptions.h"
-#include "gimpmultistroke.h"
 
 #include "gimp-intl.h"
 
diff --git a/app/paint/gimpconvolve.c b/app/paint/gimpconvolve.c
index 6839ff5..b6d7d2e 100644
--- a/app/paint/gimpconvolve.c
+++ b/app/paint/gimpconvolve.c
@@ -30,10 +30,9 @@
 #include "core/gimpdynamics.h"
 #include "core/gimpimage.h"
 #include "core/gimppickable.h"
+#include "core/gimpsymmetry.h"
 #include "core/gimptempbuf.h"
 
-#include "gimpmultistroke.h"
-
 #include "gimpconvolve.h"
 #include "gimpconvolveoptions.h"
 
@@ -50,13 +49,13 @@
 static void    gimp_convolve_paint            (GimpPaintCore    *paint_core,
                                                GimpDrawable     *drawable,
                                                GimpPaintOptions *paint_options,
-                                               GimpMultiStroke  *mstroke,
+                                               GimpSymmetry     *sym,
                                                GimpPaintState    paint_state,
                                                guint32           time);
 static void    gimp_convolve_motion           (GimpPaintCore    *paint_core,
                                                GimpDrawable     *drawable,
                                                GimpPaintOptions *paint_options,
-                                               GimpMultiStroke  *mstroke);
+                                               GimpSymmetry     *sym);
 
 static void    gimp_convolve_calculate_matrix (GimpConvolve     *convolve,
                                                GimpConvolveType  type,
@@ -104,7 +103,7 @@ static void
 gimp_convolve_paint (GimpPaintCore    *paint_core,
                      GimpDrawable     *drawable,
                      GimpPaintOptions *paint_options,
-                     GimpMultiStroke  *mstroke,
+                     GimpSymmetry     *sym,
                      GimpPaintState    paint_state,
                      guint32           time)
 {
@@ -112,7 +111,7 @@ gimp_convolve_paint (GimpPaintCore    *paint_core,
     {
     case GIMP_PAINT_STATE_MOTION:
       gimp_convolve_motion (paint_core, drawable, paint_options,
-                            mstroke);
+                            sym);
       break;
 
     default:
@@ -124,7 +123,7 @@ static void
 gimp_convolve_motion (GimpPaintCore    *paint_core,
                       GimpDrawable     *drawable,
                       GimpPaintOptions *paint_options,
-                      GimpMultiStroke  *mstroke)
+                      GimpSymmetry     *sym)
 {
   GimpConvolve        *convolve   = GIMP_CONVOLVE (paint_core);
   GimpBrushCore       *brush_core = GIMP_BRUSH_CORE (paint_core);
@@ -146,13 +145,13 @@ gimp_convolve_motion (GimpPaintCore    *paint_core,
   gint                 nstrokes;
   gint                 i;
 
-  nstrokes = gimp_multi_stroke_get_size (mstroke);
+  nstrokes = gimp_symmetry_get_size (sym);
   fade_point = gimp_paint_options_get_fade (paint_options, image,
                                             paint_core->pixel_dist);
 
   for (i = 0; i < nstrokes; i++)
     {
-      coords = gimp_multi_stroke_get_coords (mstroke, i);
+      coords = gimp_symmetry_get_coords (sym, i);
 
       opacity = gimp_dynamics_get_linear_value (dynamics,
                                                 GIMP_DYNAMICS_OUTPUT_OPACITY,
@@ -171,9 +170,9 @@ gimp_convolve_motion (GimpPaintCore    *paint_core,
       if (! paint_buffer)
         continue;
 
-      op = gimp_multi_stroke_get_operation (mstroke, i,
-                                            paint_width,
-                                            paint_height);
+      op = gimp_symmetry_get_operation (sym, i,
+                                        paint_width,
+                                        paint_height);
 
       rate = (options->rate *
               gimp_dynamics_get_linear_value (dynamics,
diff --git a/app/paint/gimpdodgeburn.c b/app/paint/gimpdodgeburn.c
index 35b1f80..092d94d 100644
--- a/app/paint/gimpdodgeburn.c
+++ b/app/paint/gimpdodgeburn.c
@@ -31,8 +31,7 @@
 #include "core/gimpdrawable.h"
 #include "core/gimpdynamics.h"
 #include "core/gimpimage.h"
-
-#include "gimpmultistroke.h"
+#include "core/gimpsymmetry.h"
 
 #include "gimpdodgeburn.h"
 #include "gimpdodgeburnoptions.h"
@@ -43,13 +42,13 @@
 static void   gimp_dodge_burn_paint  (GimpPaintCore    *paint_core,
                                       GimpDrawable     *drawable,
                                       GimpPaintOptions *paint_options,
-                                      GimpMultiStroke  *mstroke,
+                                      GimpSymmetry     *sym,
                                       GimpPaintState    paint_state,
                                       guint32           time);
 static void   gimp_dodge_burn_motion (GimpPaintCore    *paint_core,
                                       GimpDrawable     *drawable,
                                       GimpPaintOptions *paint_options,
-                                      GimpMultiStroke  *mstroke);
+                                      GimpSymmetry     *sym);
 
 
 G_DEFINE_TYPE (GimpDodgeBurn, gimp_dodge_burn, GIMP_TYPE_BRUSH_CORE)
@@ -89,7 +88,7 @@ static void
 gimp_dodge_burn_paint (GimpPaintCore    *paint_core,
                        GimpDrawable     *drawable,
                        GimpPaintOptions *paint_options,
-                       GimpMultiStroke  *mstroke,
+                       GimpSymmetry     *sym,
                        GimpPaintState    paint_state,
                        guint32           time)
 {
@@ -99,7 +98,7 @@ gimp_dodge_burn_paint (GimpPaintCore    *paint_core,
       break;
 
     case GIMP_PAINT_STATE_MOTION:
-      gimp_dodge_burn_motion (paint_core, drawable, paint_options, mstroke);
+      gimp_dodge_burn_motion (paint_core, drawable, paint_options, sym);
       break;
 
     case GIMP_PAINT_STATE_FINISH:
@@ -111,7 +110,7 @@ static void
 gimp_dodge_burn_motion (GimpPaintCore    *paint_core,
                         GimpDrawable     *drawable,
                         GimpPaintOptions *paint_options,
-                        GimpMultiStroke  *mstroke)
+                        GimpSymmetry     *sym)
 {
   GimpDodgeBurnOptions *options   = GIMP_DODGE_BURN_OPTIONS (paint_options);
   GimpContext          *context   = GIMP_CONTEXT (paint_options);
@@ -129,10 +128,10 @@ gimp_dodge_burn_motion (GimpPaintCore    *paint_core,
   gint                  nstrokes;
   gint                  i;
 
-  nstrokes = gimp_multi_stroke_get_size (mstroke);
+  nstrokes = gimp_symmetry_get_size (sym);
   for (i = 0; i < nstrokes; i++)
     {
-      coords = gimp_multi_stroke_get_coords (mstroke, i);
+      coords = gimp_symmetry_get_coords (sym, i);
 
       fade_point = gimp_paint_options_get_fade (paint_options, image,
                                                 paint_core->pixel_dist);
@@ -154,9 +153,9 @@ gimp_dodge_burn_motion (GimpPaintCore    *paint_core,
       if (! paint_buffer)
         continue;
 
-      op = gimp_multi_stroke_get_operation (mstroke, i,
-                                            paint_width,
-                                            paint_height);
+      op = gimp_symmetry_get_operation (sym, i,
+                                        paint_width,
+                                        paint_height);
 
       /*  DodgeBurn the region  */
       gimp_gegl_dodgeburn (gimp_paint_core_get_orig_image (paint_core),
diff --git a/app/paint/gimperaser.c b/app/paint/gimperaser.c
index d8c8387..65206c6 100644
--- a/app/paint/gimperaser.c
+++ b/app/paint/gimperaser.c
@@ -29,8 +29,7 @@
 #include "core/gimpdrawable.h"
 #include "core/gimpdynamics.h"
 #include "core/gimpimage.h"
-
-#include "gimpmultistroke.h"
+#include "core/gimpsymmetry.h"
 
 #include "gimperaser.h"
 #include "gimperaseroptions.h"
@@ -41,13 +40,13 @@
 static void   gimp_eraser_paint  (GimpPaintCore    *paint_core,
                                   GimpDrawable     *drawable,
                                   GimpPaintOptions *paint_options,
-                                  GimpMultiStroke  *mstroke,
+                                  GimpSymmetry     *sym,
                                   GimpPaintState    paint_state,
                                   guint32           time);
 static void   gimp_eraser_motion (GimpPaintCore    *paint_core,
                                   GimpDrawable     *drawable,
                                   GimpPaintOptions *paint_options,
-                                  GimpMultiStroke  *mstroke);
+                                  GimpSymmetry     *sym);
 
 
 G_DEFINE_TYPE (GimpEraser, gimp_eraser, GIMP_TYPE_BRUSH_CORE)
@@ -85,7 +84,7 @@ static void
 gimp_eraser_paint (GimpPaintCore    *paint_core,
                    GimpDrawable     *drawable,
                    GimpPaintOptions *paint_options,
-                   GimpMultiStroke  *mstroke,
+                   GimpSymmetry     *sym,
                    GimpPaintState    paint_state,
                    guint32           time)
 {
@@ -108,7 +107,7 @@ gimp_eraser_paint (GimpPaintCore    *paint_core,
         }
       break;
     case GIMP_PAINT_STATE_MOTION:
-      gimp_eraser_motion (paint_core, drawable, paint_options, mstroke);
+      gimp_eraser_motion (paint_core, drawable, paint_options, sym);
       break;
 
     default:
@@ -120,7 +119,7 @@ static void
 gimp_eraser_motion (GimpPaintCore    *paint_core,
                     GimpDrawable     *drawable,
                     GimpPaintOptions *paint_options,
-                    GimpMultiStroke  *mstroke)
+                    GimpSymmetry     *sym)
 {
   GimpEraserOptions    *options  = GIMP_ERASER_OPTIONS (paint_options);
   GimpContext          *context  = GIMP_CONTEXT (paint_options);
@@ -154,20 +153,20 @@ gimp_eraser_motion (GimpPaintCore    *paint_core,
   else
     paint_mode = GIMP_NORMAL_MODE;
 
-  if (gimp_dynamics_is_output_enabled (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE))
-    force = gimp_dynamics_get_linear_value (dynamics,
-                                            GIMP_DYNAMICS_OUTPUT_FORCE,
-                                            coords,
-                                            paint_options,
-                                            fade_point);
-  else
-    force = paint_options->brush_force;
-
-  nstrokes = gimp_multi_stroke_get_size (mstroke);
+  nstrokes = gimp_symmetry_get_size (sym);
 
   for (i = 0; i < nstrokes; i++)
     {
-      coords = gimp_multi_stroke_get_coords (mstroke, i);
+      coords = gimp_symmetry_get_coords (sym, i);
+
+      if (gimp_dynamics_is_output_enabled (dynamics, GIMP_DYNAMICS_OUTPUT_FORCE))
+        force = gimp_dynamics_get_linear_value (dynamics,
+                                                GIMP_DYNAMICS_OUTPUT_FORCE,
+                                                coords,
+                                                paint_options,
+                                                fade_point);
+      else
+        force = paint_options->brush_force;
 
       opacity = gimp_dynamics_get_linear_value (dynamics,
                                                 GIMP_DYNAMICS_OUTPUT_OPACITY,
@@ -186,7 +185,7 @@ gimp_eraser_motion (GimpPaintCore    *paint_core,
       if (! paint_buffer)
         continue;
 
-      op = gimp_multi_stroke_get_operation (mstroke, i,
+      op = gimp_symmetry_get_operation (sym, i,
                                             paint_width,
                                             paint_height);
 
diff --git a/app/paint/gimpink.c b/app/paint/gimpink.c
index 88ac3e3..52da0b0 100644
--- a/app/paint/gimpink.c
+++ b/app/paint/gimpink.c
@@ -32,10 +32,9 @@
 #include "core/gimpdrawable.h"
 #include "core/gimpimage.h"
 #include "core/gimpimage-undo.h"
+#include "core/gimpsymmetry.h"
 #include "core/gimptempbuf.h"
 
-#include "gimpmultistroke.h"
-
 #include "gimpinkoptions.h"
 #include "gimpink.h"
 #include "gimpink-blob.h"
@@ -54,7 +53,7 @@ static void         gimp_ink_finalize         (GObject          *object);
 static void         gimp_ink_paint            (GimpPaintCore    *paint_core,
                                                GimpDrawable     *drawable,
                                                GimpPaintOptions *paint_options,
-                                               GimpMultiStroke  *mstroke,
+                                               GimpSymmetry     *sym,
                                                GimpPaintState    paint_state,
                                                guint32           time);
 static GeglBuffer * gimp_ink_get_paint_buffer (GimpPaintCore    *paint_core,
@@ -72,7 +71,7 @@ static GimpUndo   * gimp_ink_push_undo        (GimpPaintCore    *core,
 static void         gimp_ink_motion           (GimpPaintCore    *paint_core,
                                                GimpDrawable     *drawable,
                                                GimpPaintOptions *paint_options,
-                                               GimpMultiStroke  *mstroke,
+                                               GimpSymmetry     *sym,
                                                guint32           time);
 
 static GimpBlob   * ink_pen_ellipse           (GimpInkOptions   *options,
@@ -147,7 +146,7 @@ static void
 gimp_ink_paint (GimpPaintCore    *paint_core,
                 GimpDrawable     *drawable,
                 GimpPaintOptions *paint_options,
-                GimpMultiStroke  *mstroke,
+                GimpSymmetry     *sym,
                 GimpPaintState    paint_state,
                 guint32           time)
 {
@@ -156,7 +155,7 @@ gimp_ink_paint (GimpPaintCore    *paint_core,
   GimpCoords  last_coords;
 
   gimp_paint_core_get_last_coords (paint_core, &last_coords);
-  cur_coords = gimp_multi_stroke_get_origin (mstroke);
+  cur_coords = gimp_symmetry_get_origin (sym);
 
   switch (paint_state)
     {
@@ -211,7 +210,7 @@ gimp_ink_paint (GimpPaintCore    *paint_core,
 
     case GIMP_PAINT_STATE_MOTION:
       gimp_ink_motion (paint_core, drawable, paint_options,
-                       mstroke, time);
+                       sym, time);
       break;
 
     case GIMP_PAINT_STATE_FINISH:
@@ -296,7 +295,7 @@ static void
 gimp_ink_motion (GimpPaintCore    *paint_core,
                  GimpDrawable     *drawable,
                  GimpPaintOptions *paint_options,
-                 GimpMultiStroke  *mstroke,
+                 GimpSymmetry     *sym,
                  guint32           time)
 {
   GimpInk        *ink             = GIMP_INK (paint_core);
@@ -314,7 +313,7 @@ gimp_ink_motion (GimpPaintCore    *paint_core,
   gint            nstrokes;
   gint            i;
 
-  nstrokes = gimp_multi_stroke_get_size (mstroke);
+  nstrokes = gimp_symmetry_get_size (sym);
 
   if (ink->last_blobs &&
       g_list_length (ink->last_blobs) != nstrokes)
@@ -333,7 +332,7 @@ gimp_ink_motion (GimpPaintCore    *paint_core,
 
       for (i = 0; i < nstrokes; i++)
         {
-          coords = gimp_multi_stroke_get_coords (mstroke, i);
+          coords = gimp_symmetry_get_coords (sym, i);
 
           last_blob = ink_pen_ellipse (options,
                                        coords->x,
@@ -360,7 +359,7 @@ gimp_ink_motion (GimpPaintCore    *paint_core,
           GimpBlob *blob;
           GimpBlob *blob_union = NULL;
 
-          coords = gimp_multi_stroke_get_coords (mstroke, i);
+          coords = gimp_symmetry_get_coords (sym, i);
           blob = ink_pen_ellipse (options,
                                   coords->x,
                                   coords->y,
@@ -386,7 +385,7 @@ gimp_ink_motion (GimpPaintCore    *paint_core,
     {
       GimpBlob *blob_to_render = g_list_nth_data (blobs_to_render, i);
 
-      coords = gimp_multi_stroke_get_coords (mstroke, i);
+      coords = gimp_symmetry_get_coords (sym, i);
 
       ink->cur_blob = blob_to_render;
       paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable,
diff --git a/app/paint/gimppaintbrush.c b/app/paint/gimppaintbrush.c
index 10e2a83..1f3cd30 100644
--- a/app/paint/gimppaintbrush.c
+++ b/app/paint/gimppaintbrush.c
@@ -36,10 +36,9 @@
 #include "core/gimpdynamics.h"
 #include "core/gimpgradient.h"
 #include "core/gimpimage.h"
+#include "core/gimpsymmetry.h"
 #include "core/gimptempbuf.h"
 
-#include "gimpmultistroke.h"
-
 #include "gimppaintbrush.h"
 #include "gimppaintoptions.h"
 
@@ -49,7 +48,7 @@
 static void   gimp_paintbrush_paint (GimpPaintCore    *paint_core,
                                      GimpDrawable     *drawable,
                                      GimpPaintOptions *paint_options,
-                                     GimpMultiStroke  *mstroke,
+                                     GimpSymmetry     *sym,
                                      GimpPaintState    paint_state,
                                      guint32           time);
 
@@ -89,7 +88,7 @@ static void
 gimp_paintbrush_paint (GimpPaintCore    *paint_core,
                        GimpDrawable     *drawable,
                        GimpPaintOptions *paint_options,
-                       GimpMultiStroke  *mstroke,
+                       GimpSymmetry     *sym,
                        GimpPaintState    paint_state,
                        guint32           time)
 {
@@ -119,7 +118,7 @@ gimp_paintbrush_paint (GimpPaintCore    *paint_core,
       break;
     case GIMP_PAINT_STATE_MOTION:
       _gimp_paintbrush_motion (paint_core, drawable, paint_options,
-                               mstroke, GIMP_OPACITY_OPAQUE);
+                               sym, GIMP_OPACITY_OPAQUE);
       break;
 
     default:
@@ -131,7 +130,7 @@ void
 _gimp_paintbrush_motion (GimpPaintCore    *paint_core,
                          GimpDrawable     *drawable,
                          GimpPaintOptions *paint_options,
-                         GimpMultiStroke  *mstroke,
+                         GimpSymmetry     *sym,
                          gdouble           opacity)
 {
   GimpBrushCore            *brush_core = GIMP_BRUSH_CORE (paint_core);
@@ -153,12 +152,12 @@ _gimp_paintbrush_motion (GimpPaintCore    *paint_core,
 
   image = gimp_item_get_image (GIMP_ITEM (drawable));
 
-  nstrokes = gimp_multi_stroke_get_size (mstroke);
+  nstrokes = gimp_symmetry_get_size (sym);
 
   fade_point = gimp_paint_options_get_fade (paint_options, image,
                                             paint_core->pixel_dist);
 
-  coords = gimp_multi_stroke_get_origin (mstroke);
+  coords = gimp_symmetry_get_origin (sym);
   /* Some settings are based on the original stroke. */
   opacity *= gimp_dynamics_get_linear_value (dynamics,
                                              GIMP_DYNAMICS_OUTPUT_OPACITY,
@@ -180,7 +179,7 @@ _gimp_paintbrush_motion (GimpPaintCore    *paint_core,
     {
       gint paint_width, paint_height;
 
-      coords = gimp_multi_stroke_get_coords (mstroke, i);
+      coords = gimp_symmetry_get_coords (sym, i);
 
       paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable,
                                                        paint_options, coords,
@@ -191,9 +190,9 @@ _gimp_paintbrush_motion (GimpPaintCore    *paint_core,
       if (! paint_buffer)
         continue;
 
-      op = gimp_multi_stroke_get_operation (mstroke, i,
-                                            paint_width,
-                                            paint_height);
+      op = gimp_symmetry_get_operation (sym, i,
+                                        paint_width,
+                                        paint_height);
       if (gimp_paint_options_get_gradient_color (paint_options, image,
                                                  grad_point,
                                                  paint_core->pixel_dist,
diff --git a/app/paint/gimppaintbrush.h b/app/paint/gimppaintbrush.h
index fe3f571..e60c590 100644
--- a/app/paint/gimppaintbrush.h
+++ b/app/paint/gimppaintbrush.h
@@ -54,7 +54,7 @@ GType   gimp_paintbrush_get_type (void) G_GNUC_CONST;
 void    _gimp_paintbrush_motion  (GimpPaintCore             *paint_core,
                                   GimpDrawable              *drawable,
                                   GimpPaintOptions          *paint_options,
-                                  GimpMultiStroke           *mstroke,
+                                  GimpSymmetry              *sym,
                                   gdouble                    opacity);
 
 
diff --git a/app/paint/gimppaintcore.c b/app/paint/gimppaintcore.c
index fde644e..fab9736 100644
--- a/app/paint/gimppaintcore.c
+++ b/app/paint/gimppaintcore.c
@@ -38,13 +38,13 @@
 #include "core/gimpchannel.h"
 #include "core/gimpimage.h"
 #include "core/gimpimage-guides.h"
+#include "core/gimpimage-symmetry.h"
 #include "core/gimpimage-undo.h"
 #include "core/gimppickable.h"
 #include "core/gimpprojection.h"
+#include "core/gimpsymmetry.h"
 #include "core/gimptempbuf.h"
 
-#include "gimpmultistroke.h"
-#include "gimpmultistroke-info.h"
 #include "gimppaintcore.h"
 #include "gimppaintcoreundo.h"
 #include "gimppaintcore-loops.h"
@@ -89,7 +89,7 @@ static gboolean  gimp_paint_core_real_pre_paint      (GimpPaintCore    *core,
 static void      gimp_paint_core_real_paint          (GimpPaintCore    *core,
                                                       GimpDrawable     *drawable,
                                                       GimpPaintOptions *options,
-                                                      GimpMultiStroke  *mstroke,
+                                                      GimpSymmetry     *sym,
                                                       GimpPaintState    paint_state,
                                                       guint32           time);
 static void      gimp_paint_core_real_post_paint     (GimpPaintCore    *core,
@@ -236,7 +236,7 @@ static void
 gimp_paint_core_real_paint (GimpPaintCore    *core,
                             GimpDrawable     *drawable,
                             GimpPaintOptions *paint_options,
-                            GimpMultiStroke  *mstroke,
+                            GimpSymmetry     *sym,
                             GimpPaintState    paint_state,
                             guint32           time)
 {
@@ -311,9 +311,9 @@ gimp_paint_core_paint (GimpPaintCore    *core,
                              paint_options,
                              paint_state, time))
     {
-      GimpMultiStroke *mstroke;
-      GimpImage       *image;
-      GimpItem        *item;
+      GimpSymmetry *sym;
+      GimpImage    *image;
+      GimpItem     *item;
 
       item  = GIMP_ITEM (drawable);
       image = gimp_item_get_image (item);
@@ -325,17 +325,16 @@ gimp_paint_core_paint (GimpPaintCore    *core,
           core->last_paint.y = core->cur_coords.y;
         }
 
-      if (gimp_image_get_selected_multi_stroke (image))
-        mstroke = g_object_ref (gimp_image_get_selected_multi_stroke (image));
+      if (gimp_image_get_selected_symmetry (image))
+        sym = g_object_ref (gimp_image_get_selected_symmetry (image));
       else
-        mstroke = g_object_ref (gimp_image_get_single_stroke (image));
-      gimp_multi_stroke_set_origin (mstroke, drawable, &core->cur_coords);
+        sym = g_object_ref (gimp_image_symmetry_get_id (image));
+      gimp_symmetry_set_origin (sym, drawable, &core->cur_coords);
 
       core_class->paint (core, drawable,
                          paint_options,
-                         mstroke,
-                         paint_state, time);
-      g_object_unref (mstroke);
+                         sym, paint_state, time);
+      g_object_unref (sym);
 
       core_class->post_paint (core, drawable,
                               paint_options,
diff --git a/app/paint/gimppaintcore.h b/app/paint/gimppaintcore.h
index 7c4bfd3..e880c83 100644
--- a/app/paint/gimppaintcore.h
+++ b/app/paint/gimppaintcore.h
@@ -93,7 +93,7 @@ struct _GimpPaintCoreClass
   void         (* paint)            (GimpPaintCore    *core,
                                      GimpDrawable     *drawable,
                                      GimpPaintOptions *paint_options,
-                                     GimpMultiStroke  *mstroke,
+                                     GimpSymmetry     *sym,
                                      GimpPaintState    paint_state,
                                      guint32           time);
   void         (* post_paint)       (GimpPaintCore    *core,
diff --git a/app/paint/gimppaintoptions.c b/app/paint/gimppaintoptions.c
index a38d439..118f185 100644
--- a/app/paint/gimppaintoptions.c
+++ b/app/paint/gimppaintoptions.c
@@ -29,13 +29,12 @@
 #include "core/gimp.h"
 #include "core/gimpbrushgenerated.h"
 #include "core/gimpimage.h"
+#include "core/gimpimage-symmetry.h"
 #include "core/gimpdynamics.h"
 #include "core/gimpdynamicsoutput.h"
 #include "core/gimpgradient.h"
 #include "core/gimppaintinfo.h"
-
-#include "gimpmultistroke.h"
-#include "gimpmultistroke-info.h"
+#include "core/gimpsymmetry.h"
 
 #include "gimppaintoptions.h"
 
@@ -132,7 +131,7 @@ enum
   PROP_BRUSH_LINK_SPACING,
   PROP_BRUSH_LINK_HARDNESS,
 
-  PROP_MULTI_STROKE
+  PROP_SYMMETRY
 };
 
 
@@ -374,8 +373,8 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass)
                                     * instablility */
                                    GIMP_PARAM_STATIC_STRINGS);
 
-  GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_MULTI_STROKE,
-                                "multi-stroke", _("Multi Stroke transformation"),
+  GIMP_CONFIG_INSTALL_PROP_INT (object_class, PROP_SYMMETRY,
+                                "symmetry", _("Symmetry"),
                                 G_TYPE_NONE, INT_MAX, G_TYPE_NONE,
                                 GIMP_PARAM_STATIC_STRINGS);
 }
@@ -587,25 +586,25 @@ gimp_paint_options_set_property (GObject      *object,
       smoothing_options->smoothing_factor = g_value_get_double (value);
       break;
 
-    case PROP_MULTI_STROKE:
-      options->multi_stroke = g_value_get_int (value);
+    case PROP_SYMMETRY:
+      options->symmetry = g_value_get_int (value);
       if (context && context->image)
         {
-          if (! gimp_image_select_multi_stroke (context->image,
-                                                options->multi_stroke))
+          if (! gimp_image_select_symmetry (context->image,
+                                            options->symmetry))
             {
-              GimpMultiStroke *mstroke;
+              GimpSymmetry *mstroke;
 
-              mstroke  = gimp_multi_stroke_new (options->multi_stroke,
-                                                context->image);
-              gimp_image_add_multi_stroke (context->image,
-                                           GIMP_MULTI_STROKE (mstroke));
+              mstroke  = gimp_image_symmetry_new (context->image,
+                                                  options->symmetry);
+              gimp_image_add_symmetry (context->image,
+                                       GIMP_SYMMETRY (mstroke));
               g_object_unref (mstroke);
             }
         }
       else
         {
-          options->multi_stroke = G_TYPE_NONE;
+          options->symmetry = G_TYPE_NONE;
         }
       break;
 
@@ -769,8 +768,8 @@ gimp_paint_options_get_property (GObject    *object,
       g_value_set_double (value, smoothing_options->smoothing_factor);
       break;
 
-    case PROP_MULTI_STROKE:
-      g_value_set_int (value, options->multi_stroke);
+    case PROP_SYMMETRY:
+      g_value_set_int (value, options->symmetry);
       break;
 
     default:
@@ -1185,7 +1184,7 @@ gimp_paint_options_copy_gradient_props (GimpPaintOptions *src,
 
 /**
  * Update the paint options of the current tool according to image settings.
- * Multi-Stroke settings are actually attached to an image, and therefore
+ * Symmetry settings are actually attached to an image, and therefore
  * depends on the current context image.
  */
 void
@@ -1203,12 +1202,12 @@ gimp_paint_options_set_mstroke_props (GimpPaintOptions *src,
 
   if (image)
     {
-      GimpMultiStroke  *mstroke;
+      GimpSymmetry  *mstroke;
 
-      mstroke = gimp_image_get_selected_multi_stroke (image);
+      mstroke = gimp_image_get_selected_symmetry (image);
 
       g_object_set (dest,
-                    "multi-stroke",
+                    "symmetry",
                     mstroke ? mstroke->type : G_TYPE_NONE,
                     NULL);
     }
diff --git a/app/paint/gimppaintoptions.h b/app/paint/gimppaintoptions.h
index e38aa30..20f6148 100644
--- a/app/paint/gimppaintoptions.h
+++ b/app/paint/gimppaintoptions.h
@@ -117,7 +117,7 @@ struct _GimpPaintOptions
   GimpViewType              gradient_view_type;
   GimpViewSize              gradient_view_size;
 
-  GType                     multi_stroke;
+  GType                     symmetry;
 };
 
 struct _GimpPaintOptionsClass
diff --git a/app/paint/gimpperspectiveclone.c b/app/paint/gimpperspectiveclone.c
index 1984a62..1148225 100644
--- a/app/paint/gimpperspectiveclone.c
+++ b/app/paint/gimpperspectiveclone.c
@@ -38,8 +38,8 @@
 #include "core/gimpimage.h"
 #include "core/gimppattern.h"
 #include "core/gimppickable.h"
+#include "core/gimpsymmetry.h"
 
-#include "gimpmultistroke.h"
 #include "gimpperspectiveclone.h"
 #include "gimpperspectivecloneoptions.h"
 
@@ -49,7 +49,7 @@
 static void         gimp_perspective_clone_paint      (GimpPaintCore     *paint_core,
                                                        GimpDrawable      *drawable,
                                                        GimpPaintOptions  *paint_options,
-                                                       GimpMultiStroke   *mstroke,
+                                                       GimpSymmetry      *sym,
                                                        GimpPaintState     paint_state,
                                                        guint32            time);
 
@@ -121,7 +121,7 @@ static void
 gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                               GimpDrawable     *drawable,
                               GimpPaintOptions *paint_options,
-                              GimpMultiStroke  *mstroke,
+                              GimpSymmetry     *sym,
                               GimpPaintState    paint_state,
                               guint32           time)
 {
@@ -133,7 +133,7 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
   const GimpCoords     *coords;
 
   /* The source is based on the original stroke */
-  coords = gimp_multi_stroke_get_origin (mstroke);
+  coords = gimp_symmetry_get_origin (sym);
 
   switch (paint_state)
     {
@@ -292,10 +292,10 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
           gint        nstrokes;
           gint        i;
 
-          nstrokes = gimp_multi_stroke_get_size (mstroke);
+          nstrokes = gimp_symmetry_get_size (sym);
           for (i = 0; i < nstrokes; i++)
             {
-              coords = gimp_multi_stroke_get_coords (mstroke, i);
+              coords = gimp_symmetry_get_coords (sym, i);
 
               dest_x = coords->x;
               dest_y = coords->y;
@@ -326,7 +326,7 @@ gimp_perspective_clone_paint (GimpPaintCore    *paint_core,
                 }
             }
 
-          gimp_source_core_motion (source_core, drawable, paint_options, mstroke);
+          gimp_source_core_motion (source_core, drawable, paint_options, sym);
         }
       break;
 
diff --git a/app/paint/gimpsmudge.c b/app/paint/gimpsmudge.c
index e6050a9..2df2639 100644
--- a/app/paint/gimpsmudge.c
+++ b/app/paint/gimpsmudge.c
@@ -32,10 +32,9 @@
 #include "core/gimpdynamics.h"
 #include "core/gimpimage.h"
 #include "core/gimppickable.h"
+#include "core/gimpsymmetry.h"
 #include "core/gimptempbuf.h"
 
-#include "gimpmultistroke.h"
-
 #include "gimpsmudge.h"
 #include "gimpsmudgeoptions.h"
 
@@ -47,17 +46,17 @@ static void       gimp_smudge_finalize     (GObject          *object);
 static void       gimp_smudge_paint        (GimpPaintCore    *paint_core,
                                             GimpDrawable     *drawable,
                                             GimpPaintOptions *paint_options,
-                                            GimpMultiStroke  *mstroke,
+                                            GimpSymmetry     *sym,
                                             GimpPaintState    paint_state,
                                             guint32           time);
 static gboolean   gimp_smudge_start        (GimpPaintCore    *paint_core,
                                             GimpDrawable     *drawable,
                                             GimpPaintOptions *paint_options,
-                                            GimpMultiStroke  *mstroke);
+                                            GimpSymmetry     *sym);
 static void       gimp_smudge_motion       (GimpPaintCore    *paint_core,
                                             GimpDrawable     *drawable,
                                             GimpPaintOptions *paint_options,
-                                            GimpMultiStroke  *mstroke);
+                                            GimpSymmetry     *sym);
 
 static void       gimp_smudge_accumulator_coords (GimpPaintCore    *paint_core,
                                                   const GimpCoords *coords,
@@ -132,7 +131,7 @@ static void
 gimp_smudge_paint (GimpPaintCore    *paint_core,
                    GimpDrawable     *drawable,
                    GimpPaintOptions *paint_options,
-                   GimpMultiStroke  *mstroke,
+                   GimpSymmetry     *sym,
                    GimpPaintState    paint_state,
                    guint32           time)
 {
@@ -144,10 +143,10 @@ gimp_smudge_paint (GimpPaintCore    *paint_core,
       /* initialization fails if the user starts outside the drawable */
       if (! smudge->initialized)
         smudge->initialized = gimp_smudge_start (paint_core, drawable,
-                                                 paint_options, mstroke);
+                                                 paint_options, sym);
 
       if (smudge->initialized)
-        gimp_smudge_motion (paint_core, drawable, paint_options, mstroke);
+        gimp_smudge_motion (paint_core, drawable, paint_options, sym);
       break;
 
     case GIMP_PAINT_STATE_FINISH:
@@ -174,7 +173,7 @@ static gboolean
 gimp_smudge_start (GimpPaintCore    *paint_core,
                    GimpDrawable     *drawable,
                    GimpPaintOptions *paint_options,
-                   GimpMultiStroke  *mstroke)
+                   GimpSymmetry     *sym)
 {
   GimpSmudge *smudge = GIMP_SMUDGE (paint_core);
   GeglBuffer *paint_buffer;
@@ -186,12 +185,12 @@ gimp_smudge_start (GimpPaintCore    *paint_core,
   gint        i;
   gint        x, y;
 
-  nstrokes = gimp_multi_stroke_get_size (mstroke);
+  nstrokes = gimp_symmetry_get_size (sym);
   for (i = 0; i < nstrokes; i++)
     {
       GeglBuffer *accum_buffer;
 
-      coords = gimp_multi_stroke_get_coords (mstroke, i);
+      coords = gimp_symmetry_get_coords (sym, i);
       paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable,
                                                        paint_options, coords,
                                                        &paint_buffer_x,
@@ -260,7 +259,7 @@ static void
 gimp_smudge_motion (GimpPaintCore    *paint_core,
                     GimpDrawable     *drawable,
                     GimpPaintOptions *paint_options,
-                    GimpMultiStroke  *mstroke)
+                    GimpSymmetry     *sym)
 {
   GimpSmudge         *smudge   = GIMP_SMUDGE (paint_core);
   GimpSmudgeOptions  *options  = GIMP_SMUDGE_OPTIONS (paint_options);
@@ -288,10 +287,10 @@ gimp_smudge_motion (GimpPaintCore    *paint_core,
   fade_point = gimp_paint_options_get_fade (paint_options, image,
                                             paint_core->pixel_dist);
 
-  nstrokes = gimp_multi_stroke_get_size (mstroke);
+  nstrokes = gimp_symmetry_get_size (sym);
   for (i = 0; i < nstrokes; i++)
     {
-      coords = gimp_multi_stroke_get_coords (mstroke, i);
+      coords = gimp_symmetry_get_coords (sym, i);
 
       opacity = gimp_dynamics_get_linear_value (dynamics,
                                                 GIMP_DYNAMICS_OUTPUT_OPACITY,
@@ -310,9 +309,9 @@ gimp_smudge_motion (GimpPaintCore    *paint_core,
       if (! paint_buffer)
         continue;
 
-      op = gimp_multi_stroke_get_operation (mstroke, i,
-                                            paint_width,
-                                            paint_height);
+      op = gimp_symmetry_get_operation (sym, i,
+                                        paint_width,
+                                        paint_height);
 
       paint_buffer_width  = gegl_buffer_get_width  (paint_buffer);
       paint_buffer_height = gegl_buffer_get_height (paint_buffer);
diff --git a/app/paint/gimpsourcecore.c b/app/paint/gimpsourcecore.c
index 249da56..0939bca 100644
--- a/app/paint/gimpsourcecore.c
+++ b/app/paint/gimpsourcecore.c
@@ -32,8 +32,8 @@
 #include "core/gimperror.h"
 #include "core/gimpimage.h"
 #include "core/gimppickable.h"
+#include "core/gimpsymmetry.h"
 
-#include "gimpmultistroke.h"
 #include "gimpsourcecore.h"
 #include "gimpsourceoptions.h"
 
@@ -66,7 +66,7 @@ static gboolean gimp_source_core_start           (GimpPaintCore     *paint_core,
 static void     gimp_source_core_paint           (GimpPaintCore     *paint_core,
                                                   GimpDrawable      *drawable,
                                                   GimpPaintOptions  *paint_options,
-                                                  GimpMultiStroke   *mstroke,
+                                                  GimpSymmetry      *sym,
                                                   GimpPaintState     paint_state,
                                                   guint32            time);
 
@@ -74,7 +74,7 @@ static void     gimp_source_core_paint           (GimpPaintCore     *paint_core,
 static void     gimp_source_core_motion          (GimpSourceCore    *source_core,
                                                   GimpDrawable      *drawable,
                                                   GimpPaintOptions  *paint_options,
-                                                  GimpMultiStroke   *mstroke);
+                                                  GimpSymmetry      *sym);
 #endif
 
 static gboolean gimp_source_core_real_use_source (GimpSourceCore    *source_core,
@@ -254,7 +254,7 @@ static void
 gimp_source_core_paint (GimpPaintCore    *paint_core,
                         GimpDrawable     *drawable,
                         GimpPaintOptions *paint_options,
-                        GimpMultiStroke  *mstroke,
+                        GimpSymmetry     *sym,
                         GimpPaintState    paint_state,
                         guint32           time)
 {
@@ -263,7 +263,7 @@ gimp_source_core_paint (GimpPaintCore    *paint_core,
   const GimpCoords  *coords;
 
   /* The source is based on the original stroke */
-  coords = gimp_multi_stroke_get_origin (mstroke);
+  coords = gimp_symmetry_get_origin (sym);
 
   switch (paint_state)
     {
@@ -328,7 +328,7 @@ gimp_source_core_paint (GimpPaintCore    *paint_core,
           source_core->src_y = dest_y + source_core->offset_y;
 
           gimp_source_core_motion (source_core, drawable, paint_options,
-                                   mstroke);
+                                   sym);
         }
       break;
 
@@ -353,7 +353,7 @@ void
 gimp_source_core_motion (GimpSourceCore   *source_core,
                          GimpDrawable     *drawable,
                          GimpPaintOptions *paint_options,
-                         GimpMultiStroke  *mstroke)
+                         GimpSymmetry     *sym)
 
 {
   GimpPaintCore     *paint_core   = GIMP_PAINT_CORE (source_core);
@@ -385,8 +385,8 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
   fade_point = gimp_paint_options_get_fade (paint_options, image,
                                             paint_core->pixel_dist);
 
-  origin   = gimp_multi_stroke_get_origin (mstroke);
-  nstrokes = gimp_multi_stroke_get_size (mstroke);
+  origin   = gimp_symmetry_get_origin (sym);
+  nstrokes = gimp_symmetry_get_size (sym);
 
   /* Some settings are based on the original stroke. */
   opacity = gimp_dynamics_get_linear_value (dynamics,
@@ -423,7 +423,7 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
 
   for (i = 0; i < nstrokes; i++)
     {
-      coords = gimp_multi_stroke_get_coords (mstroke, i);
+      coords = gimp_symmetry_get_coords (sym, i);
 
       paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable,
                                                        paint_options, coords,
@@ -468,9 +468,9 @@ gimp_source_core_motion (GimpSourceCore   *source_core,
       /*  Set the paint buffer to transparent  */
       gegl_buffer_clear (paint_buffer, NULL);
 
-      op = gimp_multi_stroke_get_operation (mstroke, i,
-                                            gegl_buffer_get_width (paint_buffer),
-                                            gegl_buffer_get_height (paint_buffer));
+      op = gimp_symmetry_get_operation (sym, i,
+                                        gegl_buffer_get_width (paint_buffer),
+                                        gegl_buffer_get_height (paint_buffer));
       GIMP_SOURCE_CORE_GET_CLASS (source_core)->motion (source_core,
                                                         drawable,
                                                         paint_options,
diff --git a/app/paint/gimpsourcecore.h b/app/paint/gimpsourcecore.h
index c056cb1..583f3ab 100644
--- a/app/paint/gimpsourcecore.h
+++ b/app/paint/gimpsourcecore.h
@@ -104,7 +104,7 @@ gboolean gimp_source_core_use_source (GimpSourceCore    *source_core,
 void     gimp_source_core_motion     (GimpSourceCore    *source_core,
                                       GimpDrawable      *drawable,
                                       GimpPaintOptions  *paint_options,
-                                      GimpMultiStroke   *mstroke);
+                                      GimpSymmetry      *sym);
 
 
 #endif  /*  __GIMP_SOURCE_CORE_H__  */
diff --git a/app/paint/paint-types.h b/app/paint/paint-types.h
index 8f73d74..1bd9fb0 100644
--- a/app/paint/paint-types.h
+++ b/app/paint/paint-types.h
@@ -42,11 +42,6 @@ typedef struct _GimpPencil           GimpPencil;
 typedef struct _GimpPerspectiveClone GimpPerspectiveClone;
 typedef struct _GimpSmudge           GimpSmudge;
 
-/* Multi-stroke transformations */
-typedef struct _GimpMultiStroke      GimpMultiStroke;
-typedef struct _GimpMirror           GimpMirror;
-typedef struct _GimpTiling           GimpTiling;
-
 /*  paint options  */
 
 typedef struct _GimpPaintOptions            GimpPaintOptions;
diff --git a/app/tools/gimppaintoptions-gui.c b/app/tools/gimppaintoptions-gui.c
index c63a843..071a6ac 100644
--- a/app/tools/gimppaintoptions-gui.c
+++ b/app/tools/gimppaintoptions-gui.c
@@ -28,10 +28,10 @@
 
 #include "core/gimp.h"
 #include "core/gimpimage.h"
+#include "core/gimpimage-symmetry.h"
+#include "core/gimpsymmetry.h"
 #include "core/gimptoolinfo.h"
 
-#include "paint/gimpmultistroke.h"
-#include "paint/gimpmultistroke-info.h"
 #include "paint/gimppaintoptions.h"
 
 #include "widgets/gimppropwidgets.h"
@@ -99,15 +99,15 @@ static GtkWidget * gimp_paint_options_gui_scale_with_buttons
                                                 GtkSizeGroup *link_group);
 
 static void
-     gimp_paint_options_multi_stroke_update_cb (GimpMultiStroke *mstroke,
-                                                GimpImage       *image,
-                                                GtkWidget       *frame);
+         gimp_paint_options_symmetry_update_cb (GimpSymmetry     *sym,
+                                                GimpImage        *image,
+                                                GtkWidget        *frame);
 static void
-      gimp_paint_options_multi_stroke_callback (GimpPaintOptions *options,
+          gimp_paint_options_symmetry_callback (GimpPaintOptions *options,
                                                 GParamSpec       *pspec,
                                                 GtkWidget        *frame);
-static void gimp_paint_options_multi_stroke_ui (GimpMultiStroke *mstroke,
-                                                GtkWidget       *frame);
+static void     gimp_paint_options_symmetry_ui (GimpSymmetry     *sym,
+                                                GtkWidget        *frame);
 
 
 /*  public functions  */
@@ -256,22 +256,22 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
       GimpGuiConfig *guiconfig;
 
       guiconfig = GIMP_GUI_CONFIG (tool_options->tool_info->gimp->config);
-      if (guiconfig->playground_multi_stroke)
+      if (guiconfig->playground_symmetry)
         {
-          /* Multi-Stroke Painting */
+          /* Symmetry Painting */
           GtkListStore *store;
           GtkTreeIter   iter;
-          GList        *mstrokes;
+          GList        *syms;
 
           store = gimp_int_store_new ();
 
-          mstrokes = gimp_multi_stroke_list ();
-          for (mstrokes = gimp_multi_stroke_list (); mstrokes; mstrokes = g_list_next (mstrokes))
+          syms = gimp_image_symmetry_list ();
+          for (syms = gimp_image_symmetry_list (); syms; syms = g_list_next (syms))
             {
-              GimpMultiStrokeClass *klass;
+              GimpSymmetryClass *klass;
               GType                 type;
 
-              type = (GType) mstrokes->data;
+              type = (GType) syms->data;
               klass = g_type_class_ref (type);
 
               gtk_list_store_prepend (store, &iter);
@@ -279,7 +279,7 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
                                   GIMP_INT_STORE_LABEL,
                                   klass->label,
                                   GIMP_INT_STORE_VALUE,
-                                  mstrokes->data,
+                                  syms->data,
                                   -1);
               g_type_class_unref (klass);
             }
@@ -288,11 +288,11 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
                               GIMP_INT_STORE_LABEL, _("None"),
                               GIMP_INT_STORE_VALUE, G_TYPE_NONE,
                               -1);
-          menu = gimp_prop_int_combo_box_new (config, "multi-stroke",
+          menu = gimp_prop_int_combo_box_new (config, "symmetry",
                                               GIMP_INT_STORE (store));
           g_object_unref (store);
 
-          gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (menu), _("Multi-Stroke"));
+          gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (menu), _("Symmetry"));
           gimp_int_combo_box_set_active (GIMP_INT_COMBO_BOX (menu), G_TYPE_NONE);
           g_object_set (menu, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
 
@@ -301,8 +301,8 @@ gimp_paint_options_gui (GimpToolOptions *tool_options)
 
           frame = gimp_frame_new ("");
           gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
-          g_signal_connect (options, "notify::multi-stroke",
-                            G_CALLBACK (gimp_paint_options_multi_stroke_callback),
+          g_signal_connect (options, "notify::symmetry",
+                            G_CALLBACK (gimp_paint_options_symmetry_callback),
                             frame);
 
         }
@@ -633,35 +633,35 @@ gimp_paint_options_gui_scale_with_buttons (GObject      *config,
 }
 
 static void
-gimp_paint_options_multi_stroke_update_cb (GimpMultiStroke *mstroke,
-                                           GimpImage       *image,
-                                           GtkWidget       *frame)
+gimp_paint_options_symmetry_update_cb (GimpSymmetry *sym,
+                                       GimpImage    *image,
+                                       GtkWidget    *frame)
 {
   GimpContext *context;
 
-  g_return_if_fail (GIMP_IS_MULTI_STROKE (mstroke));
+  g_return_if_fail (GIMP_IS_SYMMETRY (sym));
 
-  context = gimp_get_user_context (mstroke->image->gimp);
+  context = gimp_get_user_context (sym->image->gimp);
   if (image != context->image ||
-      mstroke != gimp_image_get_selected_multi_stroke (image))
+      sym != gimp_image_get_selected_symmetry (image))
     {
-      g_signal_handlers_disconnect_by_func (G_OBJECT (mstroke),
-                                            gimp_paint_options_multi_stroke_update_cb,
+      g_signal_handlers_disconnect_by_func (G_OBJECT (sym),
+                                            gimp_paint_options_symmetry_update_cb,
                                             frame);
       return;
     }
 
-  gimp_paint_options_multi_stroke_ui (mstroke, frame);
+  gimp_paint_options_symmetry_ui (sym, frame);
 }
 
 static void
-gimp_paint_options_multi_stroke_callback (GimpPaintOptions *options,
-                                          GParamSpec       *pspec,
-                                          GtkWidget        *frame)
+gimp_paint_options_symmetry_callback (GimpPaintOptions *options,
+                                      GParamSpec       *pspec,
+                                      GtkWidget        *frame)
 {
-  GimpMultiStroke      *mstroke = NULL;
-  GimpContext          *context;
-  GimpImage            *image;
+  GimpSymmetry *sym = NULL;
+  GimpContext  *context;
+  GimpImage    *image;
 
   g_return_if_fail (GIMP_IS_PAINT_OPTIONS (options));
 
@@ -669,35 +669,35 @@ gimp_paint_options_multi_stroke_callback (GimpPaintOptions *options,
   image   = context->image;
 
   if (image &&
-      (mstroke = gimp_image_get_selected_multi_stroke (image)))
+      (sym = gimp_image_get_selected_symmetry (image)))
     {
-      g_signal_connect (mstroke, "update-ui",
-                        G_CALLBACK (gimp_paint_options_multi_stroke_update_cb),
+      g_signal_connect (sym, "update-ui",
+                        G_CALLBACK (gimp_paint_options_symmetry_update_cb),
                         frame);
     }
 
-  gimp_paint_options_multi_stroke_ui (mstroke, frame);
+  gimp_paint_options_symmetry_ui (sym, frame);
 }
 
 static void
-gimp_paint_options_multi_stroke_ui (GimpMultiStroke *mstroke,
-                                    GtkWidget       *frame)
+gimp_paint_options_symmetry_ui (GimpSymmetry *sym,
+                                GtkWidget    *frame)
 {
-  GimpMultiStrokeClass *klass;
-  GtkWidget            *vbox;
-  GParamSpec          **specs;
-  guint                 nproperties;
-  gint                  i;
+  GimpSymmetryClass  *klass;
+  GtkWidget          *vbox;
+  GParamSpec        **specs;
+  guint               nproperties;
+  gint                i;
 
   /* Clean the old frame */
   gtk_widget_hide (frame);
   gtk_container_foreach (GTK_CONTAINER (frame),
                          (GtkCallback) gtk_widget_destroy, NULL);
 
-  if (! mstroke)
+  if (! sym)
     return;
 
-  klass = g_type_class_ref (mstroke->type);
+  klass = g_type_class_ref (sym->type);
   gtk_frame_set_label (GTK_FRAME (frame),
                        klass->label);
   g_type_class_unref (klass);
@@ -706,7 +706,7 @@ gimp_paint_options_multi_stroke_ui (GimpMultiStroke *mstroke,
   gtk_container_add (GTK_CONTAINER (frame), vbox);
   gtk_widget_show (vbox);
 
-  specs = gimp_multi_stroke_get_settings (mstroke, &nproperties);
+  specs = gimp_symmetry_get_settings (sym, &nproperties);
 
   for (i = 0; i < (gint) nproperties; i++)
     {
@@ -735,7 +735,7 @@ gimp_paint_options_multi_stroke_ui (GimpMultiStroke *mstroke,
             {
               GtkWidget *checkbox;
 
-              checkbox = gimp_prop_check_button_new (G_OBJECT (mstroke),
+              checkbox = gimp_prop_check_button_new (G_OBJECT (sym),
                                                      name,
                                                      blurb);
               gtk_box_pack_start (GTK_BOX (vbox), checkbox,
@@ -767,7 +767,7 @@ gimp_paint_options_multi_stroke_ui (GimpMultiStroke *mstroke,
                   maximum = G_PARAM_SPEC_UINT (spec)->maximum;
                 }
 
-              scale = gimp_prop_spin_scale_new (G_OBJECT (mstroke),
+              scale = gimp_prop_spin_scale_new (G_OBJECT (sym),
                                                 name, blurb,
                                                 1.0, 10.0, 1);
               gimp_spin_scale_set_scale_limits (GIMP_SPIN_SCALE (scale),
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index 96225b7..7bb0e1f 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -45,6 +45,7 @@
 #include "core/gimpimage-metadata.h"
 #include "core/gimpimage-private.h"
 #include "core/gimpimage-sample-points.h"
+#include "core/gimpimage-symmetry.h"
 #include "core/gimpimage-undo.h"
 #include "core/gimpitemstack.h"
 #include "core/gimplayer-floating-sel.h"
@@ -53,11 +54,9 @@
 #include "core/gimpparasitelist.h"
 #include "core/gimpprogress.h"
 #include "core/gimpselection.h"
+#include "core/gimpsymmetry.h"
 #include "core/gimptemplate.h"
 
-#include "paint/gimpmultistroke.h"
-#include "paint/gimpmultistroke-info.h"
-
 #include "text/gimptextlayer.h"
 #include "text/gimptextlayer-xcf.h"
 
@@ -740,42 +739,42 @@ xcf_load_image_props (XcfInfo   *info,
           }
           break;
 
-        case PROP_MULTI_STROKE:
+        case PROP_SYMMETRY:
             {
-              GimpMultiStroke *mstroke;
-              GimpMultiStroke *active_mstroke = NULL;
-              gint32           active;
-              gint32           n_mstrokes;
-              gchar           *name;
-              GType            type;
-              GParamSpec     **settings;
-              GParamSpec      *spec;
-              guint            nsettings;
-              gint             i, j;
+              GimpSymmetry  *sym;
+              GimpSymmetry  *active_sym = NULL;
+              gint32         active;
+              gint32         n_syms;
+              gchar         *name;
+              GType          type;
+              GParamSpec   **settings;
+              GParamSpec    *spec;
+              guint          nsettings;
+              gint           i, j;
 
               info->cp += xcf_read_int32 (info->input,
                                           (guint32 *) &active, 1);
               info->cp += xcf_read_int32 (info->input,
-                                          (guint32 *) &n_mstrokes, 1);
-              for (i = 1; i <= n_mstrokes; i++)
+                                          (guint32 *) &n_syms, 1);
+              for (i = 1; i <= n_syms; i++)
                 {
                   info->cp += xcf_read_string (info->input, &name, 1);
                   type = g_type_from_name (name);
-                  if (! type || ! g_type_is_a (type, GIMP_TYPE_MULTI_STROKE))
+                  if (! type || ! g_type_is_a (type, GIMP_TYPE_SYMMETRY))
                     {
                       gimp_message (info->gimp, G_OBJECT (info->progress),
                                     GIMP_MESSAGE_ERROR,
-                                    "Unknown Multi-Stroke: %s",
+                                    "Unknown Symmetry: %s",
                                     name);
                       g_free (name);
                       return FALSE;
                     }
-                  mstroke = gimp_multi_stroke_new (type, image);
-                  gimp_image_add_multi_stroke (image, mstroke);
-                  g_object_unref (mstroke);
+                  sym = gimp_image_symmetry_new (image, type);
+                  gimp_image_add_symmetry (image, sym);
+                  g_object_unref (sym);
 
-                  settings = gimp_multi_stroke_get_xcf_settings (mstroke,
-                                                                 &nsettings);
+                  settings = gimp_symmetry_get_xcf_settings (sym,
+                                                             &nsettings);
                   for (j = 0; j < nsettings; j++)
                     {
                       if (settings[j] == NULL)
@@ -790,7 +789,7 @@ xcf_load_image_props (XcfInfo   *info,
 
                               info->cp += xcf_read_int8 (info->input,
                                                          &value, 1);
-                              g_object_set (mstroke,
+                              g_object_set (sym,
                                             g_param_spec_get_name (spec),
                                             (gboolean) value,
                                             NULL);
@@ -803,7 +802,7 @@ xcf_load_image_props (XcfInfo   *info,
 
                               info->cp += xcf_read_float (info->input,
                                                           &value, 1);
-                              g_object_set (mstroke,
+                              g_object_set (sym,
                                             g_param_spec_get_name (spec),
                                             (spec->value_type == G_TYPE_FLOAT) ?
                                             value : (gdouble) value,
@@ -816,7 +815,7 @@ xcf_load_image_props (XcfInfo   *info,
 
                               info->cp += xcf_read_int32 (info->input,
                                                           &value, 1);
-                              g_object_set (mstroke,
+                              g_object_set (sym,
                                             g_param_spec_get_name (spec),
                                             (guint) value,
                                             NULL);
@@ -828,7 +827,7 @@ xcf_load_image_props (XcfInfo   *info,
 
                               info->cp += xcf_read_int32 (info->input,
                                                           &value, 1);
-                              g_object_set (mstroke,
+                              g_object_set (sym,
                                             g_param_spec_get_name (spec),
                                             (gint) value,
                                             NULL);
@@ -840,7 +839,7 @@ xcf_load_image_props (XcfInfo   *info,
 
                               info->cp += xcf_read_string (info->input,
                                                            &value, 1);
-                              g_object_set (mstroke,
+                              g_object_set (sym,
                                             g_param_spec_get_name (spec),
                                             value,
                                             NULL);
@@ -860,9 +859,9 @@ xcf_load_image_props (XcfInfo   *info,
                   g_free (settings);
 
                   if (active == i)
-                    active_mstroke = mstroke;
+                    active_sym = sym;
                 }
-              gimp_image_select_multi_stroke (image, active_mstroke->type);
+              gimp_image_select_symmetry (image, active_sym->type);
               g_free (name);
             }
           break;
diff --git a/app/xcf/xcf-private.h b/app/xcf/xcf-private.h
index e73e66b..0c3681b 100644
--- a/app/xcf/xcf-private.h
+++ b/app/xcf/xcf-private.h
@@ -58,7 +58,7 @@ typedef enum
   PROP_GROUP_ITEM_FLAGS   = 31,
   PROP_LOCK_POSITION      = 32,
   PROP_FLOAT_OPACITY      = 33,
-  PROP_MULTI_STROKE       = 34
+  PROP_SYMMETRY           = 34
 } PropType;
 
 typedef enum
diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c
index 1604683..b49f6b6 100644
--- a/app/xcf/xcf-save.c
+++ b/app/xcf/xcf-save.c
@@ -45,15 +45,14 @@
 #include "core/gimpimage-metadata.h"
 #include "core/gimpimage-private.h"
 #include "core/gimpimage-sample-points.h"
+#include "core/gimpimage-symmetry.h"
 #include "core/gimplayer.h"
 #include "core/gimplayermask.h"
 #include "core/gimpmirrorguide.h"
 #include "core/gimpparasitelist.h"
 #include "core/gimpprogress.h"
 #include "core/gimpsamplepoint.h"
-
-#include "paint/gimpmultistroke.h"
-#include "paint/gimpmultistroke-info.h"
+#include "core/gimpsymmetry.h"
 
 #include "text/gimptextlayer.h"
 #include "text/gimptextlayer-xcf.h"
@@ -365,9 +364,9 @@ xcf_save_image_props (XcfInfo    *info,
     xcf_check_error (xcf_save_prop (info, image, PROP_GUIDES, error,
                                     gimp_image_get_guides (image)));
 
-  if (gimp_image_get_multi_strokes (image))
-    xcf_check_error (xcf_save_prop (info, image, PROP_MULTI_STROKE, error,
-                                    gimp_image_get_multi_strokes (image)));
+  if (gimp_image_get_symmetrys (image))
+    xcf_check_error (xcf_save_prop (info, image, PROP_SYMMETRY, error,
+                                    gimp_image_get_symmetrys (image)));
 
   if (gimp_image_get_sample_points (image))
     xcf_check_error (xcf_save_prop (info, image, PROP_SAMPLE_POINTS, error,
@@ -947,20 +946,20 @@ xcf_save_prop (XcfInfo    *info,
       }
       break;
 
-    case PROP_MULTI_STROKE:
+    case PROP_SYMMETRY:
       {
-        GList            *mstrokes;
-        GList            *iter;
-        GimpMultiStroke  *mstroke;
-        GParamSpec      **settings;
-        GParamSpec       *spec;
-        guint             nsettings;
-        guint32           base;
-        glong             pos;
-        gint              i = 0;
+        GList         *syms;
+        GList         *iter;
+        GimpSymmetry  *sym;
+        GParamSpec   **settings;
+        GParamSpec    *spec;
+        guint          nsettings;
+        guint32        base;
+        glong          pos;
+        gint           i = 0;
 
         xcf_write_prop_type_check_error (info, prop_type);
-        /* because we don't know how much room the Multi-Stroke list
+        /* because we don't know how much room the Symmetry list
          * will take we save the file position and write the length
          * later.
          */
@@ -969,35 +968,35 @@ xcf_save_prop (XcfInfo    *info,
         xcf_write_int32_check_error (info, &size, 1);
         base = info->cp;
 
-        mstrokes = va_arg (args, GList *);
+        syms = va_arg (args, GList *);
 
-        /* Index of active multi-stroke, starting at 1
+        /* Index of active symmetry starting at 1
          * (because 0 means none active) */
-        if (gimp_image_get_selected_multi_stroke (image))
+        if (gimp_image_get_selected_symmetry (image))
           {
-            for (i = 1, iter = mstrokes; iter; iter = g_list_next (iter), i++)
+            for (i = 1, iter = syms; iter; iter = g_list_next (iter), i++)
               {
-                mstroke = GIMP_MULTI_STROKE (iter->data);
-                if (mstroke == gimp_image_get_selected_multi_stroke (image))
+                sym = GIMP_SYMMETRY (iter->data);
+                if (sym == gimp_image_get_selected_symmetry (image))
                   break;
               }
           }
         xcf_write_int32_check_error (info, (guint32 *)  &i, 1);
-        /* Number of multi-strokes that follows. */
-        i = g_list_length (mstrokes);
+        /* Number of symmetry that follows. */
+        i = g_list_length (syms);
         xcf_write_int32_check_error (info, (guint32 *)  &i, 1);
 
-        for (iter = mstrokes; iter; iter = g_list_next (iter))
+        for (iter = syms; iter; iter = g_list_next (iter))
           {
             const gchar *name;
 
-            mstroke = GIMP_MULTI_STROKE (iter->data);
+            sym = GIMP_SYMMETRY (iter->data);
 
-            name = g_type_name (mstroke->type);
+            name = g_type_name (sym->type);
             xcf_write_string_check_error (info, (gchar **) &name, 1);
 
-            settings = gimp_multi_stroke_get_xcf_settings (mstroke,
-                                                           &nsettings);
+            settings = gimp_symmetry_get_xcf_settings (sym,
+                                                       &nsettings);
 
             for (i = 0; i < nsettings; i++)
               {
@@ -1013,7 +1012,7 @@ xcf_save_prop (XcfInfo    *info,
                         gboolean value;
                         guint8   uint_value;
 
-                        g_object_get (mstroke,
+                        g_object_get (sym,
                                       g_param_spec_get_name (spec),
                                       &value,
                                       NULL);
@@ -1025,7 +1024,7 @@ xcf_save_prop (XcfInfo    *info,
                       {
                         gfloat value;
 
-                        g_object_get (mstroke,
+                        g_object_get (sym,
                                       g_param_spec_get_name (spec),
                                       &value,
                                       NULL);
@@ -1037,7 +1036,7 @@ xcf_save_prop (XcfInfo    *info,
                         gdouble value;
                         gfloat  float_value;
 
-                        g_object_get (mstroke,
+                        g_object_get (sym,
                                       g_param_spec_get_name (spec),
                                       &value,
                                       NULL);
@@ -1050,7 +1049,7 @@ xcf_save_prop (XcfInfo    *info,
                         guint   value;
                         guint32 uint_value;
 
-                        g_object_get (mstroke,
+                        g_object_get (sym,
                                       g_param_spec_get_name (spec),
                                       &value,
                                       NULL);
@@ -1063,7 +1062,7 @@ xcf_save_prop (XcfInfo    *info,
                         gint    value;
                         guint32 uint_value;
 
-                        g_object_get (mstroke,
+                        g_object_get (sym,
                                       g_param_spec_get_name (spec),
                                       &value,
                                       NULL);
@@ -1075,7 +1074,7 @@ xcf_save_prop (XcfInfo    *info,
                       {
                         gchar* value;
 
-                        g_object_get (mstroke,
+                        g_object_get (sym,
                                       g_param_spec_get_name (spec),
                                       &value,
                                       NULL);
diff --git a/devel-docs/xcf.txt b/devel-docs/xcf.txt
index bccfa6b..712a9f2 100644
--- a/devel-docs/xcf.txt
+++ b/devel-docs/xcf.txt
@@ -747,21 +747,21 @@ PROP_GUIDES (editing state)
   Some old XCF files define guides with negative coordinates; those
   should be ignored by readers.
 
-PROP_MULTI_STROKE (editing state)
+PROP_SYMMETRY (editing state)
   uint32  33       Type identification
   uint32  plength  Total length of the following payload in bytes
-                   (sum of mlength for all registered multi-strokes)
-  uint32  active   Index of the active multi-stroke, starting at 1
+                   (sum of mlength for all registered symmetries)
+  uint32  active   Index of the active symmetry, starting at 1
                    (0 means none is active)
-  uint32  n        Number of multi-strokes that follow
-  ,--------------- Repeat for each registered multi-stroke:
-  | string type    name of multi-stroke
+  uint32  n        Number of symmetrythat follow
+  ,--------------- Repeat for each registered symmetry:
+  | string type    name of symmetry
   | ...    params  various parameters.
                    Type and order depends on the
-                   gimp_multi_stroke_get_settings()
+                   gimp_symmetry_get_xcf_settings()
   `--
 
-  PROP_MULTI_STROKE stores the existence and settings of any multi-stroke so
+  PROP_SYMMETRY stores the existence and settings of any symmetry so
   that the user do not lose them upon restart (for instance, if you are drawing
   with a mirror, you want to find it precisely at the same place later).
 


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