diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 9e0d3b7a419..50363e3f42a 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3932,5 +3932,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) { /* Versioning code until next subversion bump goes here. */ + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + sa->flag &= ~AREA_FLAG_UNUSED_6; + } + } } } diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c index 8bc84388a1b..cbedb25ea64 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.c @@ -205,7 +205,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) /* we already had a fullscreen here -> mark new space as a stacked fullscreen */ if (sa->full) { - sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE); + sa->flag |= AREA_FLAG_STACKED_FULLSCREEN; } } else { @@ -222,6 +222,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) } } sima = sa->spacedata.first; + sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; /* get the correct image, and scale it */ sima->image = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 41c3a2ca285..ccee88eb0d6 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1947,7 +1947,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi if (sa->spacetype != type) { SpaceType *st; - SpaceLink *slold; + SpaceLink *slold = sa->spacedata.first; SpaceLink *sl; /* store sa->type->exit callback */ void *sa_exit = sa->type ? sa->type->exit : NULL; @@ -1963,7 +1963,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi */ int header_alignment = ED_area_header_alignment_or_fallback(sa, -1); const bool sync_header_alignment = ((header_alignment != -1) && - (sa->flag & AREA_FLAG_TEMP_TYPE) == 0); + ((slold->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0)); /* in some cases (opening temp space) we don't want to * call area exit callback, so we temporarily unset it */ @@ -1979,7 +1979,6 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi } st = BKE_spacetype_from_id(type); - slold = sa->spacedata.first; sa->spacetype = type; sa->type = st; @@ -2010,6 +2009,10 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi slold->regionbase = sa->regionbase; sa->regionbase = sl->regionbase; BLI_listbase_clear(&sl->regionbase); + /* SPACE_FLAG_TYPE_WAS_ACTIVE is only used to go back to a previously active space that is + * overlapped by temporary ones. It's now properly activated, so the flag should be cleared + * at this point. */ + sl->link_flag &= ~SPACE_FLAG_TYPE_WAS_ACTIVE; /* put in front of list */ BLI_remlink(&sa->spacedata, sl); @@ -2073,23 +2076,45 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi ED_area_tag_redraw(sa); } -void ED_area_prevspace(bContext *C, ScrArea *sa) +static SpaceLink *area_get_prevspace(ScrArea *sa) { SpaceLink *sl = sa->spacedata.first; - if (sl && sl->next) { - ED_area_newspace(C, sa, sl->next->spacetype, false); + /* First toggle to the next temporary space in the list. */ + for (SpaceLink *sl_iter = sl->next; sl_iter; sl_iter = sl_iter->next) { + if (sl_iter->link_flag & SPACE_FLAG_TYPE_TEMPORARY) { + return sl_iter; + } + } - /* keep old spacedata but move it to end, so calling - * ED_area_prevspace once more won't open it again */ - BLI_remlink(&sa->spacedata, sl); - BLI_addtail(&sa->spacedata, sl); + /* No temporary space, find the item marked as last active. */ + for (SpaceLink *sl_iter = sl->next; sl_iter; sl_iter = sl_iter->next) { + if (sl_iter->link_flag & SPACE_FLAG_TYPE_WAS_ACTIVE) { + return sl_iter; + } + } + + /* If neither is found, we can just return to the regular previous one. */ + return sl->next; +} + +void ED_area_prevspace(bContext *C, ScrArea *sa) +{ + SpaceLink *sl = sa->spacedata.first; + SpaceLink *prevspace = sl ? area_get_prevspace(sa) : NULL; + + if (prevspace) { + ED_area_newspace(C, sa, prevspace->spacetype, false); + /* We've exited the space, so it can't be considered temporary anymore. */ + sl->link_flag &= ~SPACE_FLAG_TYPE_TEMPORARY; } else { /* no change */ return; } - sa->flag &= ~(AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE); + /* If this is a stacked fullscreen, changing to previous area exits it (meaning we're still in a + * fullscreen, but not in a stacked one). */ + sa->flag &= ~AREA_FLAG_STACKED_FULLSCREEN; ED_area_tag_redraw(sa); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index bbdddfadc30..5b8fd33a4e9 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1115,6 +1115,7 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type) { wmWindow *win = CTX_wm_window(C); ScrArea *newsa = NULL; + SpaceLink *newsl; if (!sa || sa->full == NULL) { newsa = ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED); @@ -1125,15 +1126,14 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type) } BLI_assert(newsa); + newsl = newsa->spacedata.first; - if (sa && (sa->spacetype != type)) { - newsa->flag |= AREA_FLAG_TEMP_TYPE; - } - else { - newsa->flag &= ~AREA_FLAG_TEMP_TYPE; + /* Tag the active space before changing, so we can identify it when user wants to go back. */ + if ((newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) { + newsl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE; } - ED_area_newspace(C, newsa, type, (newsa->flag & AREA_FLAG_TEMP_TYPE)); + ED_area_newspace(C, newsa, type, newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY); return newsa; } @@ -1146,7 +1146,7 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa) BLI_assert(sa->full); if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) { - /* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */ + /* stacked fullscreen -> only go back to previous area and don't toggle out of fullscreen */ ED_area_prevspace(C, sa); } else { @@ -1156,13 +1156,13 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa) void ED_screen_restore_temp_type(bContext *C, ScrArea *sa) { + SpaceLink *sl = sa->spacedata.first; + /* In case nether functions below run. */ ED_area_tag_redraw(sa); - if (sa->flag & AREA_FLAG_TEMP_TYPE) { + if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) { ED_area_prevspace(C, sa); - /* Flag should be cleared now. */ - BLI_assert((sa->flag & AREA_FLAG_TEMP_TYPE) == 0); } if (sa->full) { @@ -1182,7 +1182,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa) * overlaid on top of an existing setup) then return to the previous space */ if (sl->next) { - if (sa->flag & AREA_FLAG_TEMP_TYPE) { + if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) { ED_screen_full_prevspace(C, sa); } else { @@ -1392,14 +1392,15 @@ ScrArea *ED_screen_temp_space_open(bContext *C, if (ctx_sa->full) { sa = ctx_sa; ED_area_newspace(C, ctx_sa, space_type, true); - /* we already had a fullscreen here -> mark new space as a stacked fullscreen */ - sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE); + sa->flag |= AREA_FLAG_STACKED_FULLSCREEN; + ((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; } else if (ctx_sa->spacetype == space_type) { sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED); } else { sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type); + ((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; } break; } diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index bf491e2eaea..ec42e9bd04f 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -461,9 +461,10 @@ enum { /** Update size of regions within the area. */ AREA_FLAG_REGION_SIZE_UPDATE = (1 << 3), AREA_FLAG_ACTIVE_TOOL_UPDATE = (1 << 4), + // AREA_FLAG_UNUSED_5 = (1 << 5), - /** Used to check if we should switch back to prevspace (of a different type). */ - AREA_FLAG_TEMP_TYPE = (1 << 6), + AREA_FLAG_UNUSED_6 = (1 << 6), /* cleared */ + /** * For temporary full-screens (file browser, image editor render) * that are opened above user set full-screens. diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 0f957a946d9..82f6da8bb46 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -79,6 +79,22 @@ typedef struct SpaceLink { char _pad0[6]; } SpaceLink; +/* SpaceLink.link_flag */ +enum { + /** + * The space is not a regular one opened through the editor menu (for example) but spawned by an + * operator to fulfill some task and then disappear again. Can typically be cancelled using Esc, + * but that is handled on the editor level. */ + SPACE_FLAG_TYPE_TEMPORARY = (1 << 0), + /** + * Used to mark a space as active but "overlapped" by temporary fullscreen spaces. Without this + * we wouldn't be able to restore the correct active space after closing temp fullscreens + * reliably if the same space type is opened twice in a fullscreen stack (see T19296). We don't + * actually open the same space twice, we have to pretend it is by managing area order carefully. + */ + SPACE_FLAG_TYPE_WAS_ACTIVE = (1 << 1), +}; + /** \} */ /* -------------------------------------------------------------------- */