Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Mon, 22 Oct 2018 03:59:12 +0000 (14:59 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 22 Oct 2018 03:59:12 +0000 (14:59 +1100)
Reverts: 92fd931e536

1  2 
source/blender/windowmanager/intern/wm_files.c

index 1195348ed0d5c80f6b93c88ae0c14cbc65d965bf,6182a8c5ec6b979e1277244735bca477fc450ab0..7d3599b2f11da1e752a2e0e3ef82280a6ef4b31b
@@@ -70,7 -70,6 +70,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"
@@@ -78,6 -77,7 +78,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"
@@@ -87,7 -87,6 +87,7 @@@
  #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 "BPY_extern.h"
  #endif
  
 +#include "DEG_depsgraph.h"
 +
  #include "WM_api.h"
  #include "WM_types.h"
 +#include "WM_message.h"
 +#include "WM_toolsystem.h"
 +
  #include "wm.h"
  #include "wm_files.h"
  #include "wm_window.h"
@@@ -168,7 -162,7 +168,7 @@@ static void wm_window_match_init(bConte
                        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));
                }
        }
  
        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)
 +static void wm_window_substitute_old(wmWindowManager *oldwm, wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
  {
        win->ghostwin = oldwin->ghostwin;
 -      win->multisamples = oldwin->multisamples;
 +      win->gpuctx = oldwin->gpuctx;
        win->active = oldwin->active;
 -      if (win->active)
 +      if (win->active) {
                wm->winactive = win;
 +      }
 +      if (oldwm->windrawable == oldwin) {
 +              oldwm->windrawable = NULL;
 +              wm->windrawable = win;
 +      }
  
        if (!G.background) /* file loading in background mode still calls this */
                GHOST_SetWindowUserData(win->ghostwin, win);    /* pointer back */
  
        oldwin->ghostwin = NULL;
 -      oldwin->multisamples = 0;
 +      oldwin->gpuctx = NULL;
  
        win->eventstate = oldwin->eventstate;
        oldwin->eventstate = NULL;
        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(Main *bmain, 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 (bmain->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(&bmain->wm)) {
 -                      bScreen *screen = NULL;
 +      Main *bmain = CTX_data_main(C);
 +      wmWindowManager *wm = current_wm_list->first;
 +      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 */
 +      wm->initialized &= ~WM_WINDOW_IS_INITIALIZED;
  
 -                              /* match oldwm to new dbase, only old files */
 -                              for (wm = oldwmlist->first; wm; wm = wm->id.next) {
 +      /* 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;
  
 -                                      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(bmain, win, screen);
 +                      BKE_workspace_layout_find_global(bmain, screen, &workspace);
 +                      BKE_workspace_active_set(win->workspace_hook, workspace);
 +                      win->scene = CTX_data_scene(C);
  
 -                                              BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
 -                                              win->screen->winid = win->winid;
 -                                      }
 -                              }
 +                      /* all windows get active screen from file */
 +                      if (screen->winid == 0) {
 +                              WM_window_set_active_screen(win, workspace, screen);
                        }
 +                      else {
 +                              WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
 +                              WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
  
 -                      bmain->wm = *oldwmlist;
 +                              WM_window_set_active_layout(win, workspace, layout_new);
 +                      }
  
 -                      /* screens were read from file! */
 -                      ED_screens_initialize(bmain, bmain->wm.first);
 +                      bScreen *win_screen = WM_window_get_active_screen(win);
 +                      win_screen->winid = win->winid;
                }
 -              else {
 -                      bool has_match = false;
 +      }
  
 -                      /* what if old was 3, and loaded 1? */
 -                      /* this code could move to setup_appdata */
 -                      oldwm = oldwmlist->first;
 -                      wm = bmain->wm.first;
 +      *r_new_wm_list = *current_wm_list;
 +}
  
 -                      /* 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;
 +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;
  
 -                      BLI_listbase_clear(&oldwm->keyconfigs);
 -                      oldwm->addonconf = NULL;
 -                      oldwm->defaultconf = NULL;
 -                      oldwm->userconf = NULL;
 +      /* this code could move to setup_appdata */
  
 -                      /* ensure making new keymaps and set space types */
 -                      wm->initialized = 0;
 -                      wm->winactive = NULL;
 +      /* 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;
  
 -                      /* 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) {
 +      BLI_listbase_clear(&oldwm->keyconfigs);
 +      oldwm->addonconf = NULL;
 +      oldwm->defaultconf = NULL;
 +      oldwm->userconf = NULL;
  
 -                                      if (oldwin->winid == win->winid) {
 -                                              has_match = true;
 +      /* ensure making new keymaps and set space types */
 +      wm->initialized = 0;
 +      wm->winactive = NULL;
  
 -                                              wm_window_substitute_old(wm, oldwin, win);
 -                                      }
 -                              }
 -                      }
 +      /* Clearing drawable of before deleting any context
 +       * to avoid clearing the wrong wm. */
 +      wm_window_clear_drawable(oldwm);
  
 -                      /* 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;
 +      /* 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);
 +                              wm_window_substitute_old(oldwm, 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(oldwm, 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);
                }
        }
  }
@@@ -476,8 -450,9 +476,8 @@@ void wm_file_read_report(bContext *C, M
   * Logic shared between #WM_file_read & #wm_homefile_read,
   * updates to make after reading a file.
   */
 -static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool use_userdef)
 +static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool reset_app_template)
  {
 -      Main *bmain = CTX_data_main(C);
        bool addons_loaded = false;
        wmWindowManager *wm = CTX_wm_manager(C);
  
  
        CTX_wm_window_set(C, wm->windows.first);
  
 +      Main *bmain = CTX_data_main(C);
 +      DEG_on_visible_update(bmain, true);
 +      wm_event_do_depsgraph(C);
 +
        ED_editors_init(C);
 -      DAG_on_visible_update(bmain, true);
  
  #ifdef WITH_PYTHON
        if (is_startup_file) {
                /* possible python hasn't been initialized */
                if (CTX_py_init_get(C)) {
 -                      if (use_userdef) {
 +                      if (reset_app_template) {
                                /* Only run when we have a template path found. */
                                if (BKE_appdir_app_template_any()) {
                                        BPY_execute_string(C, "__import__('bl_app_template_utils').reset()");
                addons_loaded = true;
        }
  #else
 -      UNUSED_VARS(use_userdef);
 +      UNUSED_VARS(is_startup_file, reset_app_template);
  #endif  /* WITH_PYTHON */
  
        WM_operatortype_last_properties_clear_all();
        BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
        BLI_callback_exec(bmain, 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)) {
 -              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 */
                 * 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);
        }
  }
  
@@@ -613,7 -587,7 +613,7 @@@ bool WM_file_read(bContext *C, const ch
                }
  
                /* match the read WM with current WM */
 -              wm_window_match_do(bmain, C, &wmbase);
 +              wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
                WM_check(C); /* opens window(s), checks keymaps */
  
                if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
  
                success = true;
        }
 +#if 0
 +      else if (retval == BKE_READ_EXOTIC_OK_OTHER)
 +              BKE_undo_write(C, "Import file");
 +#endif
        else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
                BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
                            errno ? strerror(errno) : TIP_("unable to open the file"));
@@@ -696,25 -666,6 +696,25 @@@ const char *WM_init_state_app_template_
        return wm_init_state_app_template.override ? wm_init_state_app_template.app_template : NULL;
  }
  
 +
 +static bool wm_app_template_has_userpref(const char *app_template)
 +{
 +      /* Test if app template provides a userpref.blend. If not, we will
 +       * share user preferences with the rest of Blender. */
 +      if (!app_template && app_template[0]) {
 +              return false;
 +      }
 +
 +      char app_template_path[FILE_MAX];
 +      if (!BKE_appdir_app_template_id_search(app_template, app_template_path, sizeof(app_template_path))) {
 +              return false;
 +      }
 +
 +      char userpref_path[FILE_MAX];
 +      BLI_path_join(userpref_path, sizeof(userpref_path), app_template_path, BLENDER_USERPREF_FILE, NULL);
 +      return BLI_exists(userpref_path);
 +}
 +
  /**
   * Called on startup, (context entirely filled with NULLs)
   * or called for 'New File' both startup.blend and userpref.blend are checked.
@@@ -809,8 -760,6 +809,8 @@@ int wm_homefile_read
        }
  
        const char *app_template = NULL;
 +      bool update_defaults = false;
 +      bool reset_app_template = false;
  
        if (filepath_startup_override != NULL) {
                /* pass */
                app_template = U.app_template;
        }
  
 +      if ((!app_template && U.app_template[0]) ||
 +          (app_template && !STREQ(app_template, U.app_template)))
 +      {
 +              /* Always load UI when switching to another template. */
 +              G.fileflags &= ~G_FILE_NO_UI;
 +              reset_app_template = true;
 +      }
 +
        if ((app_template != NULL) && (app_template[0] != '\0')) {
                if (!BKE_appdir_app_template_id_search(app_template, app_template_system, sizeof(app_template_system))) {
                        /* Can safely continue with code below, just warn it's not found. */
  
                if (filepath_startup[0] == '\0') {
                        BLI_path_join(filepath_startup, sizeof(filepath_startup), app_template_system, BLENDER_STARTUP_FILE, NULL);
 +
 +                      /* Update defaults only for system templates. */
 +                      update_defaults = true;
                }
        }
  
                                printf("\nNote: No (valid) '%s' found, fall back to built-in default.\n\n", filepath_startup);
                        success = false;
                }
 +              if (success && update_defaults) {
 +                      BLO_update_defaults_startup_blend(CTX_data_main(C), app_template);
 +              }
        }
  
        if (success == false && filepath_startup_override && reports) {
        if (use_userdef) {
                /* check userdef before open window, keymaps etc */
                wm_init_userdef(bmain, read_userdef_from_memory);
 +              reset_app_template = true;
        }
  
        /* match the read WM with current WM */
 -      wm_window_match_do(bmain, C, &wmbase);
 +      wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
        WM_check(C); /* opens window(s), checks keymaps */
  
        bmain->name[0] = '\0';
  
 -      if (use_userdef) {
 -              /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
 -              if (!G.background) {
 -                      GPU_default_lights();
 -              }
 -      }
 -
        /* start with save preference untitled.blend */
        G.save_over = 0;
 -      /* disable auto-play in startup.blend... */
 -      G.fileflags &= ~G_FILE_AUTOPLAY;
  
 -      wm_file_read_post(C, true, use_userdef);
 +      wm_file_read_post(C, true, reset_app_template);
  
        return true;
  }
@@@ -1091,7 -1034,7 +1091,7 @@@ static void wm_history_file_update(void
  
  
  /* screen can be NULL */
 -static ImBuf *blend_file_thumb(Main *bmain, Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
 +static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
  {
        /* will be scaled down, but gives some nice oversampling */
        ImBuf *ibuf;
        }
  
        /* gets scaled to BLEN_THUMB_SIZE */
 +      Depsgraph *depsgraph = CTX_data_depsgraph(C);
 +
        if (scene->camera) {
                ibuf = ED_view3d_draw_offscreen_imbuf_simple(
 -                      bmain, scene, scene->camera,
 +                      depsgraph, scene, OB_SOLID, 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);
 +                      IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
 +                      NULL, err_out);
        }
        else {
                ibuf = ED_view3d_draw_offscreen_imbuf(
 -                      bmain, scene, v3d, ar,
 +                      depsgraph, scene, OB_SOLID, 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) {
@@@ -1231,10 -1172,10 +1231,10 @@@ static int wm_file_write(bContext *C, c
  
        /* blend file thumbnail */
        /* save before exit_editmode, otherwise derivedmeshes for shared data corrupt #27765) */
 -      /* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */
 +      /* Main now can store a .blend thumbnail, useful for background mode or thumbnail customization. */
        main_thumb = thumb = bmain->blen_thumb;
        if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
 -              ibuf_thumb = blend_file_thumb(bmain, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
 +              ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
        }
  
        /* operator now handles overwrite checks */
                }
  
                SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
 -              SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_AUTOPLAY, G_FILE_AUTOPLAY);
  
                /* prevent background mode scripts from clobbering history */
                if (do_history) {
@@@ -1377,7 -1319,7 +1377,7 @@@ void wm_autosave_timer(const bContext *
        }
        else {
                /*  save as regular blend file */
 -              int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
 +              int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
  
                ED_editors_flush_edits(C, false);
  
@@@ -1492,7 -1434,7 +1492,7 @@@ static int wm_homefile_write_exec(bCont
        BLI_callback_exec(bmain, 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 */
        ED_editors_flush_edits(C, false);
  
        /*  force save as regular blend file */
 -      fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
 +      fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
  
        if (BLO_write_file(bmain, filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
                printf("fail\n");
@@@ -1525,7 -1467,7 +1525,7 @@@ void WM_OT_save_homefile(wmOperatorTyp
  {
        ot->name = "Save Startup File";
        ot->idname = "WM_OT_save_homefile";
 -      ot->description = "Make the current file the default .blend file, includes preferences";
 +      ot->description = "Make the current file the default .blend file";
  
        ot->invoke = WM_operator_confirm;
        ot->exec = wm_homefile_write_exec;
@@@ -1579,7 -1521,6 +1579,7 @@@ static int wm_userpref_write_exec(bCont
        char filepath[FILE_MAX];
        const char *cfgdir;
        bool ok = true;
 +      bool use_template_userpref = wm_app_template_has_userpref(U.app_template);
  
        /* update keymaps in user preferences */
        WM_keyconfig_update(wm);
        if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL))) {
                bool ok_write;
                BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
 -              printf("trying to save userpref at %s ", filepath);
  
 -              if (U.app_template[0]) {
 +              if (use_template_userpref) {
                        ok_write = BKE_blendfile_userdef_write_app_template(filepath, op->reports);
                }
                else {
                BKE_report(op->reports, RPT_ERROR, "Unable to create userpref path");
        }
  
 -      if (U.app_template[0]) {
 +      if (use_template_userpref) {
                if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
                        /* Also save app-template prefs */
                        BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE, NULL);
 -                      printf("trying to save app-template userpref at %s ", filepath);
                        if (BKE_blendfile_userdef_write(filepath, op->reports) != 0) {
                                printf("ok\n");
                        }
@@@ -1699,9 -1642,8 +1699,9 @@@ static int wm_homefile_read_exec(bConte
                RNA_property_string_get(op->ptr, prop_app_template, app_template_buf);
                app_template = app_template_buf;
  
 -              /* Always load preferences when switching templates. */
 -              use_userdef = true;
 +              /* Always load preferences when switching templates with own preferences. */
 +              use_userdef = wm_app_template_has_userpref(app_template) ||
 +                            wm_app_template_has_userpref(U.app_template);
  
                /* Turn override off, since we're explicitly loading a different app-template. */
                WM_init_state_app_template_set(NULL);
        }
  }
  
 +static int wm_homefile_read_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
 +{
 +      /* Draw menu which includes default startup and application templates. */
 +      uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("New File"), ICON_FILE_NEW);
 +      uiLayout *layout = UI_popup_menu_layout(pup);
 +
 +      MenuType *mt = WM_menutype_find("TOPBAR_MT_file_new", false);
 +      if (mt) {
 +              UI_menutype_draw(C, mt, layout);
 +      }
 +
 +      UI_popup_menu_end(C, pup);
 +
 +      return OPERATOR_INTERFACE;
 +}
 +
  void WM_OT_read_homefile(wmOperatorType *ot)
  {
        PropertyRNA *prop;
        ot->idname = "WM_OT_read_homefile";
        ot->description = "Open the default file (doesn't save the current file)";
  
 -      ot->invoke = WM_operator_confirm;
 +      ot->invoke = wm_homefile_read_invoke;
        ot->exec = wm_homefile_read_exec;
  
        prop = RNA_def_string_file_path(ot->srna, "filepath", NULL,
@@@ -2166,7 -2092,8 +2166,8 @@@ static int wm_save_as_mainfile_exec(bCo
  {
        Main *bmain = CTX_data_main(C);
        char path[FILE_MAX];
 -      int fileflags;
 +      int fileflags, orig_fileflags;
+       const bool is_save_as = (op->type->invoke == wm_save_as_mainfile_invoke);
  
        save_set_compress(op);
  
                wm_filepath_default(path);
        }
  
 +      orig_fileflags = G.fileflags;
        fileflags = G.fileflags & ~G_FILE_USERPREFS;
  
        /* set compression flag */
                 RNA_boolean_get(op->ptr, "copy")),
                G_FILE_SAVE_COPY);
  
 -      if (wm_file_write(C, path, fileflags, op->reports) != 0)
 +      int write_result = wm_file_write(C, path, fileflags, op->reports);
 +
 +      if ((op->flag & OP_IS_INVOKE) == 0) {
 +              /* OP_IS_INVOKE is set when the operator is called from the GUI.
 +               * If it is not set, the operator is called from a script and
 +               * shouldn't influence G.fileflags. */
 +              G.fileflags = orig_fileflags;
 +      }
 +
 +      if (write_result != 0) {
                return OPERATOR_CANCELLED;
 +      }
  
        WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
  
- #if 0 /* XXX: Remove? This is not currently defined as a valid property */
-       if (RNA_boolean_get(op->ptr, "exit")) {
+       if (!is_save_as && RNA_boolean_get(op->ptr, "exit")) {
                wm_exit_schedule_delayed(C);
        }
- #endif
  
        return OPERATOR_FINISHED;
  }