Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager/intern/wm_files.c')
-rw-r--r--source/blender/windowmanager/intern/wm_files.c166
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, &params, 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, &params, 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, &params, NULL);
+ if (bfd != NULL) {
+ BKE_blendfile_read_setup_ex(
+ C, bfd, &params, 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, &params, NULL);
+ if (bfd != NULL) {
+ BKE_blendfile_read_setup_ex(C, bfd, &params, NULL, true, NULL);
+ success = true;
+ }
if (use_data && BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);