diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_files.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_files.c | 166 |
1 files changed, 101 insertions, 65 deletions
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 13f3afdfc4c..227520ed3f9 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,36 @@ 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); + + /* Maintain the undo-depth between file loads. Useful so Python can perform + * nested operator calls that exit with the proper undo-depth. */ + wm->op_undo_depth = oldwm->op_undo_depth; + + /* 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); + + /* Don't leave the old pointer in the context. */ + CTX_wm_manager_set(C, wm); + } + bool has_match = false; /* this code could move to setup_appdata */ @@ -713,8 +744,6 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) WM_cursor_wait(true); - wm_file_read_pre(C, use_data, use_userdef); - /* first try to append data from exotic file formats... */ /* it throws error box when file doesn't exist and returns -1 */ /* note; it should set some error message somewhere... (ton) */ @@ -722,58 +751,60 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) /* we didn't succeed, now try to read Blender file */ if (retval == BKE_READ_EXOTIC_OK_BLEND) { - const int G_f_orig = G.f; - ListBase wmbase; - - /* put aside screens to match with persistent windows later */ - /* also exit screens and editors */ - wm_window_match_init(C, &wmbase); + const struct BlendFileReadParams params = { + .is_startup = false, + /* Loading preferences when the user intended to load a regular file is a security + * risk, because the excluded path list is also loaded. Further it's just confusing + * if a user loads a file and various preferences change. */ + .skip_flags = BLO_READ_SKIP_USERDEF, + }; + + struct BlendFileData *bfd = BKE_blendfile_read(filepath, ¶ms, reports); + if (bfd != NULL) { + wm_file_read_pre(C, use_data, use_userdef); + + /* Put aside screens to match with persistent windows later, + * also exit screens and editors. */ + ListBase wmbase; + wm_window_match_init(C, &wmbase); + + /* This flag is initialized by the operator but overwritten on read. + * need to re-enable it here else drivers + registered scripts wont work. */ + const int G_f_orig = G.f; + + BKE_blendfile_read_setup(C, bfd, ¶ms, reports); + + if (G.f != G_f_orig) { + const int flags_keep = G_FLAG_ALL_RUNTIME; + G.f &= G_FLAG_ALL_READFILE; + G.f = (G.f & ~flags_keep) | (G_f_orig & flags_keep); + } - /* confusing this global... */ - G.relbase_valid = 1; - success = BKE_blendfile_read( - C, - filepath, - /* Loading preferences when the user intended to load a regular file is a security risk, - * because the excluded path list is also loaded. - * Further it's just confusing if a user loads a file and various preferences change. */ - &(const struct BlendFileReadParams){ - .is_startup = false, - .skip_flags = BLO_READ_SKIP_USERDEF, - }, - reports); - - /* BKE_file_read sets new Main into context. */ - Main *bmain = CTX_data_main(C); - - /* when loading startup.blend's, we can be left with a blank path */ - if (BKE_main_blendfile_path(bmain)[0] != '\0') { - G.save_over = 1; - } - else { - G.save_over = 0; - G.relbase_valid = 0; - } + /* #BKE_blendfile_read_result_setup sets new Main into context. */ + Main *bmain = CTX_data_main(C); - /* this flag is initialized by the operator but overwritten on read. - * need to re-enable it here else drivers + registered scripts wont work. */ - if (G.f != G_f_orig) { - const int flags_keep = G_FLAG_ALL_RUNTIME; - G.f &= G_FLAG_ALL_READFILE; - G.f = (G.f & ~flags_keep) | (G_f_orig & flags_keep); - } + /* When recovering a session from an unsaved file, this can have a blank path. */ + if (BKE_main_blendfile_path(bmain)[0] != '\0') { + G.save_over = 1; + G.relbase_valid = 1; + } + else { + G.save_over = 0; + G.relbase_valid = 0; + } - /* match the read WM with current WM */ - wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); - WM_check(C); /* opens window(s), checks keymaps */ + /* match the read WM with current WM */ + wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm); + WM_check(C); /* opens window(s), checks keymaps */ - if (success) { if (do_history_file_update) { wm_history_file_update(); } - } - wm_file_read_post(C, false, false, use_data, use_userdef, false); + wm_file_read_post(C, false, false, use_data, use_userdef, false); + + success = true; + } } #if 0 else if (retval == BKE_READ_EXOTIC_OK_OTHER) { @@ -950,6 +981,9 @@ void wm_homefile_read(bContext *C, #endif /* WITH_PYTHON */ } + /* For regular file loading this only runs after the file is successfully read. + * In the case of the startup file, the in-memory startup file is used as a fallback + * so we know this will work if all else fails. */ wm_file_read_pre(C, use_data, use_userdef); if (use_data) { @@ -1041,15 +1075,17 @@ void wm_homefile_read(bContext *C, if (!use_factory_settings || (filepath_startup[0] != '\0')) { if (BLI_access(filepath_startup, R_OK) == 0) { - success = BKE_blendfile_read_ex(C, - filepath_startup, - &(const struct BlendFileReadParams){ - .is_startup = true, - .skip_flags = skip_flags | BLO_READ_SKIP_USERDEF, - }, - NULL, - update_defaults && use_data, - app_template); + const struct BlendFileReadParams params = { + .is_startup = true, + .skip_flags = skip_flags | BLO_READ_SKIP_USERDEF, + }; + + struct BlendFileData *bfd = BKE_blendfile_read(filepath_startup, ¶ms, NULL); + if (bfd != NULL) { + BKE_blendfile_read_setup_ex( + C, bfd, ¶ms, NULL, update_defaults && use_data, app_template); + success = true; + } } if (success) { is_factory_startup = filepath_startup_is_factory; @@ -1070,16 +1106,16 @@ void wm_homefile_read(bContext *C, } if (success == false) { - success = BKE_blendfile_read_from_memory_ex(C, - datatoc_startup_blend, - datatoc_startup_blend_size, - &(const struct BlendFileReadParams){ - .is_startup = true, - .skip_flags = skip_flags, - }, - NULL, - true, - NULL); + const struct BlendFileReadParams params = { + .is_startup = true, + .skip_flags = skip_flags, + }; + struct BlendFileData *bfd = BKE_blendfile_read_from_memory( + datatoc_startup_blend, datatoc_startup_blend_size, ¶ms, NULL); + if (bfd != NULL) { + BKE_blendfile_read_setup_ex(C, bfd, ¶ms, NULL, true, NULL); + success = true; + } if (use_data && BLI_listbase_is_empty(&wmbase)) { wm_clear_default_size(C); |