diff --git a/source/creator/creator.cc b/source/creator/creator.cc index a32d5b912b9..d60b7d42e69 100644 --- a/source/creator/creator.cc +++ b/source/creator/creator.cc @@ -37,7 +37,6 @@ /* Mostly initialization functions. */ #include "BKE_appdir.hh" #include "BKE_blender.hh" -#include "BKE_blender_cli_command.hh" #include "BKE_brush.hh" #include "BKE_cachefile.hh" #include "BKE_callbacks.hh" @@ -122,6 +121,7 @@ ApplicationState app_state = []() { app_state.signal.use_crash_handler = true; app_state.signal.use_abort_handler = true; app_state.exit_code_on_error.python = 0; + app_state.main_arg_deferred = nullptr; return app_state; }(); @@ -566,16 +566,9 @@ int main(int argc, #ifndef WITH_PYTHON_MODULE if (G.background) { int exit_code; - if (app_state.command.argv) { - const char *id = app_state.command.argv[0]; - if (STREQ(id, "help")) { - BKE_blender_cli_command_print_help(); - exit_code = EXIT_SUCCESS; - } - else { - exit_code = BKE_blender_cli_command_exec( - C, id, app_state.command.argc - 1, app_state.command.argv + 1); - } + if (app_state.main_arg_deferred != nullptr) { + exit_code = main_arg_handle_deferred(); + MEM_freeN(app_state.main_arg_deferred); } else { exit_code = G.is_break ? EXIT_FAILURE : EXIT_SUCCESS; @@ -584,6 +577,9 @@ int main(int argc, WM_exit(C, exit_code); } else { + /* Not supported, although it could be made to work if needed. */ + BLI_assert(app_state.main_arg_deferred == nullptr); + /* Shows the splash as needed. */ WM_init_splash_on_startup(C); diff --git a/source/creator/creator_args.cc b/source/creator/creator_args.cc index 6d1c1f6ffb1..99bd70f18dc 100644 --- a/source/creator/creator_args.cc +++ b/source/creator/creator_args.cc @@ -35,6 +35,7 @@ # endif # include "BKE_appdir.hh" +# include "BKE_blender_cli_command.hh" # include "BKE_blender_version.h" # include "BKE_blendfile.hh" # include "BKE_context.hh" @@ -420,6 +421,57 @@ fail: /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Deferred Argument Handling + * + * Support executing an argument running instead of #WM_main which is deferred. + * Needed for arguments which are handled early but require sub-systems + * (Python in particular) * to be initialized. + * \{ */ + +struct BA_ArgCallback_Deferred { + BA_ArgCallback func; + int argc; + const char **argv; + void *data; + /** Return-code. */ + int exit_code; +}; + +static bool main_arg_deferred_is_set() +{ + return app_state.main_arg_deferred != nullptr; +} + +static void main_arg_deferred_setup(BA_ArgCallback func, int argc, const char **argv, void *data) +{ + BLI_assert(app_state.main_arg_deferred == nullptr); + BA_ArgCallback_Deferred *d = static_cast( + MEM_callocN(sizeof(*d), __func__)); + d->func = func; + d->argc = argc; + d->argv = argv; + d->data = data; + d->exit_code = 0; + app_state.main_arg_deferred = d; +} + +static void main_arg_deferred_exit_code_set(int exit_code) +{ + BA_ArgCallback_Deferred *d = app_state.main_arg_deferred; + BLI_assert(d != nullptr); + d->exit_code = exit_code; +} + +int main_arg_handle_deferred() +{ + BA_ArgCallback_Deferred *d = app_state.main_arg_deferred; + d->func(d->argc, d->argv, d->data); + return d->exit_code; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Utilities Python Context Macro (#BPY_CTX_SETUP) * \{ */ @@ -940,21 +992,34 @@ static const char arg_handle_command_set_doc[] = "\tPass '--help' after the command to see its help text.\n" "\n" "\tThis implies '--background' mode."; -static int arg_handle_command_set(int argc, const char **argv, void * /*data*/) +static int arg_handle_command_set(int argc, const char **argv, void *data) { - if (argc < 2) { - fprintf(stderr, "%s requires at least one argument\n", argv[0]); - exit(EXIT_FAILURE); - BLI_assert_unreachable(); + if (!main_arg_deferred_is_set()) { + if (argc < 2) { + fprintf(stderr, "%s requires at least one argument\n", argv[0]); + exit(EXIT_FAILURE); + BLI_assert_unreachable(); + } + /* Application "info" messages get in the way of command line output, suppress them. */ + G.quiet = true; + + background_mode_set(); + + main_arg_deferred_setup(arg_handle_command_set, argc, argv, data); + } + else { + bContext *C = static_cast(data); + const char *id = argv[1]; + int exit_code; + if (STREQ(id, "help")) { + BKE_blender_cli_command_print_help(); + exit_code = EXIT_SUCCESS; + } + else { + exit_code = BKE_blender_cli_command_exec(C, id, argc - 2, argv + 2); + } + main_arg_deferred_exit_code_set(exit_code); } - - /* Application "info" messages get in the way of command line output, suppress them. */ - G.quiet = true; - - background_mode_set(); - - app_state.command.argc = argc - 1; - app_state.command.argv = argv + 1; /* Consume remaining arguments. */ return argc - 1; @@ -2409,8 +2474,8 @@ void main_args_setup(bContext *C, bArgs *ba, bool all) ba, nullptr, "--disable-abort-handler", CB(arg_handle_abort_handler_disable), nullptr); BLI_args_add(ba, "-b", "--background", CB(arg_handle_background_mode_set), nullptr); - /* Command implies background mode. */ - BLI_args_add(ba, "-c", "--command", CB(arg_handle_command_set), nullptr); + /* Command implies background mode (defers execution). */ + BLI_args_add(ba, "-c", "--command", CB(arg_handle_command_set), C); BLI_args_add(ba, "-a", nullptr, CB(arg_handle_playback_mode), nullptr); diff --git a/source/creator/creator_intern.h b/source/creator/creator_intern.h index 92bb784e401..4a7a4a10ce0 100644 --- a/source/creator/creator_intern.h +++ b/source/creator/creator_intern.h @@ -10,6 +10,7 @@ * Functionality for main() initialization. */ +struct BA_ArgCallback_Deferred; struct bArgs; struct bContext; @@ -33,6 +34,12 @@ void main_args_setup(struct bContext *C, struct bArgs *ba, bool all); */ int main_args_handle_load_file(int argc, const char **argv, void *data); +/** + * Handle an argument which requested deferred evaluation. + * Needed when arguments which evaluate early need Python to be initialized for example. + */ +int main_arg_handle_deferred(); + /* `creator_signals.cc` */ void main_signal_setup(void); @@ -53,12 +60,10 @@ struct ApplicationState { unsigned char python; } exit_code_on_error; - /** Storage for commands (see `--command` argument). */ - struct { - int argc; - const char **argv; - } command; + /** Store the argument state for later handling. */ + struct BA_ArgCallback_Deferred *main_arg_deferred; }; + extern struct ApplicationState app_state; /* `creator.cc` */ /**