forked from bartvdbraak/blender
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
This commit is contained in:
parent
2cdebf293d
commit
2cc5af9c55
@ -76,6 +76,8 @@ enum {
|
|||||||
ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4,
|
ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE = 1 << 4,
|
||||||
/** Do not remap library override pointers. */
|
/** Do not remap library override pointers. */
|
||||||
ID_REMAP_SKIP_OVERRIDE_LIBRARY = 1 << 5,
|
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,
|
/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately,
|
||||||
|
@ -422,6 +422,7 @@ static void libblock_remap_data(
|
|||||||
FOREACH_MAIN_ID_END;
|
FOREACH_MAIN_ID_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((remap_flags & ID_REMAP_SKIP_USER_CLEAR) == 0) {
|
||||||
/* XXX We may not want to always 'transfer' fake-user from old to new id...
|
/* XXX We may not want to always 'transfer' fake-user from old to new id...
|
||||||
* Think for now it's desired behavior though,
|
* Think for now it's desired behavior though,
|
||||||
* we can always add an option (flag) to control this later if needed. */
|
* we can always add an option (flag) to control this later if needed. */
|
||||||
@ -431,6 +432,7 @@ static void libblock_remap_data(
|
|||||||
}
|
}
|
||||||
|
|
||||||
id_us_clear_real(old_id);
|
id_us_clear_real(old_id);
|
||||||
|
}
|
||||||
|
|
||||||
if (new_id && (new_id->tag & LIB_TAG_INDIRECT) &&
|
if (new_id && (new_id->tag & LIB_TAG_INDIRECT) &&
|
||||||
(r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
|
(r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) {
|
||||||
@ -479,13 +481,15 @@ void BKE_libblock_remap_locked(Main *bmain, void *old_idv, void *new_idv, const
|
|||||||
skipped_direct = id_remap_data.skipped_direct;
|
skipped_direct = id_remap_data.skipped_direct;
|
||||||
skipped_refcounted = id_remap_data.skipped_refcounted;
|
skipped_refcounted = id_remap_data.skipped_refcounted;
|
||||||
|
|
||||||
|
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
|
/* 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...
|
* count has actually been incremented for that, we have to decrease once more its user
|
||||||
* unless we had to skip some 'user_one' cases. */
|
* count... unless we had to skip some 'user_one' cases. */
|
||||||
if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) &&
|
if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) &&
|
||||||
!(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
|
!(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) {
|
||||||
id_us_clear_real(old_id);
|
id_us_clear_real(old_id);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (old_id->us - skipped_refcounted < 0) {
|
if (old_id->us - skipped_refcounted < 0) {
|
||||||
CLOG_ERROR(&LOG,
|
CLOG_ERROR(&LOG,
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
#include "BKE_idprop.h"
|
#include "BKE_idprop.h"
|
||||||
#include "BKE_lib_id.h"
|
#include "BKE_lib_id.h"
|
||||||
#include "BKE_lib_override.h"
|
#include "BKE_lib_override.h"
|
||||||
|
#include "BKE_lib_remap.h"
|
||||||
#include "BKE_main.h"
|
#include "BKE_main.h"
|
||||||
#include "BKE_packedFile.h"
|
#include "BKE_packedFile.h"
|
||||||
#include "BKE_report.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 *oldwm = current_wm_list->first;
|
||||||
wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */
|
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;
|
bool has_match = false;
|
||||||
|
|
||||||
/* this code could move to setup_appdata */
|
/* this code could move to setup_appdata */
|
||||||
|
Loading…
Reference in New Issue
Block a user