diff options
author | Campbell Barton <ideasman42@gmail.com> | 2015-02-09 21:45:57 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2015-02-09 21:51:05 +0300 |
commit | 31e26bb83bd0a538c76fd8bb6ebce65027dde94c (patch) | |
tree | 7a58e52c4ab98149eab81e6fb9db67d9458a2f7e | |
parent | 2fe9e3c1f0fd968bb214e13763b58a35f637caa9 (diff) |
Fix T43424: undo changes the active scene
Using different scenes with 2+ windows broke entirely using undo.
Now keep track of the current windows scene in each undo-file,
and ensure the undo-scene is on a visible window when undo is executed,
switching the scene only when its not in a visible window.
-rw-r--r-- | source/blender/blenkernel/intern/blender.c | 49 | ||||
-rw-r--r-- | source/blender/blenloader/intern/writefile.c | 36 |
2 files changed, 75 insertions, 10 deletions
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index fb02af1be20..dda790ea700 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -185,6 +185,17 @@ static void clean_paths(Main *main) } } +static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene) +{ + wmWindow *win; + for (win = wm->windows.first; win; win = win->next) { + if (win->screen->scene == scene) { + return true; + } + } + return false; +} + /* context matching */ /* handle no-ui case */ @@ -228,24 +239,54 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath /* no load screens? */ if (mode != LOAD_UI) { + /* Logic for 'track_undo_scene' is to keep using the scene which the active screen has, + * as long as the scene associated with the undo operation is visible in one of the open windows. + * + * - 'curscreen->scene' - scene the user is currently looking at. + * - 'bfd->curscene' - scene undo-step was created in. + * + * This means users can have 2+ windows open and undo in both without screens switching. + * But if they close one of the screens, + * undo will ensure that the scene being operated on will be activated + * (otherwise we'd be undoing on an off-screen scene which isn't acceptable). + * see: T43424 + */ + bool track_undo_scene; + /* comes from readfile.c */ SWAP(ListBase, G.main->wm, bfd->main->wm); SWAP(ListBase, G.main->screen, bfd->main->screen); SWAP(ListBase, G.main->script, bfd->main->script); - /* we re-use current screen */ curscreen = CTX_wm_screen(C); - /* but use new Scene pointer */ - curscene = bfd->curscene; + + track_undo_scene = (mode == LOAD_UNDO && curscreen && bfd->main->wm.first); + if (track_undo_scene) { + curscene = curscreen->scene; + } + else { + /* but use new Scene pointer */ + curscene = bfd->curscene; + } + if (curscene == NULL) curscene = bfd->main->scene.first; /* empty file, we add a scene to make Blender work */ if (curscene == NULL) curscene = BKE_scene_add(bfd->main, "Empty"); - + /* and we enforce curscene to be in current screen */ if (curscreen) curscreen->scene = curscene; /* can run in bgmode */ /* clear_global will free G.main, here we can still restore pointers */ blo_lib_link_screen_restore(bfd->main, curscreen, curscene); + curscene = curscreen->scene; + + if (track_undo_scene) { + wmWindowManager *wm = bfd->main->wm.first; + if (wm_scene_is_visible(wm, bfd->curscene) == false) { + curscene = bfd->curscene; + curscreen->scene = curscene; + } + } } /* free G.main Main database */ diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 3eeb30ac5d0..e671e102f0b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -909,16 +909,39 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) write_node_socket_interface(wd, ntree, sock); } -static void current_screen_compat(Main *mainvar, bScreen **screen) +/** + * Take care using 'use_active_win', since we wont want the currently active window + * to change which scene renders (currently only used for undo). + */ +static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_active_win) { wmWindowManager *wm; - wmWindow *window; + wmWindow *window = NULL; /* find a global current screen in the first open window, to have * a reasonable default for reading in older versions */ wm = mainvar->wm.first; - window = (wm) ? wm->windows.first : NULL; - *screen = (window) ? window->screen : NULL; + + if (wm) { + if (use_active_win) { + /* write the active window into the file, needed for multi-window undo T43424 */ + for (window = wm->windows.first; window; window = window->next) { + if (window->active) { + break; + } + } + + /* fallback */ + if (window == NULL) { + window = wm->windows.first; + } + } + else { + window = wm->windows.first; + } + } + + *r_screen = (window) ? window->screen : NULL; } typedef struct RenderInfo { @@ -937,7 +960,7 @@ static void write_renderinfo(WriteData *wd, Main *mainvar) RenderInfo data; /* XXX in future, handle multiple windows with multiple screens? */ - current_screen_compat(mainvar, &curscreen); + current_screen_compat(mainvar, &curscreen, false); if (curscreen) curscene = curscreen->scene; for (sce= mainvar->scene.first; sce; sce= sce->id.next) { @@ -3437,6 +3460,7 @@ static void write_linestyles(WriteData *wd, ListBase *idbase) * - for undofile, curscene needs to be saved */ static void write_global(WriteData *wd, int fileflags, Main *mainvar) { + const bool is_undo = (wd->current != NULL); FileGlobal fg; bScreen *screen; char subvstr[8]; @@ -3446,7 +3470,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) memset(fg.filename, 0, sizeof(fg.filename)); memset(fg.build_hash, 0, sizeof(fg.build_hash)); - current_screen_compat(mainvar, &screen); + current_screen_compat(mainvar, &screen, is_undo); /* XXX still remap G */ fg.curscreen= screen; |