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.
This commit is contained in:
Campbell Barton 2015-02-10 05:45:57 +11:00
parent 2fe9e3c1f0
commit 31e26bb83b
Notes: blender-bot 2023-02-14 09:34:20 +01:00
Referenced by commit 4b847595ee, Fix T44217: Crash when starting .blend without "Load UI" enabled
Referenced by issue #43424, undo changes the active scene
2 changed files with 75 additions and 10 deletions

View File

@ -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 */

View File

@ -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;