OpenSubdiv: Commit of OpenSubdiv integration into Blender
[blender.git] / source / blender / windowmanager / intern / wm_init_exit.c
index 6d4a84d789659fc0f0b6621db55cd1ea37f11526..ad7044c62187c9d4b3a1612c90f1192727a9901a 100644 (file)
@@ -26,6 +26,8 @@
 
 /** \file blender/windowmanager/intern/wm_init_exit.c
  *  \ingroup wm
+ *
+ * Manage initializing resources and correctly shutting down.
  */
 
 #include <stdlib.h>
 #include <string.h>
 
 #ifdef WIN32
-#  include <Windows.h>
+#  include <windows.h>
 #endif
 
 #include "MEM_guardedalloc.h"
-#include "MEM_CacheLimiterC-Api.h"
-
-#include "IMB_imbuf_types.h"
-#include "IMB_imbuf.h"
 
-#include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 #include "DNA_userdef_types.h"
 #include "DNA_windowmanager_types.h"
 
+#include "BLI_callbacks.h"
+#include "BLI_listbase.h"
+#include "BLI_path_util.h"
+#include "BLI_string.h"
+#include "BLI_threads.h"
+#include "BLI_utildefines.h"
+
+#include "BLO_writefile.h"
+
 #include "BKE_blender.h"
 #include "BKE_context.h"
 #include "BKE_screen.h"
-#include "BKE_curve.h"
-#include "BKE_displist.h"
 #include "BKE_DerivedMesh.h"
-#include "BKE_font.h"
 #include "BKE_global.h"
+#include "BKE_icons.h"
 #include "BKE_library.h"
 #include "BKE_main.h"
-#include "BKE_mball.h"
+#include "BKE_mball_tessellate.h"
 #include "BKE_node.h"
 #include "BKE_report.h"
 
-#include "BKE_packedFile.h"
+#include "BKE_addon.h"
+#include "BKE_appdir.h"
 #include "BKE_sequencer.h" /* free seq clipboard */
 #include "BKE_material.h" /* clear_matcopybuf */
 #include "BKE_tracking.h" /* free tracking clipboard */
-
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
+#include "BKE_mask.h" /* free mask clipboard */
 
 #include "RE_engine.h"
 #include "RE_pipeline.h"        /* RE_ free stuff */
@@ -95,6 +97,7 @@
 #include "wm_window.h"
 
 #include "ED_armature.h"
+#include "ED_gpencil.h"
 #include "ED_keyframing.h"
 #include "ED_node.h"
 #include "ED_render.h"
 #include "BLF_translation.h"
 
 #include "GPU_buffers.h"
-#include "GPU_extensions.h"
 #include "GPU_draw.h"
+#include "GPU_init_exit.h"
 
 #include "BKE_depsgraph.h"
 #include "BKE_sound.h"
 #include "COM_compositor.h"
 
+#ifdef WITH_OPENSUBDIV
+#  include "opensubdiv_capi.h"
+#endif
+
 static void wm_init_reports(bContext *C)
 {
-       BKE_reports_init(CTX_wm_reports(C), RPT_STORE);
+       ReportList *reports = CTX_wm_reports(C);
+
+       BLI_assert(!reports || BLI_listbase_is_empty(&reports->list));
+
+       BKE_reports_init(reports, RPT_STORE);
 }
 static void wm_free_reports(bContext *C)
 {
-       BKE_reports_clear(CTX_wm_reports(C));
+       ReportList *reports = CTX_wm_reports(C);
+
+       BKE_reports_clear(reports);
 }
 
-int wm_start_with_console = 0; /* used in creator.c */
+bool wm_start_with_console = false; /* used in creator.c */
 
 /* only called once, for startup */
 void WM_init(bContext *C, int argc, const char **argv)
 {
+       
        if (!G.background) {
                wm_ghost_init(C);   /* note: it assigns C to ghost! */
                wm_init_cursor_data();
        }
        GHOST_CreateSystemPaths();
+
+       BKE_addon_pref_type_init();
+
        wm_operatortype_init();
        WM_menutype_init();
+       WM_uilisttype_init();
 
-       set_free_windowmanager_cb(wm_close_and_free);   /* library.c */
-       set_blender_test_break_cb(wm_window_testbreak); /* blender.c */
+       BKE_library_callback_free_window_manager_set(wm_close_and_free);   /* library.c */
+       BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference);   /* library.c */
+       BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference);   /* library.c */
+       BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
+       BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */
        DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update); /* depsgraph.c */
        
        ED_spacetypes_init();   /* editors/space_api/spacetype.c */
@@ -148,27 +169,52 @@ void WM_init(bContext *C, int argc, const char **argv)
        BLF_init(11, U.dpi); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
        BLF_lang_init();
 
+       /* Enforce loading the UI for the initial homefile */
+       G.fileflags &= ~G_FILE_NO_UI;
+
        /* get the default database, plus a wm */
-       WM_homefile_read(C, NULL, G.factory_startup);
+       wm_homefile_read(C, NULL, G.factory_startup, NULL);
+       
 
        BLF_lang_set(NULL);
 
+       if (!G.background) {
+               /* sets 3D mouse deadzone */
+               WM_ndof_deadzone_set(U.ndof_deadzone);
+
+               GPU_init();
+
+               GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
+               GPU_set_linear_mipmap(true);
+               GPU_set_anisotropic(U.anisotropic_filter);
+               GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
+
+               UI_init();
+       }
+       else {
+               /* Note: Currently only inits icons, which we now want in background mode too
+                * (scripts could use those in background processing...).
+                * In case we do more later, we may need to pass a 'background' flag.
+                * Called from 'UI_init' above */
+               BKE_icons_init(1);
+       }
+
+
+       ED_spacemacros_init();
+
        /* note: there is a bug where python needs initializing before loading the
         * startup.blend because it may contain PyDrivers. It also needs to be after
         * initializing space types and other internal data.
         *
         * However cant redo this at the moment. Solution is to load python
-        * before WM_homefile_read() or make py-drivers check if python is running.
+        * before wm_homefile_read() or make py-drivers check if python is running.
         * Will try fix when the crash can be repeated. - campbell. */
 
 #ifdef WITH_PYTHON
        BPY_context_set(C); /* necessary evil */
        BPY_python_start(argc, argv);
 
-       BPY_driver_reset();
-       BPY_app_handlers_reset(FALSE); /* causes addon callbacks to be freed [#28068],
-                                       * but this is actually what we want. */
-       BPY_modules_load_user(C);
+       BPY_python_reset(C);
 #else
        (void)argc; /* unused */
        (void)argv; /* unused */
@@ -179,28 +225,19 @@ void WM_init(bContext *C, int argc, const char **argv)
 
        wm_init_reports(C); /* reports cant be initialized before the wm */
 
-       if (!G.background) {
-               GPU_extensions_init();
-               GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
-               GPU_set_anisotropic(U.anisotropic_filter);
-               GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
-
-               UI_init();
-       }
-       
        clear_matcopybuf();
        ED_render_clear_mtex_copybuf();
 
-       //      glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+       // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                
        ED_preview_init_dbase();
        
-       WM_read_history();
+       wm_read_history();
 
        /* allow a path of "", this is what happens when making a new file */
 #if 0
        if (G.main->name[0] == 0)
-               BLI_make_file_string("/", G.main->name, BLI_getDefaultDocumentFolder(), "untitled.blend");
+               BLI_make_file_string("/", G.main->name, BKE_appdir_folder_default(), "untitled.blend");
 #endif
 
        BLI_strncpy(G.lib, G.main->name, FILE_MAX);
@@ -211,6 +248,21 @@ void WM_init(bContext *C, int argc, const char **argv)
                COM_linker_hack = COM_execute;
        }
 #endif
+       
+       /* load last session, uses regular file reading so it has to be in end (after init py etc) */
+       if (U.uiflag2 & USER_KEEP_SESSION) {
+               /* calling WM_recover_last_session(C, NULL) has been moved to creator.c */
+               /* that prevents loading both the kept session, and the file on the command line */
+       }
+       else {
+               /* normally 'wm_homefile_read' will do this,
+                * however python is not initialized when called from this function.
+                *
+                * unlikely any handlers are set but its possible,
+                * note that recovering the last session does its own callbacks. */
+               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);
+       }
 }
 
 void WM_init_splash(bContext *C)
@@ -227,7 +279,7 @@ void WM_init_splash(bContext *C)
        }
 }
 
-int WM_init_game(bContext *C)
+bool WM_init_game(bContext *C)
 {
        wmWindowManager *wm = CTX_wm_manager(C);
        wmWindow *win;
@@ -274,7 +326,7 @@ int WM_init_game(bContext *C)
 
                /* full screen the area */
                if (!sa->full) {
-                       ED_screen_full_toggle(C, win, sa);
+                       ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
                }
 
                /* Fullscreen */
@@ -295,9 +347,9 @@ int WM_init_game(bContext *C)
 
                WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL);
 
-               sound_exit();
+               BKE_sound_exit();
 
-               return 1;
+               return true;
        }
        else {
                ReportTimerInfo *rti;
@@ -312,8 +364,9 @@ int WM_init_game(bContext *C)
 
                rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
                wm->reports.reporttimer->customdata = rti;
+
+               return false;
        }
-       return 0;
 }
 
 /* free strings of open recent files */
@@ -360,11 +413,11 @@ static void wait_for_console_key(void)
 
 /* called in creator.c even... tsk, split this! */
 /* note, doesnt run exit() call WM_exit() for that */
-void WM_exit_ext(bContext *C, const short do_python)
+void WM_exit_ext(bContext *C, const bool do_python)
 {
        wmWindowManager *wm = C ? CTX_wm_manager(C) : NULL;
 
-       sound_exit();
+       BKE_sound_exit();
 
        /* first wrap up running stuff, we assume only the active WM is running */
        /* modal handlers are on window level freed, others too? */
@@ -372,6 +425,25 @@ void WM_exit_ext(bContext *C, const short do_python)
        if (C && wm) {
                wmWindow *win;
 
+               if (!G.background) {
+                       if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_is_valid(NULL)) {
+                               /* save the undo state as quit.blend */
+                               char filename[FILE_MAX];
+                               bool has_edited;
+                               int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
+
+                               BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE);
+
+                               has_edited = ED_editors_flush_edits(C, false);
+
+                               if ((has_edited && BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL)) ||
+                                   BKE_undo_save_file(filename))
+                               {
+                                       printf("Saved session recovery to '%s'\n", filename);
+                               }
+                       }
+               }
+               
                WM_jobs_kill_all(wm);
 
                for (win = wm->windows.first; win; win = win->next) {
@@ -382,9 +454,12 @@ void WM_exit_ext(bContext *C, const short do_python)
                        ED_screen_exit(C, win, win->screen);
                }
        }
+
+       BKE_addon_pref_type_free();
        wm_operatortype_free();
        wm_dropbox_free();
        WM_menutype_free();
+       WM_uilisttype_free();
        
        /* all non-screen and non-space stuff editors did, like editmode */
        if (C)
@@ -399,6 +474,10 @@ void WM_exit_ext(bContext *C, const short do_python)
        
        BKE_mball_cubeTable_free();
        
+       /* render code might still access databases */
+       RE_FreeAllRender();
+       RE_engines_exit();
+       
        ED_preview_free_dbase();  /* frees a Main dbase, before free_blender! */
 
        if (C && wm)
@@ -406,6 +485,7 @@ void WM_exit_ext(bContext *C, const short do_python)
 
        BKE_sequencer_free_clipboard(); /* sequencer.c */
        BKE_tracking_clipboard_free();
+       BKE_mask_clipboard_free();
                
 #ifdef WITH_COMPOSITOR
        COM_deinitialize();
@@ -416,6 +496,7 @@ void WM_exit_ext(bContext *C, const short do_python)
        free_anim_copybuf();
        free_anim_drivers_copybuf();
        free_fmodifiers_copybuf();
+       ED_gpencil_strokes_copybuf_free();
        ED_clipboard_posebuf_free();
        BKE_node_clipboard_clear();
 
@@ -423,14 +504,12 @@ void WM_exit_ext(bContext *C, const short do_python)
 
 #ifdef WITH_INTERNATIONAL
        BLF_free_unifont();
+       BLF_free_unifont_mono();
        BLF_lang_free();
 #endif
        
        ANIM_keyingset_infos_exit();
        
-       RE_FreeAllRender();
-       RE_engines_exit();
-       
 //     free_txt_data();
        
 
@@ -450,14 +529,18 @@ void WM_exit_ext(bContext *C, const short do_python)
        (void)do_python;
 #endif
 
-       GPU_global_buffer_pool_free();
-       GPU_free_unused_buffers();
-       GPU_extensions_exit();
+#ifdef WITH_OPENSUBDIV
+       openSubdiv_cleanup();
+#endif
 
        if (!G.background) {
-               BKE_undo_save_quit();  /* saves quit.blend if global undo is on */
+               GPU_global_buffer_pool_free();
+               GPU_free_unused_buffers();
+
+               GPU_exit();
        }
-       BKE_reset_undo(); 
+
+       BKE_undo_reset();
        
        ED_file_exit(); /* for fsmenu */
 
@@ -475,25 +558,33 @@ void WM_exit_ext(bContext *C, const short do_python)
        
        GHOST_DisposeSystemPaths();
 
+       BLI_threadapi_exit();
+
        if (MEM_get_memory_blocks_in_use() != 0) {
-               printf("Error: Not freed memory blocks: %d\n", MEM_get_memory_blocks_in_use());
+               size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use();
+               printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n",
+                      MEM_get_memory_blocks_in_use(),
+                      (double)mem_in_use / 1024 / 1024);
                MEM_printmemlist();
        }
        wm_autosave_delete();
-       
+
+       BKE_tempdir_session_purge();
+}
+
+void WM_exit(bContext *C)
+{
+       WM_exit_ext(C, 1);
+
        printf("\nBlender quit\n");
-       
-#ifdef WIN32   
+
+#ifdef WIN32
        /* ask user to press a key when in debug mode */
        if (G.debug & G_DEBUG) {
                printf("Press any key to exit . . .\n\n");
                wait_for_console_key();
        }
-#endif 
-}
+#endif
 
-void WM_exit(bContext *C)
-{
-       WM_exit_ext(C, 1);
-       exit(G.is_break == TRUE);
+       exit(G.is_break == true);
 }