diff options
author | Campbell Barton <ideasman42@gmail.com> | 2021-03-11 16:34:23 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2021-03-11 16:40:52 +0300 |
commit | 2cc5af9c553cfc00b7d4616445ad954597a92d94 (patch) | |
tree | ccc0fa74bd5df7ed9d20867832997f1b8d6c82f3 /source | |
parent | 2cdebf293d4cf925e1cdaf5c4a247b8886c1026e (diff) |
Fix T86431: Keep memory location of the window manager on file load
Keep the pointer location from the initial window-manager
between file load operations.
This is needed as the Python API may hold references to keymaps for e.g.
which are transferred to the newly loaded window manager,
without their `PointerRNA.owner_id` fields being updated.
Since there is only ever one window manager, keep the memory at the same location so the Python ID pointers stay valid.
Reviewed By: mont29
Ref D10690
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/blenkernel/BKE_lib_remap.h | 2 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/lib_remap.c | 32 | ||||
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 24 |
3 files changed, 44 insertions, 14 deletions
diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index a8d75213d39..6e81273b82b 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -76,6 +76,8 @@ enum { ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4, /** Do not remap library override pointers. */ ID_REMAP_SKIP_OVERRIDE_LIBRARY = 1 << 5, + /** Don't touch the user count (use for low level actions such as swapping pointers). */ + ID_REMAP_SKIP_USER_CLEAR = 1 << 6, }; /* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 56f7bb0be6f..0218cb913a8 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -422,15 +422,17 @@ static void libblock_remap_data( FOREACH_MAIN_ID_END; } - /* XXX We may not want to always 'transfer' fake-user from old to new id... - * Think for now it's desired behavior though, - * we can always add an option (flag) to control this later if needed. */ - if (old_id && (old_id->flag & LIB_FAKEUSER)) { - id_fake_user_clear(old_id); - id_fake_user_set(new_id); - } + if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) { + /* XXX We may not want to always 'transfer' fake-user from old to new id... + * Think for now it's desired behavior though, + * we can always add an option (flag) to control this later if needed. */ + if (old_id && (old_id->flag & LIB_FAKEUSER)) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } - id_us_clear_real(old_id); + id_us_clear_real(old_id); + } if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) { @@ -479,12 +481,14 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const skipped_direct = id_remap_data.skipped_direct; skipped_refcounted = id_remap_data.skipped_refcounted; - /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user - * count has actually been incremented for that, we have to decrease once more its user count... - * unless we had to skip some 'user_one' cases. */ - if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && - !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { - id_us_clear_real(old_id); + if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) { + /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user + * count has actually been incremented for that, we have to decrease once more its user + * count... unless we had to skip some 'user_one' cases. */ + if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && + !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { + id_us_clear_real(old_id); + } } if (old_id->us - skipped_refcounted < 0) { diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 2d1342da2fb..bd220e2ff95 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -81,6 +81,7 @@ #include "BKE_idprop.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" +#include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_packedFile.h" #include "BKE_report.h" @@ -296,6 +297,29 @@ static void wm_window_match_replace_by_file_wm(bContext *C, { wmWindowManager *oldwm = current_wm_list->first; wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */ + + /* Support window-manager ID references being held between file load operations by keeping + * #Main.wm.first memory address in-place, while swapping all of it's contents. + * + * This is needed so items such as key-maps can be held by an add-on, + * without it pointing to invalid memory, see: T86431 */ + { + /* Referencing the window-manager pointer from elsewhere in the file is highly unlikely + * however it's possible with ID-properties & animation-drivers. + * At some point we could check on disallowing this since it doesn't seem practical. */ + Main *bmain = G_MAIN; + BLI_assert(bmain->relations == NULL); + BKE_libblock_remap(bmain, wm, oldwm, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_USER_CLEAR); + + /* Simple pointer swapping step. */ + BLI_remlink(current_wm_list, oldwm); + BLI_remlink(readfile_wm_list, wm); + SWAP(wmWindowManager, *oldwm, *wm); + SWAP(wmWindowManager *, oldwm, wm); + BLI_addhead(current_wm_list, oldwm); + BLI_addhead(readfile_wm_list, wm); + } + bool has_match = false; /* this code could move to setup_appdata */ |