Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Sun, 1 Apr 2018 09:03:25 +0000 (11:03 +0200)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 1 Apr 2018 09:03:25 +0000 (11:03 +0200)
- Undo that changes modes currently asserts,
  since undo is now screen data.

  Most likely we will change how object mode and workspaces work
  since it's not practical/maintainable at the moment.

- Removed view_layer from particle settings
  (wasn't needed and complicated undo).

92 files changed:
1  2 
build_files/build_environment/install_deps.sh
build_files/cmake/macros.cmake
intern/CMakeLists.txt
source/blender/blenfont/intern/blf.c
source/blender/blenfont/intern/blf_font.c
source/blender/blenfont/intern/blf_glyph.c
source/blender/blenfont/intern/blf_internal_types.h
source/blender/blenkernel/BKE_global.h
source/blender/blenkernel/BKE_main.h
source/blender/blenkernel/BKE_pointcache.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/armature.c
source/blender/blenkernel/intern/armature_update.c
source/blender/blenkernel/intern/blender.c
source/blender/blenkernel/intern/blender_undo.c
source/blender/blenkernel/intern/cachefile.c
source/blender/blenkernel/intern/camera.c
source/blender/blenkernel/intern/fluidsim.c
source/blender/blenkernel/intern/lamp.c
source/blender/blenkernel/intern/lattice.c
source/blender/blenkernel/intern/library.c
source/blender/blenkernel/intern/linestyle.c
source/blender/blenkernel/intern/mask.c
source/blender/blenkernel/intern/mask_evaluate.c
source/blender/blenkernel/intern/particle_system.c
source/blender/blenkernel/intern/smoke.c
source/blender/blenkernel/intern/world.c
source/blender/blenloader/BLO_readfile.h
source/blender/blenloader/intern/readfile.c
source/blender/editors/armature/editarmature_undo.c
source/blender/editors/curve/editcurve.c
source/blender/editors/curve/editcurve_undo.c
source/blender/editors/curve/editfont_undo.c
source/blender/editors/gpencil/gpencil_brush.c
source/blender/editors/gpencil/gpencil_edit.c
source/blender/editors/include/ED_armature.h
source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_object.h
source/blender/editors/include/ED_particle.h
source/blender/editors/include/ED_sculpt.h
source/blender/editors/lattice/editlattice_undo.c
source/blender/editors/mesh/editmesh_extrude.c
source/blender/editors/mesh/editmesh_tools.c
source/blender/editors/mesh/editmesh_undo.c
source/blender/editors/mesh/editmesh_utils.c
source/blender/editors/metaball/editmball_undo.c
source/blender/editors/object/object_modes.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/physics/particle_edit_undo.c
source/blender/editors/physics/particle_object.c
source/blender/editors/physics/physics_fluid.c
source/blender/editors/physics/physics_intern.h
source/blender/editors/physics/rigidbody_constraint.c
source/blender/editors/physics/rigidbody_object.c
source/blender/editors/render/render_internal.c
source/blender/editors/sculpt_paint/CMakeLists.txt
source/blender/editors/sculpt_paint/paint_curve.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_image_2d.c
source/blender/editors/sculpt_paint/paint_image_proj.c
source/blender/editors/sculpt_paint/paint_image_undo.c
source/blender/editors/sculpt_paint/paint_intern.h
source/blender/editors/sculpt_paint/sculpt_intern.h
source/blender/editors/sculpt_paint/sculpt_undo.c
source/blender/editors/space_action/action_buttons.c
source/blender/editors/space_clip/tracking_ops_orient.c
source/blender/editors/space_image/image_ops.c
source/blender/editors/space_outliner/outliner_edit.c
source/blender/editors/space_text/text_ops.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_manipulator.c
source/blender/editors/util/CMakeLists.txt
source/blender/editors/util/ed_util.c
source/blender/editors/util/undo.c
source/blender/imbuf/intern/thumbs_blend.c
source/blender/makesdna/DNA_scene_types.h
source/blender/makesdna/DNA_windowmanager_types.h
source/blender/makesrna/intern/rna_sculpt_paint.c
source/blender/modifiers/intern/MOD_meshsequencecache.c
source/blender/modifiers/intern/MOD_particleinstance.c
source/blender/windowmanager/CMakeLists.txt
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm.c
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_files.c
source/blender/windowmanager/intern/wm_init_exit.c
source/blender/windowmanager/intern/wm_keymap.c
source/blender/windowmanager/intern/wm_operators.c
source/creator/CMakeLists.txt
source/creator/creator.c
source/creator/creator_args.c

Simple merge
Simple merge
Simple merge
index b4ee0173010feca9b253ce37046ba94ff7e78eb7,af0c2fab7dd3d4e3e547c95e003831a72b80d76f..07e568dd279cbd12d9678a23fc225ab3b1867ea9
@@@ -1132,13 -921,9 +1132,13 @@@ static void blf_font_fill(FontBLF *font
        font->dpi = 0;
        font->size = 0;
        BLI_listbase_clear(&font->cache);
 +      BLI_listbase_clear(&font->kerning_caches);
        font->glyph_cache = NULL;
 +      font->kerning_cache = NULL;
 +#if BLF_BLUR_ENABLE
        font->blur = 0;
-       font->max_tex_size = -1;
 +#endif
+       font->tex_size_max = -1;
  
        font->buf_info.fbuf = NULL;
        font->buf_info.cbuf = NULL;
index f5a645af5e086bfec17b6d955f598d7ce5d87214,60dfdae519b125c7ece71a212bb5f07ce36023dc..6183b54ebcc91be38f76d1229432d6313b72db90
@@@ -503,21 -460,18 +506,21 @@@ void blf_glyph_render(FontBLF *font, Gl
                glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  
                glBindTexture(GL_TEXTURE_2D, g->tex);
-               glTexSubImage2D(GL_TEXTURE_2D, 0, g->xoff, g->yoff, g->width, g->height, GL_RED, GL_UNSIGNED_BYTE, g->bitmap);
 -              glTexSubImage2D(GL_TEXTURE_2D, 0, g->offset_x, g->offset_y, g->width, g->height, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap);
 -              glPopClientAttrib();
++              glTexSubImage2D(GL_TEXTURE_2D, 0, g->offset_x, g->offset_y, g->width, g->height, GL_RED, GL_UNSIGNED_BYTE, g->bitmap);
 +
 +              glPixelStorei(GL_UNPACK_LSB_FIRST, lsb_first);
 +              glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
 +              glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
  
-               g->uv[0][0] = ((float)g->xoff) / ((float)gc->p2_width);
-               g->uv[0][1] = ((float)g->yoff) / ((float)gc->p2_height);
-               g->uv[1][0] = ((float)(g->xoff + g->width)) / ((float)gc->p2_width);
-               g->uv[1][1] = ((float)(g->yoff + g->height)) / ((float)gc->p2_height);
+               g->uv[0][0] = ((float)g->offset_x) / ((float)gc->p2_width);
+               g->uv[0][1] = ((float)g->offset_y) / ((float)gc->p2_height);
+               g->uv[1][0] = ((float)(g->offset_x + g->width)) / ((float)gc->p2_width);
+               g->uv[1][1] = ((float)(g->offset_y + g->height)) / ((float)gc->p2_height);
  
                /* update the x offset for the next glyph. */
-               gc->x_offs += (int)BLI_rctf_size_x(&g->box) + gc->pad;
+               gc->offset_x += (int)BLI_rctf_size_x(&g->box) + gc->pad;
  
-               gc->rem_glyphs--;
+               gc->glyphs_len_free--;
                g->build_tex = 1;
        }
  
Simple merge
index f36a9e99a64f7853d86408a89fa699a9b51d13fc,d789671ab24597514283f780304916ad96c7c061..6a1c3ea883c0ed20a6b9a39e508cbb8731eff4a8
@@@ -194,8 -188,8 +195,9 @@@ set(SR
        intern/tracking_solver.c
        intern/tracking_stabilize.c
        intern/tracking_util.c
+       intern/undo_system.c
        intern/unit.c
 +      intern/workspace.c
        intern/world.c
        intern/writeavi.c
        intern/writeframeserver.c
        BKE_text.h
        BKE_texture.h
        BKE_tracking.h
+       BKE_undo_system.h
        BKE_unit.h
 +      BKE_workspace.h
        BKE_world.h
        BKE_writeavi.h
        BKE_writeframeserver.h
index dbfe3dee30087b3556e91bab1079ed6f87bb73c3,6b31c8c96f9b0e110d2a5b3ef175441083f504e3..98482bcc8b1d58955ba5d7673c2e9d0c77c06811
  #include "BKE_blender_undo.h"  /* own include */
  #include "BKE_blendfile.h"
  #include "BKE_appdir.h"
- #include "BKE_brush.h"
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_global.h"
- #include "BKE_image.h"
  #include "BKE_main.h"
- #include "RE_pipeline.h"
  
  #include "BLO_undofile.h"
- #include "BLO_readfile.h"
  #include "BLO_writefile.h"
  
 +#include "DEG_depsgraph.h"
 +
  /* -------------------------------------------------------------------- */
  
  /** \name Global Undo
index 4431ce38c23a24ea6bbcbdbfe93426cb870538da,132cbd07ac3c6094fad858c0a4f376a94ca2f2e7..8c4bced1563c7a6454f54e9fe87cee8a2fba3d81
@@@ -48,8 -47,6 +48,7 @@@
  #include "BKE_animsys.h"
  #include "BKE_camera.h"
  #include "BKE_object.h"
- #include "BKE_global.h"
 +#include "BKE_layer.h"
  #include "BKE_library.h"
  #include "BKE_library_query.h"
  #include "BKE_library_remap.h"
index d92d0d9edbf3299ff596f9601515f23282652be6,4b9748133d7ca8bbf5af95f7b09ccda17adf8e91..c41ad78977ede1601c645d3139725601397be459
@@@ -53,8 -53,8 +53,7 @@@
  #include "BKE_anim.h"
  #include "BKE_cdderivedmesh.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_displist.h"
- #include "BKE_global.h"
  #include "BKE_key.h"
  #include "BKE_lattice.h"
  #include "BKE_library.h"
index 3256c16e2f658254cabe0fc87678ea6d99ff9137,b5742dbdbb7c4349b53d9ab2bd3bea4f693f5ff7..ba5a6a2504824efbfa5c70aa07bb55a31e091b4a
@@@ -51,7 -51,7 +51,7 @@@
  
  #include "BKE_animsys.h"
  #include "BKE_curve.h"
- #include "BKE_global.h"
 -#include "BKE_depsgraph.h"
++
  #include "BKE_library.h"
  #include "BKE_main.h"
  #include "BKE_mask.h"
index 7d977463abf0b3fb8357485205f3a8b8ec75acb1,e2a9691e577d0b52c910f7bb517fe1e24d144f43..61c136d2c4f2a0c82fa32e51b5a0419f2d18d7b5
@@@ -42,7 -42,7 +42,6 @@@
  #include "DNA_mask_types.h"
  
  #include "BKE_curve.h"
- #include "BKE_global.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_mask.h"
  
  #include "DEG_depsgraph.h"
index b80eca0ed5977178fb851c7bb738e9b8a0fb86e4,8aeeee5a1ad823539b181d46fc81906d105c70e9..8bb35dae96c14f1f7d7c460a0124d07bc0d31d77
@@@ -76,9 -76,7 +76,8 @@@
  #include "BKE_effect.h"
  #include "BKE_library_query.h"
  #include "BKE_particle.h"
- #include "BKE_global.h"
  
 +#include "BKE_collection.h"
  #include "BKE_DerivedMesh.h"
  #include "BKE_object.h"
  #include "BKE_material.h"
index a57fc1fe027e9d6361876a2ef7063ca9197d0a32,5736c9331bf5c2f76521e0733c223e2821047961..e87e84736c82b4bde98f6fa6053270389ce82cd0
@@@ -33,6 -33,6 +33,7 @@@
  #include <string.h>
  #include <stdlib.h>
  #include <math.h>
++
  #include "MEM_guardedalloc.h"
  
  #include "DNA_world_types.h"
index 2b2dbb8a53b3440e6eaa15b23ad57fd3041f7ad7,7b51ddcce920b785ff38db29979a3afedc26e92a..97d132a3e401679dc3bf37ecc989a4d2d9639cc8
@@@ -6561,9 -6300,8 +6560,10 @@@ static void direct_link_windowmanager(F
        wm->defaultconf = NULL;
        wm->addonconf = NULL;
        wm->userconf = NULL;
-       
+       wm->undo_stack = NULL;
 +      wm->message_bus = NULL;
 +
        BLI_listbase_clear(&wm->jobs);
        BLI_listbase_clear(&wm->drags);
        
index 36e6ec4ba7f087bd763bf129992696bc87b91621,f27d68d063480ae93f9f4114933f4f23f6455733..217de06d99b8fd9f7f704b458cebab61cbb23e0b
  #include "MEM_guardedalloc.h"
  
  #include "BLI_math.h"
+ #include "BLI_array_utils.h"
  
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
+ #include "BKE_undo_system.h"
++#include "DEG_depsgraph.h"
 +
  #include "ED_armature.h"
+ #include "ED_object.h"
  #include "ED_util.h"
  
+ #include "WM_types.h"
+ #include "WM_api.h"
+ /* -------------------------------------------------------------------- */
+ /** \name Undo Conversion
+  * \{ */
  typedef struct UndoArmature {
        EditBone *act_edbone;
        ListBase lb;
@@@ -104,9 -116,76 +117,76 @@@ static Object *editarm_object_from_cont
        return NULL;
  }
  
- /* and this is all the undo system needs to know */
- void undo_push_armature(bContext *C, const char *name)
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
+ typedef struct ArmatureUndoStep {
+       UndoStep step;
+       /* note: will split out into list for multi-object-editmode. */
+       UndoRefID_Object obedit_ref;
+       UndoArmature data;
+ } ArmatureUndoStep;
+ static bool armature_undosys_poll(bContext *C)
+ {
+       return editarm_object_from_context(C) != NULL;
+ }
+ static bool armature_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+ {
+       ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+       us->obedit_ref.ptr = editarm_object_from_context(C);
+       bArmature *arm = us->obedit_ref.ptr->data;
+       undoarm_from_editarm(&us->data, arm);
+       us->step.data_size = us->data.undo_size;
+       return true;
+ }
+ static void armature_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+ {
+       /* TODO(campbell): undo_system: use low-level API to set mode. */
+       ED_object_mode_set(C, OB_MODE_EDIT);
+       BLI_assert(armature_undosys_poll(C));
+       ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+       Object *obedit = us->obedit_ref.ptr;
+       bArmature *arm = obedit->data;
+       undoarm_to_editarm(&us->data, arm);
 -      DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
++      DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+ }
+ static void armature_undosys_step_free(UndoStep *us_p)
+ {
+       ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+       undoarm_free_data(&us->data);
+ }
+ static void armature_undosys_foreach_ID_ref(
+         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
  {
-       // XXX solve getdata()
-       undo_editmode_push(C, name, get_armature_edit, free_undoBones, undoBones_to_editBones, editBones_to_undoBones, NULL);
+       ArmatureUndoStep *us = (ArmatureUndoStep *)us_p;
+       foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
  }
+ /* Export for ED_undo_sys. */
+ void ED_armature_undosys_type(UndoType *ut)
+ {
+       ut->name = "Edit Armature";
+       ut->poll = armature_undosys_poll;
+       ut->step_encode = armature_undosys_step_encode;
+       ut->step_decode = armature_undosys_step_decode;
+       ut->step_free = armature_undosys_step_free;
+       ut->step_foreach_ID_ref = armature_undosys_foreach_ID_ref;
+       ut->mode = BKE_UNDOTYPE_MODE_STORE;
+       ut->use_context = true;
+       ut->step_size = sizeof(ArmatureUndoStep);
+ }
+ /** \} */
index f8f96eb3bc9c9977046d60d4fe3d51347eea7586,1bc2d6219b911639310a7d0e5e59d40143ef4676..5775835e5ff70ee9856a3b9b45e311cffdcbc647
  #include "BKE_fcurve.h"
  #include "BKE_library.h"
  #include "BKE_animsys.h"
 -#include "BKE_depsgraph.h"
+ #include "BKE_undo_system.h"
  
++#include "DEG_depsgraph.h"
++
+ #include "ED_object.h"
  #include "ED_util.h"
  #include "ED_curve.h"
  
@@@ -126,38 -136,112 +137,112 @@@ static void undocurve_from_editcurve(Un
                        ED_curve_keyindex_update_nurb(&tmpEditnurb, nu, newnu);
                }
  
-               BLI_addtail(&undoCurve->nubase, newnu);
+               BLI_addtail(&ucu->nubase, newnu);
+               ucu->undo_size += (
+                       (nu->bezt ? (sizeof(BezTriple) * nu->pntsu) : 0) +
+                       (nu->bp ? (sizeof(BPoint) * (nu->pntsu * nu->pntsv)) : 0) +
+                       (nu->knotsu ? (sizeof(float) * KNOTSU(nu)) : 0) +
+                       (nu->knotsv ? (sizeof(float) * KNOTSV(nu)) : 0) +
+                       sizeof(Nurb));
        }
  
-       undoCurve->actvert = cu->actvert;
-       undoCurve->actnu = cu->actnu;
-       undoCurve->flag = cu->flag;
+       ucu->actvert = cu->actvert;
+       ucu->actnu = cu->actnu;
+       ucu->flag = cu->flag;
+ }
+ static void undocurve_free_data(UndoCurve *uc)
+ {
+       BKE_nurbList_free(&uc->nubase);
+       BKE_curve_editNurb_keyIndex_free(&uc->undoIndex);
  
-       return undoCurve;
+       free_fcurves(&uc->fcurves);
+       free_fcurves(&uc->drivers);
  }
  
- static void free_undoCurve(void *ucv)
+ static Object *editcurve_object_from_context(bContext *C)
  {
-       UndoCurve *undoCurve = ucv;
+       Object *obedit = CTX_data_edit_object(C);
+       if (obedit && ELEM(obedit->type, OB_CURVE, OB_SURF)) {
+               Curve *cu = obedit->data;
+               if (BKE_curve_editNurbs_get(cu) != NULL) {
+                       return obedit;
+               }
+       }
+       return NULL;
+ }
  
-       BKE_nurbList_free(&undoCurve->nubase);
+ /** \} */
  
-       BKE_curve_editNurb_keyIndex_free(&undoCurve->undoIndex);
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
  
-       free_fcurves(&undoCurve->fcurves);
-       free_fcurves(&undoCurve->drivers);
+ typedef struct CurveUndoStep {
+       UndoStep step;
+       /* note: will split out into list for multi-object-editmode. */
+       UndoRefID_Object obedit_ref;
+       UndoCurve data;
+ } CurveUndoStep;
  
-       MEM_freeN(undoCurve);
+ static bool curve_undosys_poll(bContext *C)
+ {
+       Object *obedit = editcurve_object_from_context(C);
+       return (obedit != NULL);
  }
  
- static void *get_data(bContext *C)
+ static bool curve_undosys_step_encode(struct bContext *C, UndoStep *us_p)
  {
-       Object *obedit = CTX_data_edit_object(C);
-       return obedit;
+       CurveUndoStep *us = (CurveUndoStep *)us_p;
+       us->obedit_ref.ptr = editcurve_object_from_context(C);
+       undocurve_from_editcurve(&us->data, us->obedit_ref.ptr->data);
+       us->step.data_size = us->data.undo_size;
+       return true;
  }
  
- /* and this is all the undo system needs to know */
- void undo_push_curve(bContext *C, const char *name)
+ static void curve_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
  {
-       undo_editmode_push(C, name, get_data, free_undoCurve, undoCurve_to_editCurve, editCurve_to_undoCurve, NULL);
+       /* TODO(campbell): undo_system: use low-level API to set mode. */
+       ED_object_mode_set(C, OB_MODE_EDIT);
+       BLI_assert(curve_undosys_poll(C));
+       CurveUndoStep *us = (CurveUndoStep *)us_p;
+       Object *obedit = us->obedit_ref.ptr;
+       undocurve_to_editcurve(&us->data, obedit->data);
 -      DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
++      DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
  }
+ static void curve_undosys_step_free(UndoStep *us_p)
+ {
+       CurveUndoStep *us = (CurveUndoStep *)us_p;
+       undocurve_free_data(&us->data);
+ }
+ static void curve_undosys_foreach_ID_ref(
+         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+ {
+       CurveUndoStep *us = (CurveUndoStep *)us_p;
+       foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+ }
+ /* Export for ED_undo_sys. */
+ void ED_curve_undosys_type(UndoType *ut)
+ {
+       ut->name = "Edit Curve";
+       ut->poll = curve_undosys_poll;
+       ut->step_encode = curve_undosys_step_encode;
+       ut->step_decode = curve_undosys_step_decode;
+       ut->step_free = curve_undosys_step_free;
+       ut->step_foreach_ID_ref = curve_undosys_foreach_ID_ref;
+       ut->mode = BKE_UNDOTYPE_MODE_STORE;
+       ut->use_context = true;
+       ut->step_size = sizeof(CurveUndoStep);
+ }
+ /** \} */
index a61f863b61e9db17ca953677f241d119c74bc93c,3a76d0333f9aebc8f4e1c486d4993fd77fd89af6..d4d48e93f43c5fe8df6231b4095fd1e105180bac
  
  #include "BKE_context.h"
  #include "BKE_font.h"
 -#include "BKE_depsgraph.h"
+ #include "BKE_undo_system.h"
++#include "DEG_depsgraph.h"
 +
+ #include "ED_object.h"
  #include "ED_curve.h"
  #include "ED_util.h"
  
@@@ -304,8 -320,76 +321,76 @@@ static Object *editfont_object_from_con
        return NULL;
  }
  
- /* and this is all the undo system needs to know */
- void undo_push_font(bContext *C, const char *name)
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
+ typedef struct FontUndoStep {
+       UndoStep step;
+       /* note: will split out into list for multi-object-editmode. */
+       UndoRefID_Object obedit_ref;
+       UndoFont data;
+ } FontUndoStep;
+ static bool font_undosys_poll(bContext *C)
  {
-       undo_editmode_push(C, name, get_undoFont, free_undoFont, undoFont_to_editFont, editFont_to_undoFont, NULL);
+       return editfont_object_from_context(C) != NULL;
  }
 -      DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ static bool font_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+ {
+       FontUndoStep *us = (FontUndoStep *)us_p;
+       us->obedit_ref.ptr = editfont_object_from_context(C);
+       Curve *cu = us->obedit_ref.ptr->data;
+       undofont_from_editfont(&us->data, cu);
+       us->step.data_size = us->data.undo_size;
+       return true;
+ }
+ static void font_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+ {
+       /* TODO(campbell): undo_system: use low-level API to set mode. */
+       ED_object_mode_set(C, OB_MODE_EDIT);
+       BLI_assert(font_undosys_poll(C));
+       FontUndoStep *us = (FontUndoStep *)us_p;
+       Object *obedit = us->obedit_ref.ptr;
+       Curve *cu = obedit->data;
+       undofont_to_editfont(&us->data, cu);
++      DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+ }
+ static void font_undosys_step_free(UndoStep *us_p)
+ {
+       FontUndoStep *us = (FontUndoStep *)us_p;
+       undofont_free_data(&us->data);
+ }
+ static void font_undosys_foreach_ID_ref(
+         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+ {
+       FontUndoStep *us = (FontUndoStep *)us_p;
+       foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+ }
+ /* Export for ED_undo_sys. */
+ void ED_font_undosys_type(UndoType *ut)
+ {
+       ut->name = "Edit Font";
+       ut->poll = font_undosys_poll;
+       ut->step_encode = font_undosys_step_encode;
+       ut->step_decode = font_undosys_step_decode;
+       ut->step_free = font_undosys_step_free;
+       ut->step_foreach_ID_ref = font_undosys_foreach_ID_ref;
+       ut->mode = BKE_UNDOTYPE_MODE_STORE;
+       ut->use_context = true;
+       ut->step_size = sizeof(FontUndoStep);
+ }
+ /** \} */
index a35380ca547bb57c900f0eec72dd9008b042fee6,241bcbea4af27f8e6e74473af0b302e031d30610..0b1fb57af947ca1e13c93e39bff9bd411fa1976e
@@@ -51,7 -49,7 +51,8 @@@ struct ViewLayer
  struct ViewContext;
  struct wmKeyConfig;
  struct wmOperator;
 +struct Main;
+ struct UndoType;
  
  typedef struct EditBone {
        struct EditBone *next, *prev;
index 4e25284dfa3a24d3621837814f83c9cc3e829f22,349a1944a237b6a220328f85f0116cf82c0527b4..b9723e3865e1f5c3d164a6ce93c850d9d5aa4222
@@@ -128,9 -127,11 +127,12 @@@ void EDBM_flag_enable_all(struct BMEdit
  void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag);
  
  bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e,
 +                       const struct Depsgraph *depsgraph,
                         struct ARegion *ar, struct View3D *v3d, struct Object *obedit);
  
+ /* editmesh_undo.c */
+ void ED_mesh_undosys_type(struct UndoType *ut);
  /* editmesh_select.c */
  void EDBM_select_mirrored(
          struct BMEditMesh *em, const int axis, const bool extend,
index a116cf5e5d0aa93c99d35478abcd32699b6a509f,7faf975ea9132c012d01fc5560e69e9f05ed4924..95adea7fbe2a5e91d180e832a80d06a3f293cc76
@@@ -205,30 -194,10 +205,31 @@@ void ED_object_constraint_dependency_ta
  
  /* object_modes.c */
  bool ED_object_mode_compat_test(const struct Object *ob, eObjectMode mode);
 -bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, eObjectMode mode, struct ReportList *reports);
 +bool ED_object_mode_compat_set(struct bContext *C, struct WorkSpace *workspace, eObjectMode mode, struct ReportList *reports);
  void ED_object_mode_toggle(struct bContext *C, eObjectMode mode);
+ void ED_object_mode_set(struct bContext *C, eObjectMode mode);
  
 +bool ED_object_mode_generic_enter(
 +        struct bContext *C,
 +        eObjectMode object_mode);
 +void ED_object_mode_generic_exit(
 +        const struct EvaluationContext *eval_ctx,
 +        struct WorkSpace *workspace, struct Scene *scene, struct Object *ob);
 +bool ED_object_mode_generic_has_data(
 +        const struct EvaluationContext *eval_ctx,
 +        struct Object *ob);
 +
 +bool ED_object_mode_generic_enter_or_other_window(
 +        struct bContext *C, const struct wmWindow *win_compare,
 +        eObjectMode object_mode);
 +void ED_object_mode_generic_exit_or_other_window(
 +        const struct EvaluationContext *eval_ctx, struct wmWindowManager *wm,
 +        struct WorkSpace *workspace, struct Scene *scene, struct Object *ob);
 +
 +bool ED_object_mode_generic_exists(
 +        struct wmWindowManager *wm, struct Object *ob,
 +        eObjectMode object_mode);
 +
  /* object_modifier.c */
  enum {
        MODIFIER_APPLY_DATA = 1,
index ee60d1c8eef0f61ebf76aaf0b227b7577603dd70,fa5abb8e1ddff84b7fa498e084fe81140d79eb0f..b3e274a235a641eb7038e8d78a02f95db6c00a73
@@@ -38,17 -38,17 +38,18 @@@ struct ParticleEditSettings
  struct rcti;
  struct PTCacheEdit;
  struct Scene;
 +struct ViewLayer;
+ struct UndoType;
  
  /* particle edit mode */
  void PE_free_ptcache_edit(struct PTCacheEdit *edit);
  int PE_start_edit(struct PTCacheEdit *edit);
  
  /* access */
- struct PTCacheEdit *PE_get_current(struct Scene *scene, struct ViewLayer *view_layer, struct Object *ob);
+ struct PTCacheEdit *PE_get_current(struct Scene *scene, struct Object *ob);
 -struct PTCacheEdit *PE_create_current(struct Scene *scene, struct Object *ob);
 -void PE_current_changed(struct Scene *scene, struct Object *ob);
 -int PE_minmax(struct Scene *scene, float min[3], float max[3]);
 +struct PTCacheEdit *PE_create_current(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
 +void PE_current_changed(const struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob);
 +int PE_minmax(struct Scene *scene, struct ViewLayer *view_layer, float min[3], float max[3]);
  struct ParticleEditSettings *PE_settings(struct Scene *scene);
  
  /* update calls */
@@@ -64,14 -62,10 +65,8 @@@ int PE_circle_select(struct bContext *C
  int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, bool extend, bool select);
  void PE_deselect_all_visible(struct PTCacheEdit *edit);
  
- /* undo */
- void PE_undo_push(struct Scene *scene, struct ViewLayer *view_layer, const char *str);
- void PE_undo_step(struct Scene *scene, struct ViewLayer *view_layer, int step);
- void PE_undo(struct Scene *scene, struct ViewLayer *view_layer);
- void PE_redo(struct Scene *scene, struct ViewLayer *view_layer);
- bool PE_undo_is_valid(struct Scene *scene, struct ViewLayer *view_layer);
- void PE_undo_number(struct Scene *scene, struct ViewLayer *view_layer, int nr);
- const char *PE_undo_get_name(struct Scene *scene, struct ViewLayer *view_layer, int nr, bool *r_active);
+ /* particle_edit_undo.c */
+ void ED_particle_undosys_type(struct UndoType *ut);
  
 -void PE_undo_push(struct Scene *scene, const char *str);
 -
  #endif /* __ED_PARTICLE_H__ */
  
index a81d63d9f2593029ebb23c0f94ce53ff81c519c4,7c17e7b68c3ae6def6a2849d984f8c8c34b6ff76..574523696f542ce48578cb30551c250b5a30eded
@@@ -39,7 -42,11 +42,10 @@@ struct ListBase
  
  /* sculpt.c */
  void ED_operatortypes_sculpt(void);
 -void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar,
 -                                 struct RegionView3D *rv3d, struct Object *ob);
 +void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar, struct Object *ob);
  int  ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend);
  
+ /* sculpt_undo.c */
+ void ED_sculpt_undosys_type(struct UndoType *ut);
  #endif /* __ED_SCULPT_H__ */
index aa817928f92553fe145279775b1882a19340a452,7a7372f5a6a791779f096fee8e98aab61813f9d6..58fa08e5aa9b4d180b931d734aa3db78b594d251
  #include "DNA_scene_types.h"
  
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
+ #include "BKE_undo_system.h"
  
++#include "DEG_depsgraph.h"
++
+ #include "ED_object.h"
  #include "ED_lattice.h"
  #include "ED_util.h"
  
@@@ -106,8 -119,77 +120,77 @@@ static Object *editlatt_object_from_con
        return NULL;
  }
  
- /* and this is all the undo system needs to know */
- void undo_push_lattice(bContext *C, const char *name)
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
+ typedef struct LatticeUndoStep {
+       UndoStep step;
+       /* note: will split out into list for multi-object-editmode. */
+       UndoRefID_Object obedit_ref;
+       UndoLattice data;
+ } LatticeUndoStep;
+ static bool lattice_undosys_poll(bContext *C)
+ {
+       return editlatt_object_from_context(C) != NULL;
+ }
+ static bool lattice_undosys_step_encode(struct bContext *C, UndoStep *us_p)
  {
-       undo_editmode_push(C, name, get_editlatt, free_undoLatt, undoLatt_to_editLatt, editLatt_to_undoLatt, validate_undoLatt);
+       LatticeUndoStep *us = (LatticeUndoStep *)us_p;
+       us->obedit_ref.ptr = editlatt_object_from_context(C);
+       Lattice *lt = us->obedit_ref.ptr->data;
+       undolatt_from_editlatt(&us->data, lt->editlatt);
+       us->step.data_size = us->data.undo_size;
+       return true;
  }
 -      DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+ static void lattice_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+ {
+       /* TODO(campbell): undo_system: use low-level API to set mode. */
+       ED_object_mode_set(C, OB_MODE_EDIT);
+       BLI_assert(lattice_undosys_poll(C));
+       LatticeUndoStep *us = (LatticeUndoStep *)us_p;
+       Object *obedit = us->obedit_ref.ptr;
+       Lattice *lt = obedit->data;
+       EditLatt *editlatt = lt->editlatt;
+       undolatt_to_editlatt(&us->data, editlatt);
++      DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+ }
+ static void lattice_undosys_step_free(UndoStep *us_p)
+ {
+       LatticeUndoStep *us = (LatticeUndoStep *)us_p;
+       undolatt_free_data(&us->data);
+ }
+ static void lattice_undosys_foreach_ID_ref(
+         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+ {
+       LatticeUndoStep *us = (LatticeUndoStep *)us_p;
+       foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+ }
+ /* Export for ED_undo_sys. */
+ void ED_lattice_undosys_type(UndoType *ut)
+ {
+       ut->name = "Edit Lattice";
+       ut->poll = lattice_undosys_poll;
+       ut->step_encode = lattice_undosys_step_encode;
+       ut->step_decode = lattice_undosys_step_decode;
+       ut->step_free = lattice_undosys_step_free;
+       ut->step_foreach_ID_ref = lattice_undosys_foreach_ID_ref;
+       ut->mode = BKE_UNDOTYPE_MODE_STORE;
+       ut->use_context = true;
+       ut->step_size = sizeof(LatticeUndoStep);
+ }
+ /** \} */
index ab91f4b34c772c1c87b33da1913e02ba130e8429,220f9cc0287111032ac2ab0b01d66a8e05aa93e2..aeb343707daf8f77de3443b1beeed730eadc219c
  #include "BKE_key.h"
  #include "BKE_mesh.h"
  #include "BKE_editmesh.h"
 -#include "BKE_depsgraph.h"
+ #include "BKE_undo_system.h"
  
++#include "DEG_depsgraph.h"
++
+ #include "ED_object.h"
  #include "ED_mesh.h"
  #include "ED_util.h"
  
@@@ -657,15 -663,162 +664,89 @@@ static Object *editmesh_object_from_con
        return NULL;
  }
  
- /* and this is all the undo system needs to know */
- void undo_push_mesh(bContext *C, const char *name)
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
+ typedef struct MeshUndoStep {
+       UndoStep step;
+       /* Use for all ID lookups (can be NULL). */
+       struct UndoIDPtrMap *id_map;
+       /* note: will split out into list for multi-object-editmode. */
+       UndoRefID_Object obedit_ref;
+       /* Needed for MTexPoly's image use. */
+       UndoRefID_Object *image_array_ref;
+       UndoMesh data;
+ } MeshUndoStep;
 -static void mesh_undosys_step_encode_store_ids(MeshUndoStep *us)
 -{
 -      Mesh *me = us->obedit_ref.ptr->data;
 -      BMesh *bm = me->edit_btmesh->bm;
 -      const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
 -      if (mtex_len != 0) {
 -              ID **id_src = BLI_array_alloca(id_src,  mtex_len);
 -              memset(id_src, 0x0, sizeof(*id_src) * mtex_len);
 -
 -              BMIter iter;
 -              BMFace *efa;
 -
 -              if (us->id_map == NULL) {
 -                      us->id_map = BKE_undosys_ID_map_create();
 -              }
 -
 -              uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0);
 -              uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len);
 -              BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
 -                      for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0;
 -                           cd_poly_tex_offset < cd_poly_tex_offset_end;
 -                           cd_poly_tex_offset += sizeof(MTexPoly), i++)
 -                      {
 -                              const MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
 -                              if (tf->tpage != NULL) {
 -                                      if ((ID *)tf->tpage != id_src[i]) {
 -                                              BKE_undosys_ID_map_add(us->id_map, (ID *)tf->tpage);
 -                                              id_src[i] = (ID *)tf->tpage;
 -                                      }
 -                              }
 -                      }
 -              }
 -      }
 -}
 -
 -static void mesh_undosys_step_decode_restore_ids(MeshUndoStep *us)
 -{
 -      Mesh *me = us->obedit_ref.ptr->data;
 -      BMesh *bm = me->edit_btmesh->bm;
 -      const int mtex_len = CustomData_number_of_layers(&bm->pdata, CD_MTEXPOLY);
 -      if (mtex_len != 0 && us->id_map) {
 -              BMIter iter;
 -              BMFace *efa;
 -
 -              ID **id_dst = BLI_array_alloca(id_dst,  mtex_len);
 -              ID **id_src = BLI_array_alloca(id_src,  mtex_len);
 -              memset(id_src, 0x0, sizeof(*id_src) * mtex_len);
 -
 -              uint cd_poly_tex_offset_first = CustomData_get_n_offset(&bm->pdata, CD_MTEXPOLY, 0);
 -              uint cd_poly_tex_offset_end = cd_poly_tex_offset_first + (sizeof(MTexPoly) * mtex_len);
 -              BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) {
 -                      for (uint cd_poly_tex_offset = cd_poly_tex_offset_first, i = 0;
 -                           cd_poly_tex_offset < cd_poly_tex_offset_end;
 -                           cd_poly_tex_offset += sizeof(MTexPoly), i++)
 -                      {
 -                              MTexPoly *tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset);
 -                              if (tf->tpage != NULL) {
 -                                      if ((ID *)tf->tpage == id_src[i]) {
 -                                              tf->tpage = (Image *)id_dst[i];
 -                                      }
 -                                      else {
 -                                              id_src[i] = (ID *)tf->tpage;
 -                                              tf->tpage = (Image *)BKE_undosys_ID_map_lookup(us->id_map, (ID *)tf->tpage);
 -                                              id_dst[i] = (ID *)tf->tpage;
 -                                      }
 -                              }
 -                      }
 -              }
 -      }
 -}
 -
+ static bool mesh_undosys_poll(bContext *C)
  {
-       /* em->ob gets out of date and crashes on mesh undo,
-        * this is an easy way to ensure its OK
-        * though we could investigate the matter further. */
-       Object *obedit = CTX_data_edit_object(C);
-       BMEditMesh *em = BKE_editmesh_from_object(obedit);
-       em->ob = obedit;
+       return editmesh_object_from_context(C) != NULL;
+ }
+ static bool mesh_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+ {
+       MeshUndoStep *us = (MeshUndoStep *)us_p;
+       us->obedit_ref.ptr = editmesh_object_from_context(C);
+       Mesh *me = us->obedit_ref.ptr->data;
+       undomesh_from_editmesh(&us->data, me->edit_btmesh, me->key);
 -      mesh_undosys_step_encode_store_ids(us);
+       us->step.data_size = us->data.undo_size;
+       return true;
+ }
+ static void mesh_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+ {
+       /* TODO(campbell): undo_system: use low-level API to set mode. */
+       ED_object_mode_set(C, OB_MODE_EDIT);
+       BLI_assert(mesh_undosys_poll(C));
+       MeshUndoStep *us = (MeshUndoStep *)us_p;
+       Object *obedit = us->obedit_ref.ptr;
+       Mesh *me = obedit->data;
+       BMEditMesh *em = me->edit_btmesh;
+       undomesh_to_editmesh(&us->data, em, obedit->data);
 -      mesh_undosys_step_decode_restore_ids(us);
 -      DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
++      DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+ }
+ static void mesh_undosys_step_free(UndoStep *us_p)
+ {
+       MeshUndoStep *us = (MeshUndoStep *)us_p;
+       undomesh_free_data(&us->data);
  
-       undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
+       if (us->id_map != NULL) {
+               BKE_undosys_ID_map_destroy(us->id_map);
+       }
  }
+ static void mesh_undosys_foreach_ID_ref(
+         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+ {
+       MeshUndoStep *us = (MeshUndoStep *)us_p;
+       foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+       if (us->id_map != NULL) {
+               BKE_undosys_ID_map_foreach_ID_ref(us->id_map, foreach_ID_ref_fn, user_data);
+       }
+ }
+ /* Export for ED_undo_sys. */
+ void ED_mesh_undosys_type(UndoType *ut)
+ {
+       ut->name = "Edit Mesh";
+       ut->poll = mesh_undosys_poll;
+       ut->step_encode = mesh_undosys_step_encode;
+       ut->step_decode = mesh_undosys_step_decode;
+       ut->step_free = mesh_undosys_step_free;
+       ut->step_foreach_ID_ref = mesh_undosys_foreach_ID_ref;
+       ut->mode = BKE_UNDOTYPE_MODE_STORE;
+       ut->use_context = true;
+       ut->step_size = sizeof(MeshUndoStep);
+ }
+ /** \} */
index 312dc000a2b58adcaa2c5c380beeabd90e55ffd1,dceffd462ff6ee52428ca3f89de131c54f022ebd..393fa475a9b665588b30c908659460ab2813cfbe
@@@ -43,7 -43,7 +43,6 @@@
  
  #include "BKE_DerivedMesh.h"
  #include "BKE_context.h"
- #include "BKE_global.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_main.h"
  #include "BKE_mesh.h"
  #include "BKE_mesh_mapping.h"
index 974bfb237d38bb26baf77392ee5ba3d2cb55eba9,dc64f61a916aaef6ec4987b7fa54fe7b9123e340..cc461c0c365947b4f95fab9861f8e40e9915dcdd
  #include "DNA_object_types.h"
  
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
+ #include "BKE_undo_system.h"
  
++#include "DEG_depsgraph.h"
++
+ #include "ED_object.h"
  #include "ED_mball.h"
  #include "ED_util.h"
  
@@@ -117,15 -125,75 +126,75 @@@ static Object *editmball_object_from_co
        return NULL;
  }
  
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
  
- static void *get_data(bContext *C)
+ typedef struct MBallUndoStep {
+       UndoStep step;
+       /* note: will split out into list for multi-object-editmode. */
+       UndoRefID_Object obedit_ref;
+       UndoMBall data;
+ } MBallUndoStep;
+ static bool mball_undosys_poll(bContext *C)
  {
-       Object *obedit = CTX_data_edit_object(C);
-       return metaball_get_obdata(obedit);
+       return editmball_object_from_context(C) != NULL;
+ }
+ static bool mball_undosys_step_encode(struct bContext *C, UndoStep *us_p)
+ {
+       MBallUndoStep *us = (MBallUndoStep *)us_p;
+       us->obedit_ref.ptr = editmball_object_from_context(C);
+       MetaBall *mb = us->obedit_ref.ptr->data;
+       editmball_from_undomball(&us->data, mb);
+       us->step.data_size = us->data.undo_size;
+       return true;
  }
  
- /* this is undo system for MetaBalls */
- void undo_push_mball(bContext *C, const char *name)
+ static void mball_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
  {
-       undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
+       ED_object_mode_set(C, OB_MODE_EDIT);
+       MBallUndoStep *us = (MBallUndoStep *)us_p;
+       Object *obedit = us->obedit_ref.ptr;
+       MetaBall *mb = obedit->data;
+       undomball_to_editmball(&us->data, mb);
 -      DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
++      DEG_id_tag_update(&obedit->id, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
  }
+ static void mball_undosys_step_free(UndoStep *us_p)
+ {
+       MBallUndoStep *us = (MBallUndoStep *)us_p;
+       undomball_free_data(&us->data);
+ }
+ static void mball_undosys_foreach_ID_ref(
+         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
+ {
+       MBallUndoStep *us = (MBallUndoStep *)us_p;
+       foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->obedit_ref));
+ }
+ /* Export for ED_undo_sys. */
+ void ED_mball_undosys_type(UndoType *ut)
+ {
+       ut->name = "Edit MBall";
+       ut->poll = mball_undosys_poll;
+       ut->step_encode = mball_undosys_step_encode;
+       ut->step_decode = mball_undosys_step_decode;
+       ut->step_free = mball_undosys_step_free;
+       ut->step_foreach_ID_ref = mball_undosys_foreach_ID_ref;
+       ut->mode = BKE_UNDOTYPE_MODE_STORE;
+       ut->use_context = true;
+       ut->step_size = sizeof(MBallUndoStep);
+ }
+ /** \} */
index 33b9ea49ec0852e15d6d50032542ebb8c11251f1,d70a69e30f8dce1dbaa99bf073874b48153906cf..25795e75fefe73adad95798efde7c3468558560f
@@@ -152,167 -137,42 +152,209 @@@ void ED_object_mode_toggle(bContext *C
        }
  }
  
 -      if (ob->mode == mode) {
++
+ /* Wrapper for operator  */
+ void ED_object_mode_set(bContext *C, eObjectMode mode)
+ {
+ #if 0
+       wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
+       PointerRNA ptr;
+       WM_operator_properties_create_ptr(&ptr, ot);
+       RNA_enum_set(&ptr, "mode", mode);
+       RNA_boolean_set(&ptr, "toggle", false);
+       WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &ptr);
+       WM_operator_properties_free(&ptr);
+ #else
++      const WorkSpace *workspace = CTX_wm_workspace(C);
+       Object *ob = CTX_data_active_object(C);
+       if (ob == NULL) {
+               return;
+       }
 -      else if (mode != OB_MODE_OBJECT) {
 -              if (ob && (ob->mode & mode) == 0) {
++      if (workspace->object_mode == mode) {
+               /* pass */
+       }
 -              ED_object_mode_toggle(C, ob->mode);
++      else if (workspace->object_mode != OB_MODE_OBJECT) {
++              if (ob && (workspace->object_mode & mode) == 0) {
+                       /* needed so we don't do undo pushes. */
+                       wmWindowManager *wm = CTX_wm_manager(C);
+                       wm->op_undo_depth++;
+                       ED_object_mode_toggle(C, mode);
+                       wm->op_undo_depth--;
+               }
+       }
+       else {
+               /* needed so we don't do undo pushes. */
+               wmWindowManager *wm = CTX_wm_manager(C);
+               wm->op_undo_depth++;
++              ED_object_mode_toggle(C, workspace->object_mode);
+               wm->op_undo_depth--;
+       }
+ #endif
+ }
++
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Generic Mode Enter/Exit
 + *
 + * Supports exiting a mode without it being in the current context.
 + * This could be done for entering modes too if it's needed.
 + *
 + * \{ */
 +
 +bool ED_object_mode_generic_enter(
 +        struct bContext *C, eObjectMode object_mode)
 +{
 +      WorkSpace *workspace = CTX_wm_workspace(C);
 +      if (workspace->object_mode == object_mode) {
 +              return true;
 +      }
 +      wmOperatorType *ot = WM_operatortype_find("OBJECT_OT_mode_set", false);
 +      PointerRNA ptr;
 +      WM_operator_properties_create_ptr(&ptr, ot);
 +      RNA_enum_set(&ptr, "mode", object_mode);
 +      WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
 +      WM_operator_properties_free(&ptr);
 +      return (workspace->object_mode == object_mode);
 +}
 +
 +/**
 + * Use for changing works-paces or changing active object.
 + * Caller can check #OB_MODE_ALL_MODE_DATA to test if this needs to be run.
 + */
 +static bool ed_object_mode_generic_exit_ex(
 +        const struct EvaluationContext *eval_ctx,
 +        struct WorkSpace *workspace, struct Scene *scene, struct Object *ob,
 +        bool only_test)
 +{
 +      if (eval_ctx->object_mode & OB_MODE_EDIT) {
 +              if (BKE_object_is_in_editmode(ob)) {
 +                      if (only_test) {
 +                              return true;
 +                      }
 +                      ED_object_editmode_exit_ex(NULL, workspace, scene, ob, EM_FREEDATA);
 +              }
 +      }
 +      else if (eval_ctx->object_mode & OB_MODE_VERTEX_PAINT) {
 +              if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_VERTEX_PAINT)) {
 +                      if (only_test) {
 +                              return true;
 +                      }
 +                      ED_object_vpaintmode_exit_ex(workspace, ob);
 +              }
 +      }
 +      else if (eval_ctx->object_mode & OB_MODE_WEIGHT_PAINT) {
 +              if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_WEIGHT_PAINT)) {
 +                      if (only_test) {
 +                              return true;
 +                      }
 +                      ED_object_wpaintmode_exit_ex(workspace, ob);
 +              }
 +      }
 +      else if (eval_ctx->object_mode & OB_MODE_SCULPT) {
 +              if (ob->sculpt && (ob->sculpt->mode_type == OB_MODE_SCULPT)) {
 +                      if (only_test) {
 +                              return true;
 +                      }
 +                      ED_object_sculptmode_exit_ex(eval_ctx, workspace, scene, ob);
 +              }
 +      }
 +      else {
 +              if (only_test) {
 +                      return false;
 +              }
 +              BLI_assert((eval_ctx->object_mode & OB_MODE_ALL_MODE_DATA) == 0);
 +      }
 +
 +      return false;
 +}
 +
 +void ED_object_mode_generic_exit(
 +        const struct EvaluationContext *eval_ctx,
 +        struct WorkSpace *workspace, struct Scene *scene, struct Object *ob)
 +{
 +      ed_object_mode_generic_exit_ex(eval_ctx, workspace, scene, ob, false);
 +}
 +
 +bool ED_object_mode_generic_has_data(
 +        const struct EvaluationContext *eval_ctx,
 +        struct Object *ob)
 +{
 +      return ed_object_mode_generic_exit_ex(eval_ctx, NULL, NULL, ob, true);
 +}
 +
 +/** \} */
 +
 +/* -------------------------------------------------------------------- */
 +/** \name Mode Syncing Utils
 + *
 + * \{ */
 +
 +/**
 + * A version of #ED_object_mode_generic_enter that checks if the object
 + * has an active mode mode in another window we need to use another window first.
 + */
 +bool ED_object_mode_generic_enter_or_other_window(
 +        struct bContext *C, const wmWindow *win_compare, eObjectMode object_mode)
 +{
 +      WorkSpace *workspace = CTX_wm_workspace(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Base *basact = view_layer->basact;
 +      if (basact == NULL) {
 +              workspace->object_mode = OB_MODE_OBJECT;
 +              return (workspace->object_mode == object_mode);
 +      }
 +
 +      wmWindowManager *wm = CTX_wm_manager(C);
 +      eObjectMode object_mode_set = OB_MODE_OBJECT;
 +      bool use_object_mode = ED_workspace_object_mode_in_other_window(wm, win_compare, basact->object, &object_mode_set);
 +
 +      if (use_object_mode) {
 +              workspace->object_mode = object_mode_set;
 +              return (workspace->object_mode == object_mode);
 +      }
 +      else {
 +              workspace->object_mode = OB_MODE_OBJECT;
 +              return ED_object_mode_generic_enter(C, object_mode);
 +      }
 +}
 +
 +void ED_object_mode_generic_exit_or_other_window(
 +        const struct EvaluationContext *eval_ctx, wmWindowManager *wm,
 +        struct WorkSpace *workspace, struct Scene *scene, struct Object *ob)
 +{
 +      if (ob == NULL) {
 +              return;
 +      }
 +      bool is_active = ED_workspace_object_mode_in_other_window(wm, NULL, ob, NULL);
 +      if (is_active == false) {
 +              ED_object_mode_generic_exit(eval_ctx, workspace, scene, ob);
 +      }
 +}
 +
 +/**
 + * Use to find if we need to create the mode-data.
 + *
 + * When the mode 'exists' it means we have a windowing showing an object with this mode.
 + * So it's data is already created.
 + * Used to check if we need to perform mode switching.
 + */
 +bool ED_object_mode_generic_exists(
 +        wmWindowManager *wm, struct Object *ob,
 +        eObjectMode object_mode)
 +{
 +      if (ob == NULL) {
 +              return false;
 +      }
 +      eObjectMode object_mode_test;
 +      if (ED_workspace_object_mode_in_other_window(wm, NULL, ob, &object_mode_test)) {
 +              if (object_mode == object_mode_test) {
 +                      return true;
 +              }
 +      }
 +      return false;
 +}
 +
 +/** \} */
index 224790269e2b50276b8e323120977496f9334cc8,fce43fa64251ef603778cf8cc67cbae1cf9ed49c..9deae22e4e1c45710bc9257efc0fee8d093b4f6f
  
  int PE_poll(bContext *C)
  {
 +      const WorkSpace *workspace = CTX_wm_workspace(C);
        Scene *scene= CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
        Object *ob= CTX_data_active_object(C);
  
 -      if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
 +      if (!scene || !view_layer || !ob || !(workspace->object_mode & OB_MODE_PARTICLE_EDIT)) {
                return 0;
 -      
 +      }
-       return (PE_get_current(scene, view_layer, ob) != NULL);
+       return (PE_get_current(scene, ob) != NULL);
  }
  
  int PE_hair_poll(bContext *C)
  {
 +      const WorkSpace *workspace = CTX_wm_workspace(C);
        Scene *scene= CTX_data_scene(C);
-       ViewLayer *view_layer = CTX_data_view_layer(C);
        Object *ob= CTX_data_active_object(C);
        PTCacheEdit *edit;
  
 -      if (!scene || !ob || !(ob->mode & OB_MODE_PARTICLE_EDIT))
 +      if (!scene || !ob || !(workspace->object_mode & OB_MODE_PARTICLE_EDIT)) {
                return 0;
 -      
 +      }
-       edit= PE_get_current(scene, view_layer, ob);
+       edit= PE_get_current(scene, ob);
  
        return (edit && edit->psys);
  }
@@@ -200,8 -188,7 +197,8 @@@ static float pe_brush_size_get(const Sc
   *
   * note: this function runs on poll, therefor it can runs many times a second
   * keep it fast! */
 -static PTCacheEdit *pe_get_current(Scene *scene, Object *ob, int create)
 +static PTCacheEdit *pe_get_current(
-         const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, int create)
++        const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int create)
  {
        ParticleEditSettings *pset= PE_settings(scene);
        PTCacheEdit *edit = NULL;
                                if (psys->part && psys->part->type == PART_HAIR) {
                                        if (psys->flag & PSYS_HAIR_DYNAMICS && psys->pointcache->flag & PTCACHE_BAKED) {
                                                if (create && !psys->pointcache->edit)
-                                                       PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL);
 -                                                      PE_create_particle_edit(scene, ob, pid->cache, NULL);
++                                                      PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL);
                                                edit = pid->cache->edit;
                                        }
                                        else {
                                                if (create && !psys->edit && psys->flag & PSYS_HAIR_DONE)
-                                                       PE_create_particle_edit(eval_ctx, scene, view_layer, ob, NULL, psys);
 -                                                      PE_create_particle_edit(scene, ob, NULL, psys);
++                                                      PE_create_particle_edit(eval_ctx, scene, ob, NULL, psys);
                                                edit = psys->edit;
                                        }
                                }
                                else {
                                        if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit)
-                                               PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, psys);
 -                                              PE_create_particle_edit(scene, ob, pid->cache, psys);
++                                              PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, psys);
                                        edit = pid->cache->edit;
                                }
  
                        if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
                                pset->flag |= PE_FADE_TIME;
                                // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
-                               PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL);
 -                              PE_create_particle_edit(scene, ob, pid->cache, NULL);
++                              PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL);
                        }
                        edit = pid->cache->edit;
                        break;
                        if (create && pid->cache->flag & PTCACHE_BAKED && !pid->cache->edit) {
                                pset->flag |= PE_FADE_TIME;
                                // NICE TO HAVE but doesn't work: pset->brushtype = PE_BRUSH_COMB;
-                               PE_create_particle_edit(eval_ctx, scene, view_layer, ob, pid->cache, NULL);
 -                              PE_create_particle_edit(scene, ob, pid->cache, NULL);
++                              PE_create_particle_edit(eval_ctx, scene, ob, pid->cache, NULL);
                        }
                        edit = pid->cache->edit;
                        break;
        return edit;
  }
  
- PTCacheEdit *PE_get_current(Scene *scene, ViewLayer *view_layer, Object *ob)
+ PTCacheEdit *PE_get_current(Scene *scene, Object *ob)
  {
-       return pe_get_current(NULL, scene, view_layer, ob, 0);
 -      return pe_get_current(scene, ob, 0);
++      return pe_get_current(NULL, scene, ob, 0);
  }
  
 -PTCacheEdit *PE_create_current(Scene *scene, Object *ob)
 +PTCacheEdit *PE_create_current(const EvaluationContext *eval_ctx, Scene *scene, Object *ob)
  {
-       return pe_get_current(eval_ctx, scene, eval_ctx->view_layer, ob, 1);
 -      return pe_get_current(scene, ob, 1);
++      return pe_get_current(eval_ctx, scene, ob, 1);
  }
  
 -void PE_current_changed(Scene *scene, Object *ob)
 +void PE_current_changed(const EvaluationContext *eval_ctx, Scene *scene, Object *ob)
  {
 -      if (ob->mode == OB_MODE_PARTICLE_EDIT)
 -              PE_create_current(scene, ob);
 +      if (eval_ctx->object_mode == OB_MODE_PARTICLE_EDIT) {
 +              PE_create_current(eval_ctx, scene, ob);
 +      }
  }
  
  void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
@@@ -381,11 -364,9 +377,11 @@@ static void PE_set_data(bContext *C, PE
  {
        memset(data, 0, sizeof(*data));
  
 -      data->scene= CTX_data_scene(C);
 -      data->ob= CTX_data_active_object(C);
 -      data->edit= PE_get_current(data->scene, data->ob);
 +      data->scene = CTX_data_scene(C);
 +      data->view_layer = CTX_data_view_layer(C);
 +      data->ob = CTX_data_active_object(C);
 +      CTX_data_eval_ctx(C, &data->eval_ctx);
-       data->edit = PE_get_current(data->scene, data->view_layer, data->ob);
++      data->edit = PE_get_current(data->scene, data->ob);
  }
  
  static void PE_set_view3d_data(bContext *C, PEData *data)
@@@ -1144,9 -1128,9 +1140,9 @@@ void recalc_emitter_field(Object *ob, P
        BLI_kdtree_balance(edit->emitter_field);
  }
  
 -static void PE_update_selection(Scene *scene, Object *ob, int useflag)
 +static void PE_update_selection(const EvaluationContext *eval_ctx, Scene *scene, Object *ob, int useflag)
  {
-       PTCacheEdit *edit = PE_get_current(scene, eval_ctx->view_layer, ob);
 -      PTCacheEdit *edit= PE_get_current(scene, ob);
++      PTCacheEdit *edit = PE_get_current(scene, ob);
        HairKey *hkey;
        POINT_P; KEY_K;
  
@@@ -1393,10 -1375,8 +1389,10 @@@ static void select_action_apply(PTCache
  static int pe_select_all_exec(bContext *C, wmOperator *op)
  {
        Scene *scene= CTX_data_scene(C);
 +      EvaluationContext eval_ctx;
 +      CTX_data_eval_ctx(C, &eval_ctx);
        Object *ob= CTX_data_active_object(C);
-       PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
+       PTCacheEdit *edit= PE_get_current(scene, ob);
        POINT_P; KEY_K;
        int action = RNA_enum_get(op->ptr, "action");
  
@@@ -1448,11 -1428,10 +1444,10 @@@ int PE_mouse_particles(bContext *C, con
  {
        PEData data;
        Scene *scene= CTX_data_scene(C);
-       ViewLayer *view_layer = CTX_data_view_layer(C);
        Object *ob= CTX_data_active_object(C);
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+       PTCacheEdit *edit= PE_get_current(scene, ob);
        POINT_P; KEY_K;
 -      
 +
        if (!PE_start_edit(edit))
                return OPERATOR_CANCELLED;
  
@@@ -1903,13 -1879,9 +1895,13 @@@ static int hide_exec(bContext *C, wmOpe
  {
        Object *ob= CTX_data_active_object(C);
        Scene *scene= CTX_data_scene(C);
-       PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
 +      EvaluationContext eval_ctx;
 +      CTX_data_eval_ctx(C, &eval_ctx);
 +
+       PTCacheEdit *edit= PE_get_current(scene, ob);
        POINT_P; KEY_K;
 -      
 +
 +
        if (RNA_enum_get(op->ptr, "unselected")) {
                LOOP_UNSELECTED_POINTS {
                        point->flag |= PEP_HIDE;
@@@ -1959,9 -1931,7 +1951,9 @@@ static int reveal_exec(bContext *C, wmO
  {
        Object *ob= CTX_data_active_object(C);
        Scene *scene= CTX_data_scene(C);
 -      PTCacheEdit *edit = PE_get_current(scene, ob);
 +      EvaluationContext eval_ctx;
 +      CTX_data_eval_ctx(C, &eval_ctx);
-       PTCacheEdit *edit= PE_get_current(scene, eval_ctx.view_layer, ob);
++      PTCacheEdit *edit= PE_get_current(scene, ob);
        const bool select = RNA_boolean_get(op->ptr, "select");
        POINT_P; KEY_K;
  
@@@ -2228,11 -2192,11 +2220,11 @@@ void PARTICLE_OT_rekey(wmOperatorType *
        RNA_def_int(ot->srna, "keys_number", 2, 2, INT_MAX, "Number of Keys", "", 2, 100);
  }
  
- static void rekey_particle_to_time(const bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int pa_index, float path_time)
 -static void rekey_particle_to_time(Scene *scene, Object *ob, int pa_index, float path_time)
++static void rekey_particle_to_time(const bContext *C, Scene *scene, Object *ob, int pa_index, float path_time)
  {
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+       PTCacheEdit *edit= PE_get_current(scene, ob);
        ParticleSystem *psys;
 -      ParticleSimulationData sim= {0};
 +      ParticleSimulationData sim = {0};
        ParticleData *pa;
        ParticleKey state;
        HairKey *new_keys, *key;
@@@ -2823,12 -2772,11 +2813,12 @@@ void PARTICLE_OT_delete(wmOperatorType 
  
  /*************************** mirror operator **************************/
  
 -static void PE_mirror_x(Scene *scene, Object *ob, int tagged)
 +static void PE_mirror_x(
-         Scene *scene, ViewLayer *view_layer, Object *ob, int tagged)
++        Scene *scene, Object *ob, int tagged)
  {
        Mesh *me= (Mesh *)(ob->data);
        ParticleSystemModifierData *psmd;
-       PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
 -      PTCacheEdit *edit= PE_get_current(scene, ob);
++      PTCacheEdit *edit = PE_get_current(scene, ob);
        ParticleSystem *psys = edit->psys;
        ParticleData *pa, *newpa, *new_pars;
        PTCacheEditPoint *newpoint, *new_points;
@@@ -3116,7 -3063,7 +3105,7 @@@ static void brush_cut(PEData *data, in
                        edit->points[pa_index].flag |= PEP_TAG;
                }
                else {
-                       rekey_particle_to_time(data->context, data->scene, data->view_layer, ob, pa_index, cut_time);
 -                      rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
++                      rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
                        edit->points[pa_index].flag |= PEP_EDIT_RECALC;
                }
        }
@@@ -3768,10 -3706,9 +3757,10 @@@ typedef struct BrushEdit 
  static int brush_edit_init(bContext *C, wmOperator *op)
  {
        Scene *scene= CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
        Object *ob= CTX_data_active_object(C);
        ParticleEditSettings *pset= PE_settings(scene);
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+       PTCacheEdit *edit= PE_get_current(scene, ob);
        ARegion *ar= CTX_wm_region(C);
        BrushEdit *bedit;
        float min[3], max[3];
@@@ -4223,7 -4153,7 +4211,7 @@@ static void shape_cut(PEData *data, in
                        edit->points[pa_index].flag |= PEP_TAG;
                }
                else {
-                       rekey_particle_to_time(data->context, data->scene, data->view_layer, ob, pa_index, cut_time);
 -                      rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
++                      rekey_particle_to_time(data->context, data->scene, ob, pa_index, cut_time);
                        edit->points[pa_index].flag |= PEP_EDIT_RECALC;
                }
        }
@@@ -4307,10 -4235,10 +4294,10 @@@ void PARTICLE_OT_shape_cut(wmOperatorTy
  
  /************************ utilities ******************************/
  
 -int PE_minmax(Scene *scene, float min[3], float max[3])
 +int PE_minmax(Scene *scene, ViewLayer *view_layer, float min[3], float max[3])
  {
 -      Object *ob= OBACT;
 +      Object *ob= OBACT(view_layer);
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, ob);
+       PTCacheEdit *edit= PE_get_current(scene, ob);
        ParticleSystem *psys;
        ParticleSystemModifierData *psmd = NULL;
        POINT_P; KEY_K;
  /************************ particle edit toggle operator ************************/
  
  /* initialize needed data for bake edit */
 -void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
 +void PE_create_particle_edit(
-         const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, Object *ob, PointCache *cache, ParticleSystem *psys)
++        const EvaluationContext *eval_ctx, Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys)
  {
        PTCacheEdit *edit;
        ParticleSystemModifierData *psmd = (psys) ? psys_get_modifier(ob, psys) : NULL;
                recalc_lengths(edit);
                if (psys && !cache)
                        recalc_emitter_field(ob, psys);
 -              PE_update_object(scene, ob, 1);
 -
 -              /* Causes issues, adding undo pushes while performing undo history.
 -               * Seems not to like this isn't needed anyway - Campbell. */
 -#if 0
 -              PE_undo_push(scene, "Original");
 -#endif
 +              PE_update_object(eval_ctx, scene, ob, 1);
-               PTCacheUndo_clear(edit);
-               PE_undo_push(scene, view_layer, "Original");
        }
  }
  
@@@ -4663,12 -4586,8 +4647,12 @@@ static int unify_length_exec(bContext *
  {
        Object *ob = CTX_data_active_object(C);
        Scene *scene = CTX_data_scene(C);
-       PTCacheEdit *edit = PE_get_current(scene, eval_ctx.view_layer, ob);
 +      EvaluationContext eval_ctx;
 +      CTX_data_eval_ctx(C, &eval_ctx);
 +
+       PTCacheEdit *edit = PE_get_current(scene, ob);
        float average_length = calculate_average_length(edit);
 +
        if (average_length == 0.0f) {
                return OPERATOR_CANCELLED;
        }
index 45eb5923e577c207c0c5fd4cfad3388983f4f5fa,329658a56e1800ce470ed0781389d53f1c35148a..1264800afc86694da4cf3a056be969f2730f76ae
  #include "BKE_global.h"
  #include "BKE_particle.h"
  #include "BKE_pointcache.h"
+ #include "BKE_context.h"
+ #include "BKE_main.h"
+ #include "BKE_undo_system.h"
  
 +#include "DEG_depsgraph.h"
 +
+ #include "ED_object.h"
  #include "ED_particle.h"
+ #include "ED_physics.h"
  
  #include "particle_edit_utildefines.h"
  
@@@ -192,150 -193,122 +194,110 @@@ static void undoptcache_to_editcache(PT
        }
  }
  
void PE_undo_push(Scene *scene, ViewLayer *view_layer, const char *str)
static void undoptcache_free_data(PTCacheUndo *undo)
  {
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
-       PTCacheUndo *undo;
-       int nr;
-       if (!edit) return;
-       /* remove all undos after (also when curundo==NULL) */
-       while (edit->undo.last != edit->curundo) {
-               undo= edit->undo.last;
-               BLI_remlink(&edit->undo, undo);
-               free_PTCacheUndo(undo);
-               MEM_freeN(undo);
-       }
+       PTCacheEditPoint *point;
+       int i;
  
-       /* make new */
-       edit->curundo= undo= MEM_callocN(sizeof(PTCacheUndo), "particle undo file");
-       BLI_strncpy(undo->name, str, sizeof(undo->name));
-       BLI_addtail(&edit->undo, undo);
-       /* and limit amount to the maximum */
-       nr= 0;
-       undo= edit->undo.last;
-       while (undo) {
-               nr++;
-               if (nr==U.undosteps) break;
-               undo= undo->prev;
-       }
-       if (undo) {
-               while (edit->undo.first != undo) {
-                       PTCacheUndo *first= edit->undo.first;
-                       BLI_remlink(&edit->undo, first);
-                       free_PTCacheUndo(first);
-                       MEM_freeN(first);
+       for (i = 0, point=undo->points; i < undo->totpoint; i++, point++) {
+               if (undo->particles && (undo->particles + i)->hair) {
+                       MEM_freeN((undo->particles + i)->hair);
+               }
+               if (point->keys) {
+                       MEM_freeN(point->keys);
                }
        }
-       /* copy  */
-       make_PTCacheUndo(edit, edit->curundo);
+       if (undo->points) {
+               MEM_freeN(undo->points);
+       }
+       if (undo->particles) {
+               MEM_freeN(undo->particles);
+       }
+       BKE_ptcache_free_mem(&undo->mem_cache);
  }
  
- void PE_undo_step(Scene *scene, ViewLayer *view_layer, int step)
- {
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
+ /** \} */
  
-       if (!edit) return;
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
  
-       if (step==0) {
-               get_PTCacheUndo(edit, edit->curundo);
-       }
-       else if (step==1) {
+ typedef struct ParticleUndoStep {
+       UndoStep step;
+       UndoRefID_Scene scene_ref;
+       UndoRefID_Object object_ref;
+       PTCacheUndo data;
+ } ParticleUndoStep;
  
-               if (edit->curundo==NULL || edit->curundo->prev==NULL) {
-                       /* pass */
-               }
-               else {
-                       if (G.debug & G_DEBUG) printf("undo %s\n", edit->curundo->name);
-                       edit->curundo= edit->curundo->prev;
-                       get_PTCacheUndo(edit, edit->curundo);
-               }
-       }
-       else {
-               /* curundo has to remain current situation! */
-               if (edit->curundo==NULL || edit->curundo->next==NULL) {
-                       /* pass */
-               }
-               else {
-                       get_PTCacheUndo(edit, edit->curundo->next);
-                       edit->curundo= edit->curundo->next;
-                       if (G.debug & G_DEBUG) printf("redo %s\n", edit->curundo->name);
-               }
-       }
-       DEG_id_tag_update(&OBACT(view_layer)->id, OB_RECALC_DATA);
+ static bool particle_undosys_poll(struct bContext *C)
+ {
+       Scene *scene = CTX_data_scene(C);
 -      Object *ob = OBACT;
++      ViewLayer *view_layer = CTX_data_view_layer(C);
++      Object *ob = OBACT(view_layer);
+       PTCacheEdit *edit = PE_get_current(scene, ob);
++      
+       return (edit != NULL);
  }
  
bool PE_undo_is_valid(Scene *scene, ViewLayer *view_layer)
static bool particle_undosys_step_encode(struct bContext *C, UndoStep *us_p)
  {
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
-       if (edit) {
-               return (edit->undo.last != edit->undo.first);
-       }
-       return 0;
+       ParticleUndoStep *us = (ParticleUndoStep *)us_p;
++      ViewLayer *view_layer = CTX_data_view_layer(C);
+       us->scene_ref.ptr = CTX_data_scene(C);
 -      us->object_ref.ptr = us->scene_ref.ptr->basact->object;
++      us->object_ref.ptr = OBACT(view_layer);
+       PTCacheEdit *edit = PE_get_current(us->scene_ref.ptr, us->object_ref.ptr);
+       undoptcache_from_editcache(&us->data, edit);
+       return true;
  }
  
void PTCacheUndo_clear(PTCacheEdit *edit)
static void particle_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
  {
-       PTCacheUndo *undo;
-       if (edit==NULL) return;
-       undo= edit->undo.first;
-       while (undo) {
-               free_PTCacheUndo(undo);
-               undo= undo->next;
+       /* TODO(campbell): undo_system: use low-level API to set mode. */
+       ED_object_mode_set(C, OB_MODE_PARTICLE_EDIT);
+       BLI_assert(particle_undosys_poll(C));
+       ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+       Scene *scene = us->scene_ref.ptr;
+       Object *ob = us->object_ref.ptr;
+       PTCacheEdit *edit = PE_get_current(scene, ob);
+       if (edit) {
+               undoptcache_to_editcache(&us->data, edit);
 -              DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
++              DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
+       }
+       else {
+               BLI_assert(0);
        }
-       BLI_freelistN(&edit->undo);
-       edit->curundo= NULL;
  }
  
void PE_undo(Scene *scene, ViewLayer *view_layer)
static void particle_undosys_step_free(UndoStep *us_p)
  {
-       PE_undo_step(scene, view_layer, 1);
+       ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+       undoptcache_free_data(&us->data);
  }
  
- void PE_redo(Scene *scene, ViewLayer *view_layer)
+ static void particle_undosys_foreach_ID_ref(
+         UndoStep *us_p, UndoTypeForEachIDRefFn foreach_ID_ref_fn, void *user_data)
  {
-       PE_undo_step(scene, view_layer, -1);
+       ParticleUndoStep *us = (ParticleUndoStep *)us_p;
+       foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->scene_ref));
+       foreach_ID_ref_fn(user_data, ((UndoRefID *)&us->object_ref));
  }
  
- void PE_undo_number(Scene *scene, ViewLayer *view_layer, int nr)
+ /* Export for ED_undo_sys. */
+ void ED_particle_undosys_type(UndoType *ut)
  {
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
-       PTCacheUndo *undo;
-       int a=0;
-       for (undo= edit->undo.first; undo; undo= undo->next, a++) {
-               if (a==nr) break;
-       }
-       edit->curundo= undo;
-       PE_undo_step(scene, view_layer, 0);
- }
+       ut->name = "Edit Particle";
+       ut->poll = particle_undosys_poll;
+       ut->step_encode = particle_undosys_step_encode;
+       ut->step_decode = particle_undosys_step_decode;
+       ut->step_free = particle_undosys_step_free;
  
- /* get name of undo item, return null if no item with this index */
- /* if active pointer, set it to 1 if true */
- const char *PE_undo_get_name(Scene *scene, ViewLayer *view_layer, int nr, bool *r_active)
- {
-       PTCacheEdit *edit= PE_get_current(scene, view_layer, OBACT(view_layer));
-       PTCacheUndo *undo;
+       ut->step_foreach_ID_ref = particle_undosys_foreach_ID_ref;
  
-       if (r_active) *r_active = false;
+       ut->mode = BKE_UNDOTYPE_MODE_STORE;
+       ut->use_context = true;
  
-       if (edit) {
-               undo= BLI_findlink(&edit->undo, nr);
-               if (undo) {
-                       if (r_active && (undo == edit->curundo)) {
-                               *r_active = true;
-                       }
-                       return undo->name;
-               }
-       }
-       return NULL;
+       ut->step_size = sizeof(ParticleUndoStep);
  }
 -
 -/* -------------------------------------------------------------------- */
 -/** \name Utilities
 - * \{ */
 -
 -void PE_undo_push(struct Scene *scene, const char *str)
 -{
 -      wmWindowManager *wm = G.main->wm.first;
 -      bContext *C_temp = CTX_create();
 -      CTX_data_scene_set(C_temp, scene);
 -      BKE_undosys_step_push_with_type(wm->undo_stack, C_temp, str, BKE_UNDOSYS_TYPE_PARTICLE);
 -      CTX_free(C_temp);
 -}
 -
 -/** \} */
+ /** \} */
index 71810d0913555c2d2b55737ad34bc1952b1af02b,63b84df9fce1c3fe0ba7f78babcfc680710dc3cf..f6ece9d4bdc179865c6808786eb665ab1a6675df
@@@ -962,10 -939,9 +959,7 @@@ static void copy_particle_edit
        
        recalc_lengths(edit);
        recalc_emitter_field(ob, psys);
 -      PE_update_object(scene, ob, true);
 -
 -      PE_undo_push(scene, "Original");
 +      PE_update_object(eval_ctx, scene, ob, true);
-       
-       PTCacheUndo_clear(edit);
-       PE_undo_push(scene, view_layer, "Original");
  }
  
  static void remove_particle_systems_from_object(Object *ob_to)
index 8888589b5d797f00897b9cea801e655e7f0a77ed,f3f3697caaa661ff2120ec3ab5b78ada77d643cb..246bf79360f1c522ebb3a15be2ef869038056b89
@@@ -70,10 -68,7 +70,9 @@@ void PARTICLE_OT_edited_clear(struct wm
  
  void PARTICLE_OT_unify_length(struct wmOperatorType *ot);
  
- void PTCacheUndo_clear(struct PTCacheEdit *edit);
 -void PE_create_particle_edit(struct Scene *scene, struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys);
 +void PE_create_particle_edit(
-         const struct EvaluationContext *eval_ctx, struct Scene *scene, struct ViewLayer *view_layer,
++        const struct EvaluationContext *eval_ctx, struct Scene *scene,
 +        struct Object *ob, struct PointCache *cache, struct ParticleSystem *psys);
  void recalc_lengths(struct PTCacheEdit *edit);
  void recalc_emitter_field(struct Object *ob, struct ParticleSystem *psys);
  void update_world_cos(struct Object *ob, struct PTCacheEdit *edit);
index f77e164ba160e98b9fcb81dde60dd202aad452e3,412f9acf718a63d939738969d2594e0057ec9f5b..3bcc047bf5ba0e3c0e44f2d4577a7486bd93b160
@@@ -38,7 -38,7 +38,6 @@@
  #include "DNA_scene_types.h"
  
  #include "BKE_context.h"
- #include "BKE_global.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_group.h"
  #include "BKE_main.h"
  #include "BKE_report.h"
index 3b667520550003930d45586026a3be2246a78cc0,b7083c297219e7c4c61163f11e258fb8830a897f..3553ffa5033a895f2fc11d467341247a295df15c
@@@ -43,7 -43,7 +43,6 @@@
  #include "BLT_translation.h"
  
  #include "BKE_context.h"
- #include "BKE_global.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_group.h"
  #include "BKE_main.h"
  #include "BKE_report.h"
index 33ca6ea74954500f886f78a4a5b968cf6c24b12d,92fb140243f7d50366037e5f605c49b747086371..f128a15ca6f3019105dfdff798f4ed7f2389a1b7
  #include "BKE_sequencer.h"
  #include "BKE_screen.h"
  #include "BKE_scene.h"
+ #include "BKE_undo_system.h"
 +#include "BKE_workspace.h"
 +
 +#include "DEG_depsgraph.h"
  
  #include "WM_api.h"
  #include "WM_types.h"
index fb8dea2af0e3a26d653bcd16f590ed0634b3b61e,120514762f421b03c76611f96b2111f431e226a3..710ee7fcb44fbed9cf7dfb60418d312e10da5d50
  #include "BKE_main.h"
  #include "BKE_paint.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "ED_view3d.h"
+ #include "ED_paint.h"
  
  #include "WM_api.h"
  #include "WM_types.h"
index b7cbdfecfe89ab3c74f4ab9a32a83d10b674319f,cb6dba4772f14b6e116404516405d2e40ce36321..e72dac3b19e372ef00638d500de2736a2bd7673f
  #include "BKE_material.h"
  #include "BKE_node.h"
  #include "BKE_paint.h"
+ #include "BKE_undo_system.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "UI_interface.h"
  #include "UI_view2d.h"
  
@@@ -1215,9 -1189,9 +1223,9 @@@ void ED_imapaint_bucket_fill(struct bCo
  
        paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
  
-       ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+       BKE_undosys_step_push(wm->undo_stack, C, op->type->name);
  
 -      DAG_id_tag_update(&ima->id, 0);
 +      DEG_id_tag_update(&ima->id, 0);
  }
  
  
index d080c324d6cd770212c4a7a4e748fc94fb74ba4a,9d1987943a5bd7ebe6eabce00bdedaa3ed5ca4bc..5308ef0fae8de10a6c54fe20b1e7e86cf88fc1e4
  #include "BLI_threads.h"
  
  #include "DNA_image_types.h"
+ #include "DNA_windowmanager_types.h"
+ #include "DNA_object_types.h"
+ #include "DNA_screen_types.h"
+ #include "DNA_space_types.h"
++#include "DNA_workspace_types.h"
  
  #include "IMB_imbuf.h"
  #include "IMB_imbuf_types.h"
  
  #include "BKE_context.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_image.h"
  #include "BKE_main.h"
+ #include "BKE_global.h"
+ #include "BKE_undo_system.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "ED_paint.h"
  
  #include "GPU_draw.h"
@@@ -352,9 -365,65 +367,66 @@@ void ED_image_undo_push_begin(const cha
  
  void ED_image_undo_push_end(void)
  {
-       ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+       wmWindowManager *wm = G.main->wm.first;  /* XXX, avoids adding extra arg. */
+       BKE_undosys_step_push(wm->undo_stack, NULL, NULL);
+ }
+ static void image_undo_invalidate(void)
+ {
        UndoImageTile *tile;
-       int deallocsize = 0;
+       ListBase *lb = ED_image_undo_get_tiles();
+       for (tile = lb->first; tile; tile = tile->next) {
+               tile->valid = false;
+       }
+ }
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
+ typedef struct ImageUndoStep {
+       UndoStep step;
+       ListBase tiles;
+ } ImageUndoStep;
+ static bool image_undosys_poll(bContext *C)
+ {
++      const WorkSpace *workspace = CTX_wm_workspace(C);
+       Object *obact = CTX_data_active_object(C);
+       ScrArea *sa = CTX_wm_area(C);
+       if (sa && (sa->spacetype == SPACE_IMAGE)) {
+               SpaceImage *sima = (SpaceImage *)sa->spacedata.first;
 -              if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
++              if ((obact && (workspace->object_mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) {
+                       return true;
+               }
+       }
+       else if (sa && (sa->spacetype == SPACE_VIEW3D)) {
 -              if (obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) {
++              if (obact && (workspace->object_mode & OB_MODE_TEXTURE_PAINT)) {
+                       return true;
+               }
+       }
+       return false;
+ }
+ static void image_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+ {
+       ImageUndoStep *us = (ImageUndoStep *)us_p;
+       /* dummy, memory is cleared anyway. */
+       BLI_listbase_clear(&us->tiles);
+ }
+ static bool image_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p)
+ {
+       /* dummy, encoding is done along the way by adding tiles
+        * to the current 'ImageUndoStep' added by encode_init. */
+       ImageUndoStep *us = (ImageUndoStep *)us_p;
+       BLI_assert(us->step.data_size == 0);
        int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
  
        /* first dispose of invalid tiles (may happen due to drag dot for instance) */
index 55950a51fba8df84a671300e466a928eb3c500da,4e2bcab9f369af9cba20075b557b0f1c778df424..7158c0fc88f6e7c0c616d0daff15b4a8d49c7847
@@@ -48,6 -48,8 +48,9 @@@
  #include "DNA_object_types.h"
  #include "DNA_scene_types.h"
  #include "DNA_mesh_types.h"
+ #include "DNA_screen_types.h"
+ #include "DNA_space_types.h"
++#include "DNA_workspace_types.h"
  
  #include "BKE_ccg.h"
  #include "BKE_context.h"
  #include "BKE_key.h"
  #include "BKE_mesh.h"
  #include "BKE_subsurf.h"
 +#include "DEG_depsgraph.h"
+ #include "BKE_global.h"
+ #include "BKE_main.h"
+ #include "BKE_undo_system.h"
  
  #include "WM_api.h"
  #include "WM_types.h"
@@@ -980,7 -995,97 +1002,98 @@@ void sculpt_undo_push_end(void
                        BKE_pbvh_node_layer_disp_free(unode->node);
        }
  
-       ED_undo_paint_push_end(UNDO_PAINT_MESH);
+       wmWindowManager *wm = G.main->wm.first;  /* XXX, avoids adding extra arg. */
+       BKE_undosys_step_push(wm->undo_stack, NULL, NULL);
+ }
+ /* -------------------------------------------------------------------- */
+ /** \name Implements ED Undo System
+  * \{ */
+ typedef struct SculptUndoStep {
+       UndoStep step;
+       /* note: will split out into list for multi-object-sculpt-mode. */
+       UndoSculpt data;
+ } SculptUndoStep;
+ static bool sculpt_undosys_poll(bContext *C)
+ {
+       ScrArea *sa = CTX_wm_area(C);
+       if (sa && (sa->spacetype == SPACE_VIEW3D)) {
++              const WorkSpace *workspace = CTX_wm_workspace(C);
+               Object *obact = CTX_data_active_object(C);
 -              if (obact && (obact->mode & OB_MODE_SCULPT)) {
++              if (obact && (workspace->object_mode & OB_MODE_SCULPT)) {
+                       return true;
+               }
+       }
+       return false;
+ }
+ static void sculpt_undosys_step_encode_init(struct bContext *UNUSED(C), UndoStep *us_p)
+ {
+       SculptUndoStep *us = (SculptUndoStep *)us_p;
+       /* dummy, memory is cleared anyway. */
+       BLI_listbase_clear(&us->data.nodes);
+ }
+ static bool sculpt_undosys_step_encode(struct bContext *UNUSED(C), UndoStep *us_p)
+ {
+       /* dummy, encoding is done along the way by adding tiles
+        * to the current 'SculptUndoStep' added by encode_init. */
+       SculptUndoStep *us = (SculptUndoStep *)us_p;
+       us->step.data_size = us->data.undo_size;
+       return true;
+ }
+ static void sculpt_undosys_step_decode(struct bContext *C, UndoStep *us_p, int UNUSED(dir))
+ {
+       /* TODO(campbell): undo_system: use low-level API to set mode. */
+       ED_object_mode_set(C, OB_MODE_SCULPT);
+       BLI_assert(sculpt_undosys_poll(C));
+       SculptUndoStep *us = (SculptUndoStep *)us_p;
+       sculpt_undo_restore_list(C, &us->data.nodes);
+ }
  
-       WM_file_tag_modified();
+ static void sculpt_undosys_step_free(UndoStep *us_p)
+ {
+       SculptUndoStep *us = (SculptUndoStep *)us_p;
+       sculpt_undo_free_list(&us->data.nodes);
  }
+ /* Export for ED_undo_sys. */
+ void ED_sculpt_undosys_type(UndoType *ut)
+ {
+       ut->name = "Sculpt";
+       ut->poll = sculpt_undosys_poll;
+       ut->step_encode_init = sculpt_undosys_step_encode_init;
+       ut->step_encode = sculpt_undosys_step_encode;
+       ut->step_decode = sculpt_undosys_step_decode;
+       ut->step_free = sculpt_undosys_step_free;
+       ut->mode = BKE_UNDOTYPE_MODE_ACCUMULATE;
+       ut->use_context = true;
+       ut->step_size = sizeof(SculptUndoStep);
+ }
+ /** \} */
+ /* -------------------------------------------------------------------- */
+ /** \name Utilities
+  * \{ */
+ static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p)
+ {
+       SculptUndoStep *us = (SculptUndoStep *)us_p;
+       return &us->data;
+ }
+ static UndoSculpt *sculpt_undo_get_nodes(void)
+ {
+       wmWindowManager *wm = G.main->wm.first;  /* XXX, avoids adding extra arg. */
+       UndoStep *us = BKE_undosys_stack_init_or_active_with_type(wm->undo_stack, BKE_UNDOSYS_TYPE_SCULPT);
+       return sculpt_undosys_step_get_nodes(us);
+ }
+ /** \} */
index 80ec91079848abd1e81b35a9480a34d90ff51118,0dec95d4340ff1d0a1fdf1e818c82fb55620928d..82768bedc953f776560542a0e11e42b7421091ef
@@@ -48,9 -48,9 +48,8 @@@
  
  #include "BKE_context.h"
  #include "BKE_curve.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_fcurve.h"
  #include "BKE_main.h"
- #include "BKE_global.h"
  #include "BKE_screen.h"
  #include "BKE_unit.h"
  
index 49cfc4b71b074900aef5008123b9e30064b49643,8c5be7c9d04fd4c1fc6958f94b036a21a261eea9..583beef5001dd6d9ae7a8764cc81c2ea68db17ee
@@@ -42,8 -42,7 +42,7 @@@
  #include "BKE_context.h"
  #include "BKE_constraint.h"
  #include "BKE_tracking.h"
- #include "BKE_global.h"
 -#include "BKE_depsgraph.h"
 +#include "BKE_layer.h"
  #include "BKE_object.h"
  #include "BKE_report.h"
  
index 6bbec6a1a48697114c6f35f39f2dc79dbf86ead5,71edd855cf082ea784d6491eadd65490f2253c47..93e9b77a837041b6682bd6d249badf400122e3fe
@@@ -51,9 -51,8 +51,8 @@@
  
  #include "BKE_animsys.h"
  #include "BKE_context.h"
- #include "BKE_global.h"
 -#include "BKE_depsgraph.h"
  #include "BKE_idcode.h"
 +#include "BKE_layer.h"
  #include "BKE_library.h"
  #include "BKE_library_query.h"
  #include "BKE_library_remap.h"
index 5d267767cf93f82ddacf7a293a328392b502d16c,adcd3a29bd09c972e1e51d2728de168923ed5d98..3ccf65a8a69b36fc42d5fcaf1ce954326fc013c3
@@@ -2008,9 -2022,8 +2008,9 @@@ static void createTransParticleVerts(bC
  void flushTransParticles(TransInfo *t)
  {
        Scene *scene = t->scene;
 -      Object *ob = OBACT;
 +      ViewLayer *view_layer = t->view_layer;
 +      Object *ob = OBACT(view_layer);
-       PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+       PTCacheEdit *edit = PE_get_current(scene, ob);
        ParticleSystem *psys = edit->psys;
        ParticleSystemModifierData *psmd = NULL;
        PTCacheEditPoint *point;
@@@ -6547,10 -6554,10 +6547,10 @@@ void special_aftertrans_update(bContex
        else if (t->options & CTX_PAINT_CURVE) {
                /* pass */
        }
 -      else if ((t->scene->basact) &&
 -               (ob = t->scene->basact->object) &&
 -               (ob->mode & OB_MODE_PARTICLE_EDIT) &&
 +      else if ((t->view_layer->basact) &&
 +               (ob = t->view_layer->basact->object) &&
 +               (t->eval_ctx.object_mode & OB_MODE_PARTICLE_EDIT) &&
-                PE_get_current(t->scene, t->view_layer, ob))
+                PE_get_current(t->scene, ob))
        {
                /* do nothing */
        }
@@@ -8304,11 -8311,10 +8304,11 @@@ void createTransData(bContext *C, Trans
                                        createTransPose(t, ob_armature);
                                }
                        }
 -                      
                }
        }
 -      else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT) && PE_start_edit(PE_get_current(scene, ob))) {
 +      else if (ob && (t->eval_ctx.object_mode & OB_MODE_PARTICLE_EDIT) &&
-                PE_start_edit(PE_get_current(scene, view_layer, ob)))
++               PE_start_edit(PE_get_current(scene, ob)))
 +      {
                createTransParticleVerts(C, t);
                t->flag |= T_POINTS;
  
index fbe9c2ef2405521aae92b450f8c4e1c651f36ae8,618b8a3732058d36f685d01977e32a4b5c15e37f..e051b401f8762ec844e441403822437dd440f5ab
@@@ -899,11 -893,9 +899,11 @@@ static void recalcData_objects(TransInf
                        BIK_clear_data(ob->pose);
                }
                else
 -                      BKE_pose_where_is(t->scene, ob);
 +                      BKE_pose_where_is(&t->eval_ctx, t->scene, ob);
        }
 -      else if (base && (base->object->mode & OB_MODE_PARTICLE_EDIT) && PE_get_current(t->scene, base->object)) {
 +      else if (base && (t->eval_ctx.object_mode & OB_MODE_PARTICLE_EDIT) &&
-                PE_get_current(t->scene, t->view_layer, base->object))
++               PE_get_current(t->scene, base->object))
 +      {
                if (t->state != TRANS_CANCEL) {
                        applyProject(t);
                }
index 1839583015c841539b1413b47cb0beaf0deca857,193a29928ef3555ddc53aafabd26b02216b7acec..cb5b17b415ee16c77551ceb76a26bbb051feaa80
@@@ -972,11 -558,11 +972,11 @@@ static int calc_manipulator_stats
                        mul_m4_v3(ob->obmat, tbounds->max);
                }
        }
 -      else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
 +      else if (ob && (workspace->object_mode & OB_MODE_ALL_PAINT)) {
                /* pass */
        }
 -      else if (ob && ob->mode & OB_MODE_PARTICLE_EDIT) {
 +      else if (ob && workspace->object_mode & OB_MODE_PARTICLE_EDIT) {
-               PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+               PTCacheEdit *edit = PE_get_current(scene, ob);
                PTCacheEditPoint *point;
                PTCacheEditKey *ek;
                int k;
index 7a5b8bfbda1bdc227727f2234385953fbaa6ae7f,03d0b4a8d48504e9ea05dd36c13e07e2fe497448..4bec0d9f11470435dc30f3cd60d970286d284580
@@@ -60,8 -58,7 +60,9 @@@
  #include "BKE_packedFile.h"
  #include "BKE_paint.h"
  #include "BKE_screen.h"
 +#include "BKE_workspace.h"
 +#include "BKE_layer.h"
+ #include "BKE_undo_system.h"
  
  #include "ED_armature.h"
  #include "ED_buttons.h"
  void ED_editors_init(bContext *C)
  {
        wmWindowManager *wm = CTX_wm_manager(C);
 -      Main *bmain = CTX_data_main(C);
 -      Scene *sce = CTX_data_scene(C);
 -      Object *ob, *obact = (sce && sce->basact) ? sce->basact->object : NULL;
 -      ID *data;
  
+       if (wm->undo_stack == NULL) {
+               wm->undo_stack = BKE_undosys_stack_create();
+       }
        /* This is called during initialization, so we don't want to store any reports */
        ReportList *reports = CTX_wm_reports(C);
        int reports_flag_prev = reports->flag & ~RPT_STORE;
@@@ -150,24 -130,34 +154,30 @@@ void ED_editors_exit(bContext *C
  
        if (!bmain)
                return;
--      
++
        /* frees all editmode undos */
-       undo_editmode_clear();
-       ED_undo_paint_free();
+       if (G.main->wm.first) {
+               wmWindowManager *wm = G.main->wm.first;
+               /* normally we don't check for NULL undo stack, do here since it may run in different context. */
+               if (wm->undo_stack) {
+                       BKE_undosys_stack_destroy(wm->undo_stack);
+                       wm->undo_stack = NULL;
+               }
+       }
  
 -      for (sce = bmain->scene.first; sce; sce = sce->id.next) {
 -              if (sce->obedit) {
 -                      Object *ob = sce->obedit;
 -              
 -                      if (ob) {
 -                              if (ob->type == OB_MESH) {
 -                                      Mesh *me = ob->data;
 -                                      if (me->edit_btmesh) {
 -                                              EDBM_mesh_free(me->edit_btmesh);
 -                                              MEM_freeN(me->edit_btmesh);
 -                                              me->edit_btmesh = NULL;
 -                                      }
 -                              }
 -                              else if (ob->type == OB_ARMATURE) {
 -                                      ED_armature_edit_free(ob->data);
 -                              }
 +      for (Object *ob = bmain->object.first; ob; ob = ob->id.next) {
 +              if (ob->type == OB_MESH) {
 +                      Mesh *me = ob->data;
 +                      if (me->edit_btmesh) {
 +                              EDBM_mesh_free(me->edit_btmesh);
 +                              MEM_freeN(me->edit_btmesh);
 +                              me->edit_btmesh = NULL;
 +                      }
 +              }
 +              else if (ob->type == OB_ARMATURE) {
 +                      bArmature *arm = ob->data;
 +                      if (arm->edbo) {
 +                              ED_armature_edit_free(ob->data);
                        }
                }
        }
index b7101e7ae99424d9af73f382244200a9f1daff27,fea3360a39c80cde703c8d0177697d22c40002fc..99e90eb73e8af3963a9f15f71ce50d99673e1dd3
  #include "BKE_blender_undo.h"
  #include "BKE_context.h"
  #include "BKE_global.h"
 +#include "BKE_library_override.h"
  #include "BKE_main.h"
  #include "BKE_screen.h"
+ #include "BKE_undo_system.h"
  
 +#include "DEG_depsgraph.h"
 +
  #include "ED_armature.h"
  #include "ED_particle.h"
  #include "ED_curve.h"
index cc1db43758b01f4d2d442a0a0c6eb48db54c52f9,20470ba862e5feee2ea359f29169f2d9ee2c3167..f03ff4ba8b72f3d21bd8177c589f6add4364ac1e
@@@ -155,11 -155,10 +156,13 @@@ typedef struct wmWindowManager 
        ListBase timers;                  /* active timers */
        struct wmTimer *autosavetimer;    /* timer for auto save */
  
+       struct UndoStack *undo_stack;     /* all undo history (runtime only). */
        char is_interface_locked;               /* indicates whether interface is locked for user interaction */
        char par[7];
 +
 +      struct wmMsgBus *message_bus;
 +
  } wmWindowManager;
  
  /* wmWindowManager.initialized */
index 06c0260d08f41c582a0aab241b77bf79b5d3a1e3,6dbfc3634b250916a92901626116f3bcedbdf050..69237cad855d38f21c0a0c8a2234c8bf4640b8f8
@@@ -155,12 -152,10 +155,12 @@@ static PointerRNA rna_ParticleBrush_cur
        return rna_pointer_inherit_refine(ptr, &RNA_CurveMapping, NULL);
  }
  
 -static void rna_ParticleEdit_redo(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
 +static void rna_ParticleEdit_redo(bContext *C, PointerRNA *UNUSED(ptr))
  {
 -      Object *ob = (scene->basact) ? scene->basact->object : NULL;
 +      Scene *scene = CTX_data_scene(C);
 +      ViewLayer *view_layer = CTX_data_view_layer(C);
 +      Object *ob = OBACT(view_layer);
-       PTCacheEdit *edit = PE_get_current(scene, view_layer, ob);
+       PTCacheEdit *edit = PE_get_current(scene, ob);
  
        if (!edit)
                return;
@@@ -181,10 -174,10 +181,10 @@@ static void rna_ParticleEdit_tool_set(P
        ParticleEditSettings *pset = (ParticleEditSettings *)ptr->data;
        
        /* redraw hair completely if weight brush is/was used */
-       if ((pset->brushtype == PE_BRUSH_WEIGHT || value == PE_BRUSH_WEIGHT) && pset->view_layer) {
-               Object *ob = (pset->view_layer->basact) ? pset->view_layer->basact->object : NULL;
 -      if ((pset->brushtype == PE_BRUSH_WEIGHT || value == PE_BRUSH_WEIGHT) && pset->scene) {
 -              Object *ob = (pset->scene->basact) ? pset->scene->basact->object : NULL;
++      if ((pset->brushtype == PE_BRUSH_WEIGHT || value == PE_BRUSH_WEIGHT) && pset->object) {
++              Object *ob = pset->object;
                if (ob) {
 -                      DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
 +                      DEG_id_tag_update(&ob->id, OB_RECALC_DATA);
                        WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, NULL);
                }
        }
index 630f858099ff9494be5d9b4295b877db528bcd04,b2df53321c01e19e4a689382ff5f972e24088259..4a4a993b38663d4f9d859a033d6e63b7346c5d44
@@@ -774,12 -703,9 +768,9 @@@ static void wm_operator_reports(bContex
                        CTX_wm_region_set(C, ar_prev);
                }
        }
 -
 +      
        if (retval & OPERATOR_FINISHED) {
-               if (G.debug & G_DEBUG_WM) {
-                       /* todo - this print may double up, might want to check more flags then the FINISHED */
-                       wm_operator_print(C, op);
-               }
+               CLOG_STR_INFO_N(WM_LOG_OPERATORS, 1, WM_operator_pystring(C, op, false, true));
  
                if (caller_owns_reports == false) {
                        BKE_reports_print(op->reports, RPT_DEBUG); /* print out reports to console. */
@@@ -1203,11 -1125,12 +1190,12 @@@ static int wm_operator_invoke
                        WM_operator_last_properties_init(op);
                }
  
-               if ((G.debug & G_DEBUG_HANDLERS) && ((event == NULL) || (event->type != MOUSEMOVE))) {
-                       printf("%s: handle evt %d region %p op %s\n",
-                              __func__, event ? event->type : 0, CTX_wm_screen(C)->active_region, ot->idname);
+               if ((event == NULL) || (event->type != MOUSEMOVE)) {
+                       CLOG_INFO(WM_LOG_HANDLERS, 2,
 -                                "handle evt %d win %d op %s",
 -                                event ? event->type : 0, CTX_wm_screen(C)->subwinactive, ot->idname);
++                                "handle evt %d win %p op %s",
++                                event ? event->type : 0, CTX_wm_screen(C)->active_region, ot->idname);
                }
-               
                if (op->type->invoke && event) {
                        wm_region_mouse_co(C, event);
  
index e673b1d386b693dbdf7147e04388f66174f0c01f,1d96d291dc45ffebe32b00694a2e60a6f978d780..bb9ff0ab8ebb01ca573fc0d43af5a1e059a7a74b
@@@ -87,7 -87,7 +87,8 @@@
  #include "BKE_sound.h"
  #include "BKE_scene.h"
  #include "BKE_screen.h"
+ #include "BKE_undo_system.h"
 +#include "BKE_workspace.h"
  
  #include "BLO_readfile.h"
  #include "BLO_writefile.h"
index 03bc1ae0a02f4544f8f0678e61e67777e5080cab,b9ac05e0c57582180e5057b197c329fb89c8fb00..534b20ff22ebd321816ecd359a5c8306f93afbec
@@@ -169,10 -167,8 +172,10 @@@ void WM_init(bContext *C, int argc, con
        wm_operatortype_init();
        WM_menutype_init();
        WM_uilisttype_init();
 +      wm_manipulatortype_init();
 +      wm_manipulatorgrouptype_init();
  
-       BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback);
+       ED_undosys_type_init();
  
        BKE_library_callback_free_window_manager_set(wm_close_and_free);   /* library.c */
        BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference);   /* library.c */
@@@ -608,8 -582,17 +614,6 @@@ void WM_exit_ext(bContext *C, const boo
        (void)do_python;
  #endif
  
-       BKE_undo_reset();
-       
 -      if (!G.background) {
 -#ifdef WITH_OPENSUBDIV
 -              BKE_subsurf_osd_cleanup();
 -#endif
 -
 -              GPU_global_buffer_pool_free();
 -              GPU_free_unused_buffers();
 -
 -              GPU_exit();
 -      }
 -
        ED_file_exit(); /* for fsmenu */
  
        UI_exit();
index e86e80dddf6285eca5ffc0fdc0a4f77d010279b2,bcfc97a1e235f987bc6e78b4f6d2444be57ab227..0db67e0b199b01b6e79b6f5069694e01be4638d0
  #include "DNA_space_types.h"
  #include "DNA_userdef_types.h"
  #include "DNA_windowmanager_types.h"
 +#include "DNA_workspace_types.h"
  
  #include "MEM_guardedalloc.h"
+ #include "CLG_log.h"
  
  #include "BLI_blenlib.h"
  #include "BLI_utildefines.h"
index 782d0c502a4b55b1862d057f9b5550a423209cd7,b05b25967190d9285e8c693ec67b52c1c61d0f31..ebe68bc8f35f62ddb98f759fedb3212b869062fe
@@@ -174,19 -169,12 +176,18 @@@ static wmOperatorType *wm_operatortype_
        /* Set the default i18n context now, so that opfunc can redefine it if needed! */
        RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
        ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
 -      opfunc(ot);
  
 +      return ot;
 +}
 +static void wm_operatortype_append__end(wmOperatorType *ot)
 +{
        if (ot->name == NULL) {
-               fprintf(stderr, "ERROR: Operator %s has no name property!\n", ot->idname);
-               ot->name = N_("Dummy Name");
+               CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname);
        }
  
 +      /* Allow calling _begin without _end in operatortype creation. */
 +      WM_operatortype_props_advanced_end(ot);
 +
        /* XXX All ops should have a description but for now allow them not to. */
        RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
        RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
Simple merge
Simple merge
Simple merge