Depsgraph: remove EvaluationContext, pass Depsgraph instead.
[blender.git] / source / blender / windowmanager / intern / wm_files.c
index 551b17302feee9ef0c24c4025415b3550c65ccb1..9dcb83244ca86612804c6bb68f21e6c13252efb9 100644 (file)
@@ -62,6 +62,8 @@
 
 #include "BLT_translation.h"
 
+#include "BLF_api.h"
+
 #include "DNA_mesh_types.h" /* only for USE_BMESH_SAVE_AS_COMPAT */
 #include "DNA_object_types.h"
 #include "DNA_space_types.h"
@@ -69,6 +71,7 @@
 #include "DNA_scene_types.h"
 #include "DNA_screen_types.h"
 #include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
 
 #include "BKE_appdir.h"
 #include "BKE_autoexec.h"
@@ -76,7 +79,6 @@
 #include "BKE_blendfile.h"
 #include "BKE_blender_undo.h"
 #include "BKE_context.h"
-#include "BKE_depsgraph.h"
 #include "BKE_global.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
 #include "BKE_sound.h"
 #include "BKE_scene.h"
 #include "BKE_screen.h"
+#include "BKE_undo_system.h"
+#include "BKE_workspace.h"
 
 #include "BLO_readfile.h"
 #include "BLO_writefile.h"
+#include "BLO_undofile.h"  /* to save from an undo memfile */
 
 #include "RNA_access.h"
 #include "RNA_define.h"
 #include "ED_screen.h"
 #include "ED_view3d.h"
 #include "ED_util.h"
+#include "ED_undo.h"
 
 #include "GHOST_C-api.h"
 #include "GHOST_Path-api.h"
 #include "BPY_extern.h"
 #endif
 
+#include "DEG_depsgraph.h"
+
 #include "WM_api.h"
 #include "WM_types.h"
+#include "WM_message.h"
 #include "wm.h"
 #include "wm_files.h"
 #include "wm_window.h"
@@ -158,7 +167,7 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
                        CTX_wm_window_set(C, win);  /* needed by operator close callbacks */
                        WM_event_remove_handlers(C, &win->handlers);
                        WM_event_remove_handlers(C, &win->modalhandlers);
-                       ED_screen_exit(C, win, win->screen);
+                       ED_screen_exit(C, win, WM_window_get_active_screen(win));
                }
        }
        
@@ -173,27 +182,12 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
        CTX_wm_menu_set(C, NULL);
 
        ED_editors_exit(C);
-
-       /* just had return; here from r12991, this code could just get removed?*/
-#if 0
-       if (wm == NULL) return;
-       if (G.fileflags & G_FILE_NO_UI) return;
-       
-       /* we take apart the used screens from non-active window */
-       for (win = wm->windows.first; win; win = win->next) {
-               BLI_strncpy(win->screenname, win->screen->id.name, MAX_ID_NAME);
-               if (win != wm->winactive) {
-                       BLI_remlink(&G.main->screen, win->screen);
-                       //BLI_addtail(screenbase, win->screen);
-               }
-       }
-#endif
 }
 
 static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
 {
        win->ghostwin = oldwin->ghostwin;
-       win->multisamples = oldwin->multisamples;
+       win->gwnctx = oldwin->gwnctx;
        win->active = oldwin->active;
        if (win->active)
                wm->winactive = win;
@@ -202,7 +196,7 @@ static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWi
                GHOST_SetWindowUserData(win->ghostwin, win);    /* pointer back */
 
        oldwin->ghostwin = NULL;
-       oldwin->multisamples = 0;
+       oldwin->gwnctx = NULL;
 
        win->eventstate = oldwin->eventstate;
        oldwin->eventstate = NULL;
@@ -214,102 +208,127 @@ static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWi
        win->posy = oldwin->posy;
 }
 
-/* match old WM with new, 4 cases:
- * 1- no current wm, no read wm: make new default
- * 2- no current wm, but read wm: that's OK, do nothing
- * 3- current wm, but not in file: try match screen names
- * 4- current wm, and wm in file: try match ghostwin
- */
-
-static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
+static void wm_window_match_keep_current_wm(
+        const bContext *C, ListBase *current_wm_list,
+        const bool load_ui,
+        ListBase *r_new_wm_list)
 {
-       wmWindowManager *oldwm, *wm;
-       wmWindow *oldwin, *win;
-       
-       /* cases 1 and 2 */
-       if (BLI_listbase_is_empty(oldwmlist)) {
-               if (G.main->wm.first) {
-                       /* nothing todo */
-               }
-               else {
-                       wm_add_default(C);
-               }
-       }
-       else {
-               /* cases 3 and 4 */
-               
-               /* we've read file without wm..., keep current one entirely alive */
-               if (BLI_listbase_is_empty(&G.main->wm)) {
-                       bScreen *screen = NULL;
-
-                       /* when loading without UI, no matching needed */
-                       if (!(G.fileflags & G_FILE_NO_UI) && (screen = CTX_wm_screen(C))) {
-
-                               /* match oldwm to new dbase, only old files */
-                               for (wm = oldwmlist->first; wm; wm = wm->id.next) {
-                                       
-                                       for (win = wm->windows.first; win; win = win->next) {
-                                               /* all windows get active screen from file */
-                                               if (screen->winid == 0)
-                                                       win->screen = screen;
-                                               else 
-                                                       win->screen = ED_screen_duplicate(win, screen);
-                                               
-                                               BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
-                                               win->screen->winid = win->winid;
-                                       }
-                               }
+       wmWindowManager *wm = current_wm_list->first;
+       bScreen *screen = NULL;
+
+       /* match oldwm to new dbase, only old files */
+       wm->initialized &= ~WM_WINDOW_IS_INITIALIZED;
+
+       /* when loading without UI, no matching needed */
+       if (load_ui && (screen = CTX_wm_screen(C))) {
+               for (wmWindow *win = wm->windows.first; win; win = win->next) {
+                       WorkSpace *workspace;
+
+                       BKE_workspace_layout_find_global(G.main, screen, &workspace);
+                       BKE_workspace_active_set(win->workspace_hook, workspace);
+                       win->scene = CTX_data_scene(C);
+
+                       /* all windows get active screen from file */
+                       if (screen->winid == 0) {
+                               WM_window_set_active_screen(win, workspace, screen);
                        }
-                       
-                       G.main->wm = *oldwmlist;
-                       
-                       /* screens were read from file! */
-                       ED_screens_initialize(G.main->wm.first);
-               }
-               else {
-                       bool has_match = false;
+                       else {
+                               WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
+                               WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(workspace, layout_old, win);
 
-                       /* what if old was 3, and loaded 1? */
-                       /* this code could move to setup_appdata */
-                       oldwm = oldwmlist->first;
-                       wm = G.main->wm.first;
+                               WM_window_set_active_layout(win, workspace, layout_new);
+                       }
 
-                       /* preserve key configurations in new wm, to preserve their keymaps */
-                       wm->keyconfigs = oldwm->keyconfigs;
-                       wm->addonconf = oldwm->addonconf;
-                       wm->defaultconf = oldwm->defaultconf;
-                       wm->userconf = oldwm->userconf;
+                       bScreen *win_screen = WM_window_get_active_screen(win);
+                       win_screen->winid = win->winid;
+               }
+       }
 
-                       BLI_listbase_clear(&oldwm->keyconfigs);
-                       oldwm->addonconf = NULL;
-                       oldwm->defaultconf = NULL;
-                       oldwm->userconf = NULL;
+       *r_new_wm_list = *current_wm_list;
+}
 
-                       /* ensure making new keymaps and set space types */
-                       wm->initialized = 0;
-                       wm->winactive = NULL;
+static void wm_window_match_replace_by_file_wm(
+        bContext *C, ListBase *current_wm_list, ListBase *readfile_wm_list,
+        ListBase *r_new_wm_list)
+{
+       wmWindowManager *oldwm = current_wm_list->first;
+       wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */
+       bool has_match = false;
 
-                       /* only first wm in list has ghostwins */
-                       for (win = wm->windows.first; win; win = win->next) {
-                               for (oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
+       /* this code could move to setup_appdata */
 
-                                       if (oldwin->winid == win->winid) {
-                                               has_match = true;
+       /* preserve key configurations in new wm, to preserve their keymaps */
+       wm->keyconfigs = oldwm->keyconfigs;
+       wm->addonconf = oldwm->addonconf;
+       wm->defaultconf = oldwm->defaultconf;
+       wm->userconf = oldwm->userconf;
 
-                                               wm_window_substitute_old(wm, oldwin, win);
-                                       }
-                               }
-                       }
+       BLI_listbase_clear(&oldwm->keyconfigs);
+       oldwm->addonconf = NULL;
+       oldwm->defaultconf = NULL;
+       oldwm->userconf = NULL;
 
-                       /* make sure at least one window is kept open so we don't lose the context, check T42303 */
-                       if (!has_match) {
-                               oldwin = oldwm->windows.first;
-                               win = wm->windows.first;
+       /* ensure making new keymaps and set space types */
+       wm->initialized = 0;
+       wm->winactive = NULL;
+
+       /* only first wm in list has ghostwins */
+       for (wmWindow *win = wm->windows.first; win; win = win->next) {
+               for (wmWindow *oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
+                       if (oldwin->winid == win->winid) {
+                               has_match = true;
 
                                wm_window_substitute_old(wm, oldwin, win);
                        }
+               }
+       }
+       /* make sure at least one window is kept open so we don't lose the context, check T42303 */
+       if (!has_match) {
+               wm_window_substitute_old(wm, oldwm->windows.first, wm->windows.first);
+       }
+
+       wm_close_and_free_all(C, current_wm_list);
 
-                       wm_close_and_free_all(C, oldwmlist);
+       *r_new_wm_list = *readfile_wm_list;
+}
+
+/**
+ * Match old WM with new, 4 cases:
+ * 1) No current WM, no WM in file: Make new default.
+ * 2) No current WM, but WM in file: Keep current WM, do nothing else.
+ * 3) Current WM, but not in file: Keep current WM, update windows with screens from file.
+ * 4) Current WM, and WM in file: Try to keep current GHOST windows, use WM from file.
+ *
+ * \param r_new_wm_list: Return argument for the wm list to be used from now on.
+ */
+static void wm_window_match_do(
+        bContext *C,
+        ListBase *current_wm_list, ListBase *readfile_wm_list,
+        ListBase *r_new_wm_list)
+{
+       if (BLI_listbase_is_empty(current_wm_list)) {
+               /* case 1 */
+               if (BLI_listbase_is_empty(readfile_wm_list)) {
+                       Main *bmain = CTX_data_main(C);
+                       /* Neither current, no newly read file have a WM -> add the default one. */
+                       wm_add_default(bmain, C);
+                       *r_new_wm_list = bmain->wm;
+               }
+               /* case 2 */
+               else {
+                       *r_new_wm_list = *readfile_wm_list;
+               }
+       }
+       else {
+               /* case 3 */
+               if (BLI_listbase_is_empty(readfile_wm_list)) {
+                       /* We've read file without wm, keep current one entirely alive.
+                        * Happens when reading pre 2.5 files (no WM back then) */
+                       wm_window_match_keep_current_wm(C, current_wm_list, (G.fileflags & G_FILE_NO_UI) == 0, r_new_wm_list);
+               }
+               /* case 4 */
+               else {
+                       wm_window_match_replace_by_file_wm(C, current_wm_list, readfile_wm_list, r_new_wm_list);
                }
        }
 }
@@ -339,6 +358,8 @@ static void wm_init_userdef(Main *bmain, const bool read_userdef_from_memory)
 
        /* update tempdir from user preferences */
        BKE_tempdir_init(U.tempdir);
+
+       BLF_antialias_set((U.text_render & USER_TEXT_DISABLE_AA) == 0);
 }
 
 
@@ -422,8 +443,9 @@ void wm_file_read_report(bContext *C)
        Scene *sce;
 
        for (sce = G.main->scene.first; sce; sce = sce->id.next) {
-               if (sce->r.engine[0] &&
-                   BLI_findstring(&R_engines, sce->r.engine, offsetof(RenderEngineType, idname)) == NULL)
+               ViewRender *view_render = &sce->view_render;
+               if (view_render->engine_id[0] &&
+                   BLI_findstring(&R_engines, view_render->engine_id, offsetof(RenderEngineType, idname)) == NULL)
                {
                        if (reports == NULL) {
                                reports = CTX_wm_reports(C);
@@ -431,7 +453,7 @@ void wm_file_read_report(bContext *C)
 
                        BKE_reportf(reports, RPT_ERROR,
                                    "Engine '%s' not available for scene '%s' (an add-on may need to be installed or enabled)",
-                                   sce->r.engine, sce->id.name + 2);
+                                   view_render->engine_id, sce->id.name + 2);
                }
        }
 
@@ -459,7 +481,7 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
        CTX_wm_window_set(C, wm->windows.first);
 
        ED_editors_init(C);
-       DAG_on_visible_update(CTX_data_main(C), true);
+       DEG_on_visible_update(CTX_data_main(C), true);
 
 #ifdef WITH_PYTHON
        if (is_startup_file) {
@@ -492,17 +514,11 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
        BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
        BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
 
-       /* Would otherwise be handled by event loop.
-        *
-        * Disabled for startup file, since it causes problems when PyDrivers are used in the startup file.
-        * While its possible state of startup file may be wrong,
-        * in this case users nearly always load a file to replace the startup file. */
-       if (G.background && (is_startup_file == false)) {
-               Main *bmain = CTX_data_main(C);
-               BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
-       }
-
+#if 1
        WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
+#else
+       WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ);
+#endif
 
        /* report any errors.
         * currently disabled if addons aren't yet loaded */
@@ -515,12 +531,19 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
                 * a blend file and do anything since the screen
                 * won't be set to a valid value again */
                CTX_wm_window_set(C, NULL); /* exits queues */
+
+               /* Ensure tools are registered. */
+               WM_toolsystem_init(C);
        }
 
        if (!G.background) {
-//             undo_editmode_clear();
-               BKE_undo_reset();
-               BKE_undo_write(C, "original");  /* save current state */
+               if (wm->undo_stack == NULL) {
+                       wm->undo_stack = BKE_undosys_stack_create();
+               }
+               else {
+                       BKE_undosys_stack_clear(wm->undo_stack);
+               }
+               BKE_undosys_stack_init_from_main(wm->undo_stack, CTX_data_main(C));
        }
 }
 
@@ -552,7 +575,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
 
                /* put aside screens to match with persistent windows later */
                /* also exit screens and editors */
-               wm_window_match_init(C, &wmbase); 
+               wm_window_match_init(C, &wmbase);
                
                /* confusing this global... */
                G.relbase_valid = 1;
@@ -574,7 +597,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
                }
 
                /* match the read WM with current WM */
-               wm_window_match_do(C, &wmbase);
+               wm_window_match_do(C, &wmbase, &G.main->wm, &G.main->wm);
                WM_check(C); /* opens window(s), checks keymaps */
 
                if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
@@ -837,14 +860,14 @@ int wm_homefile_read(
        /* prevent buggy files that had G_FILE_RELATIVE_REMAP written out by mistake. Screws up autosaves otherwise
         * can remove this eventually, only in a 2.53 and older, now its not written */
        G.fileflags &= ~G_FILE_RELATIVE_REMAP;
-       
-       if (use_userdef) {
+
+       if (use_userdef) {      
                /* check userdef before open window, keymaps etc */
                wm_init_userdef(CTX_data_main(C), read_userdef_from_memory);
        }
        
        /* match the read WM with current WM */
-       wm_window_match_do(C, &wmbase); 
+       wm_window_match_do(C, &wmbase, &G.main->wm, &G.main->wm);
        WM_check(C); /* opens window(s), checks keymaps */
 
        G.main->name[0] = '\0';
@@ -990,7 +1013,7 @@ static void wm_history_file_update(void)
 
 
 /* screen can be NULL */
-static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
+static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, ViewLayer *view_layer, bScreen *screen, BlendThumbnail **thumb_pt)
 {
        /* will be scaled down, but gives some nice oversampling */
        ImBuf *ibuf;
@@ -1025,19 +1048,22 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, BlendThumbnail **t
        }
 
        /* gets scaled to BLEN_THUMB_SIZE */
+       Depsgraph *depsgraph = CTX_data_depsgraph(C);
+       RenderEngineType *engine_type = CTX_data_engine_type(C);
+
        if (scene->camera) {
                ibuf = ED_view3d_draw_offscreen_imbuf_simple(
-                       scene, scene->camera,
+                       depsgraph, scene, view_layer, engine_type, scene->camera,
                        BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
                        IB_rect, V3D_OFSDRAW_NONE, OB_SOLID, R_ALPHAPREMUL, 0, NULL,
-                       NULL, NULL, err_out);
+                       NULL, err_out);
        }
        else {
                ibuf = ED_view3d_draw_offscreen_imbuf(
-                       scene, v3d, ar,
+                       depsgraph, scene, view_layer, engine_type, v3d, ar,
                        BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
                        IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
-                       NULL, NULL, err_out);
+                       NULL, err_out);
        }
 
        if (ibuf) {
@@ -1130,7 +1156,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
        /* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */
        main_thumb = thumb = CTX_data_main(C)->blen_thumb;
        if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
-               ibuf_thumb = blend_file_thumb(CTX_data_scene(C), CTX_wm_screen(C), &thumb);
+               ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_data_view_layer(C), CTX_wm_screen(C), &thumb);
        }
 
        /* operator now handles overwrite checks */
@@ -1267,7 +1293,10 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
 
        if (U.uiflag & USER_GLOBALUNDO) {
                /* fast save of last undobuffer, now with UI */
-               BKE_undo_save_file(filepath);
+               struct MemFile *memfile = ED_undosys_stack_memfile_get_active(wm->undo_stack);
+               if (memfile) {
+                       BLO_memfile_write_file(memfile, filepath);
+               }
        }
        else {
                /*  save as regular blend file */
@@ -1385,7 +1414,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
        BLI_callback_exec(G.main, NULL, BLI_CB_EVT_SAVE_PRE);
 
        /* check current window and close it if temp */
-       if (win && win->screen->temp)
+       if (win && WM_window_is_temp_screen(win))
                wm_window_close(C, wm, win);
 
        /* update keymaps in user preferences */
@@ -1532,6 +1561,42 @@ void WM_OT_save_userpref(wmOperatorType *ot)
        ot->exec = wm_userpref_write_exec;
 }
 
+static int wm_workspace_configuration_file_write_exec(bContext *C, wmOperator *op)
+{
+       Main *bmain = CTX_data_main(C);
+       char filepath[FILE_MAX];
+
+       const char *app_template = U.app_template[0] ? U.app_template : NULL;
+       const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
+       if (cfgdir == NULL) {
+               BKE_report(op->reports, RPT_ERROR, "Unable to create workspace configuration file path");
+               return OPERATOR_CANCELLED;
+       }
+
+       BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_WORKSPACES_FILE, NULL);
+       printf("trying to save workspace configuration file at %s ", filepath);
+
+       if (BKE_blendfile_workspace_config_write(bmain, filepath, op->reports) != 0) {
+               printf("ok\n");
+               return OPERATOR_FINISHED;
+       }
+       else {
+               printf("fail\n");
+       }
+
+       return OPERATOR_CANCELLED;
+}
+
+void WM_OT_save_workspace_file(wmOperatorType *ot)
+{
+       ot->name = "Save Workspace Configuration";
+       ot->idname = "WM_OT_save_workspace_file";
+       ot->description = "Save workspaces of the current file as part of the user configuration";
+
+       ot->invoke = WM_operator_confirm;
+       ot->exec = wm_workspace_configuration_file_write_exec;
+}
+
 static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
 {
        ED_file_read_bookmarks();
@@ -2076,7 +2141,7 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
        WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
 
        if (RNA_boolean_get(op->ptr, "exit")) {
-               WM_exit(C);
+               wm_exit_schedule_delayed(C);
        }
 
        return OPERATOR_FINISHED;