Fix saving a quit.blend on exit when a file failed to load

When a file passed in from the command line failed to load,
blender would exit & save the quit.blend.

Resolve by adding a `do_user_exit_actions` to WM_exit_ex which is
false in backgrounds mode or when an error has occurred.

---

Back-ported [0] & [1] from main with fix [2] included.

[0]: c803ddab29
[1]: d7d1c524e3
[2]: d3d91b79e0
This commit is contained in:
Campbell Barton 2023-05-31 10:17:39 +10:00
parent 71079b7957
commit b2950b2ad7
6 changed files with 34 additions and 19 deletions

View File

@ -429,8 +429,7 @@ extern "C" int GHOST_HACK_getFirstFile(char buf[FIRSTFILEBUFLG])
- (void)applicationWillTerminate:(NSNotification *)aNotification
{
#if 0
G.is_break = false; /* Let Cocoa perform the termination at the end. */
WM_exit(C);
WM_exit(C, EXIT_SUCCESS);
#endif
}

View File

@ -22,7 +22,7 @@ static PyObject *bpy_atexit(PyObject *UNUSED(self), PyObject *UNUSED(args), PyOb
/* close down enough of blender at least not to crash */
struct bContext *C = BPY_context_get();
WM_exit_ex(C, false);
WM_exit_ex(C, false, false);
Py_RETURN_NONE;
}

View File

@ -100,16 +100,29 @@ void WM_init_input_devices(void);
*/
void WM_init(struct bContext *C, int argc, const char **argv);
/**
* \param do_python: Free all data associated with Blender's Python integration.
* Also exit the Python interpreter (unless `WITH_PYTHON_MODULE` is enabled).
* \param do_user_exit_actions: When enabled perform actions associated with a user
* having been using Blender then exiting. Actions such as writing the auto-save
* and writing any changes to preferences.
* Set to false in background mode or when exiting because of failed command line argument parsing.
* In general automated actions where the user isn't making changes should pass in false too.
*
* \note doesn't run exit() call #WM_exit() for that.
*/
void WM_exit_ex(struct bContext *C, bool do_python);
void WM_exit_ex(struct bContext *C, bool do_python, bool do_user_exit_actions);
/**
* \brief Main exit function to close Blender ordinarily.
* \note Use #wm_exit_schedule_delayed() to close Blender from an operator.
* Might leak memory otherwise.
*
* \param exit_code: Passed to #exit, typically #EXIT_SUCCESS or #EXIT_FAILURE should be used.
* With failure being used for an early exit when parsing command line arguments fails.
* Note that any exit-code besides #EXIT_SUCCESS calls #WM_exit_ex with its `do_user_exit_actions`
* argument set to false.
*/
void WM_exit(struct bContext *C) ATTR_NORETURN;
void WM_exit(struct bContext *C, int exit_code) ATTR_NORETURN;
void WM_main(struct bContext *C) ATTR_NORETURN;

View File

@ -450,10 +450,7 @@ static void wait_for_console_key(void)
static int wm_exit_handler(bContext *C, const wmEvent *event, void *userdata)
{
/* Prevent a non-zero exit code (if escape was pressed by the user). */
G.is_break = false;
WM_exit(C);
WM_exit(C, EXIT_SUCCESS);
UNUSED_VARS(event, userdata);
return WM_UI_HANDLER_BREAK;
@ -475,15 +472,21 @@ void wm_exit_schedule_delayed(const bContext *C)
void UV_clipboard_free();
void WM_exit_ex(bContext *C, const bool do_python)
void WM_exit_ex(bContext *C, const bool do_python, const bool do_user_exit_actions)
{
wmWindowManager *wm = C ? CTX_wm_manager(C) : nullptr;
/* While nothing technically prevents saving user data in background mode,
* don't do this as not typically useful and more likely to cause problems
* if automated scripts happen to write changes to the preferences for e.g.
* Saving #BLENDER_QUIT_FILE is also not likely to be desired either. */
BLI_assert(G.background ? (do_user_exit_actions == false) : true);
/* first wrap up running stuff, we assume only the active WM is running */
/* modal handlers are on window level freed, others too? */
/* NOTE: same code copied in `wm_files.cc`. */
if (C && wm) {
if (!G.background) {
if (do_user_exit_actions) {
struct MemFile *undo_memfile = wm->undo_stack ?
ED_undosys_stack_memfile_get_active(wm->undo_stack) :
nullptr;
@ -517,7 +520,7 @@ void WM_exit_ex(bContext *C, const bool do_python)
ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
if (!G.background) {
if (do_user_exit_actions) {
if ((U.pref_flag & USER_PREF_FLAG_SAVE) && ((G.f & G_FLAG_USERPREF_NO_SAVE_ON_EXIT) == 0)) {
if (U.runtime.is_dirty) {
BKE_blendfile_userdef_write_all(nullptr);
@ -693,9 +696,10 @@ void WM_exit_ex(bContext *C, const bool do_python)
CLG_exit();
}
void WM_exit(bContext *C)
void WM_exit(bContext *C, const int exit_code)
{
WM_exit_ex(C, true);
const bool do_user_exit_actions = G.background ? false : (exit_code == EXIT_SUCCESS);
WM_exit_ex(C, true, do_user_exit_actions);
printf("\nBlender quit\n");
@ -707,7 +711,7 @@ void WM_exit(bContext *C)
}
#endif
exit(G.is_break == true);
exit(exit_code);
}
void WM_script_tag_reload(void)

View File

@ -574,7 +574,7 @@ int main(int argc,
#ifndef WITH_PYTHON_MODULE
if (G.background) {
/* Using window-manager API in background-mode is a bit odd, but works fine. */
WM_exit(C);
WM_exit(C, G.is_break ? EXIT_FAILURE : EXIT_SUCCESS);
}
else {
/* Shows the splash as needed. */
@ -594,7 +594,7 @@ int main(int argc,
#ifdef WITH_PYTHON_MODULE
void main_python_exit(void)
{
WM_exit_ex((bContext *)evil_C, true);
WM_exit_ex((bContext *)evil_C, true, false);
evil_C = NULL;
}
#endif

View File

@ -2105,8 +2105,7 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data)
if (error_msg) {
fprintf(stderr, "Error: %s, exiting! %s\n", error_msg, filepath);
G.is_break = true;
WM_exit(C);
WM_exit(C, EXIT_FAILURE);
/* Unreachable, return for clarity. */
return -1;
}