diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 1d3d35699f..b93f80c45e 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -9239,7 +9239,7 @@ static int materialui_list_push(void *data, void *userdata, } else { - if (system->load_no_content) + if (system && system->load_no_content) { MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( info->list, diff --git a/menu/drivers/ozone.c b/menu/drivers/ozone.c index e1cc729ee2..37965c11b2 100644 --- a/menu/drivers/ozone.c +++ b/menu/drivers/ozone.c @@ -7899,7 +7899,7 @@ static int ozone_list_push(void *data, void *userdata, } else { - if (system->load_no_content) + if (system && system->load_no_content) { MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( info->list, diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index e7f71265cd..fe82be8a2f 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -7107,7 +7107,7 @@ static int xmb_list_push(void *data, void *userdata, } else { - if (system->load_no_content) + if (system && system->load_no_content) { MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM( info->list, diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 3a30337d81..6e1fa15ddd 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -8061,23 +8061,73 @@ int generic_menu_entry_action( } #endif - if (menu_st->pending_close_content) + if (menu_st->pending_close_content || + menu_st->pending_env_shutdown_flush) { - const char *content_path = path_get(RARCH_PATH_CONTENT); - const char *menu_flush_to = msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU); + const char *content_path = menu_st->pending_env_shutdown_flush ? + menu_st->pending_env_shutdown_content_path : + path_get(RARCH_PATH_CONTENT); + const char *deferred_path = menu ? menu->deferred_path : NULL; + const char *flush_target = msg_hash_to_str(MENU_ENUM_LABEL_MAIN_MENU); + size_t stack_offset = 1; + bool reset_navigation = true; - /* Flush to playlist entry menu if launched via playlist */ - if (menu && - !string_is_empty(menu->deferred_path) && - !string_is_empty(content_path) && - string_is_equal(menu->deferred_path, content_path)) - menu_flush_to = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS); + /* Loop backwards through the menu stack to + * find a known reference point */ + while (menu_stack && (menu_stack->size >= stack_offset)) + { + const char *parent_label = NULL; - command_event(CMD_EVENT_UNLOAD_CORE, NULL); - menu_entries_flush_stack(menu_flush_to, 0); + file_list_get_at_offset(menu_stack, + menu_stack->size - stack_offset, + NULL, &parent_label, NULL, NULL); + + if (string_is_empty(parent_label)) + continue; + + /* If core was launched via a playlist, flush + * to playlist entry menu */ + if (string_is_equal(parent_label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS)) && + (!string_is_empty(deferred_path) && + !string_is_empty(content_path) && + string_is_equal(deferred_path, content_path))) + { + flush_target = msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_RPL_ENTRY_ACTIONS); + break; + } + /* If core was launched via standalone cores menu, + * flush to standalone cores menu */ + else if (string_is_equal(parent_label, + msg_hash_to_str(MENU_ENUM_LABEL_CONTENTLESS_CORES_TAB)) || + string_is_equal(parent_label, + msg_hash_to_str(MENU_ENUM_LABEL_DEFERRED_CONTENTLESS_CORES_LIST))) + { + flush_target = parent_label; + reset_navigation = false; + break; + } + + stack_offset++; + } + + if (!menu_st->pending_env_shutdown_flush) + command_event(CMD_EVENT_UNLOAD_CORE, NULL); + + menu_entries_flush_stack(flush_target, 0); + /* An annoyance - some menu drivers (Ozone...) call + * RARCH_MENU_CTL_SET_PREVENT_POPULATE in awkward + * places, which can cause breakage here when flushing + * the menu stack. We therefore have to force a + * RARCH_MENU_CTL_UNSET_PREVENT_POPULATE */ menu_driver_ctl(RARCH_MENU_CTL_UNSET_PREVENT_POPULATE, NULL); - menu_st->selection_ptr = 0; - menu_st->pending_close_content = false; + + if (reset_navigation) + menu_st->selection_ptr = 0; + + menu_st->pending_close_content = false; + menu_st->pending_env_shutdown_flush = false; + menu_st->pending_env_shutdown_content_path[0] = '\0'; } return ret; diff --git a/menu/menu_driver.h b/menu/menu_driver.h index 0afa910d28..5666c61bed 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -501,6 +501,12 @@ struct menu_state /* Storage container for current menu datetime * representation string */ char datetime_cache[255]; + /* Filled with current content path when a core calls + * RETRO_ENVIRONMENT_SHUTDOWN. Value is required in + * generic_menu_entry_action(), and must be cached + * since RETRO_ENVIRONMENT_SHUTDOWN will cause + * RARCH_PATH_CONTENT to be cleared */ + char pending_env_shutdown_content_path[PATH_MAX_LENGTH]; #ifdef HAVE_MENU char input_dialog_kb_label_setting[256]; @@ -520,6 +526,9 @@ struct menu_state bool entries_nonblocking_refresh; /* 'Close Content'-hotkey menu resetting */ bool pending_close_content; + /* Flagged when a core calls RETRO_ENVIRONMENT_SHUTDOWN, + * requiring the menu to be flushed on the next iteration */ + bool pending_env_shutdown_flush; /* Screensaver status * - Does menu driver support screensaver functionality? * - Is screensaver currently active? */ diff --git a/retroarch.c b/retroarch.c index 5a27fbbe2d..2fc3c89ad6 100644 --- a/retroarch.c +++ b/retroarch.c @@ -1875,6 +1875,7 @@ bool command_event(enum event_command cmd, void *data) break; case CMD_EVENT_UNLOAD_CORE: { + bool load_dummy_core = data ? *(bool*)data : true; bool contentless = false; bool is_inited = false; content_ctx_info_t content_info = {0}; @@ -1936,7 +1937,7 @@ bool command_event(enum event_command cmd, void *data) else input_remapping_restore_global_config(true); - if (is_inited) + if (is_inited && load_dummy_core) { #ifdef HAVE_MENU if ( (settings->uints.quit_on_close_content == QUIT_ON_CLOSE_CONTENT_CLI && global->launched_from_cli) diff --git a/runloop.c b/runloop.c index ea83727288..86b9da96a2 100644 --- a/runloop.c +++ b/runloop.c @@ -1900,48 +1900,34 @@ bool runloop_environment_cb(unsigned cmd, void *data) } case RETRO_ENVIRONMENT_SHUTDOWN: - RARCH_LOG("[Environ]: SHUTDOWN.\n"); - - /* This case occurs when a core (internally) requests - * a shutdown event. Must save runtime log file here, - * since normal command.c CMD_EVENT_CORE_DEINIT event - * will not occur until after the current content has - * been cleared (causing log to be skipped) */ - runloop_runtime_log_deinit(runloop_st, - settings->bools.content_runtime_log, - settings->bools.content_runtime_log_aggregate, - settings->paths.directory_runtime_log, - settings->paths.directory_playlist); - - /* Similarly, since the CMD_EVENT_CORE_DEINIT will - * be called *after* the runloop state has been - * cleared, must also perform the following actions - * here: - * - Disable any active config overrides - * - Unload any active input remaps */ -#ifdef HAVE_CONFIGFILE - if (runloop_st->overrides_active) - { - /* Reload the original config */ - config_unload_override(); - runloop_st->overrides_active = false; - } + { +#ifdef HAVE_MENU + struct menu_state *menu_st = menu_state_get_ptr(); #endif - if ( runloop_st->remaps_core_active - || runloop_st->remaps_content_dir_active - || runloop_st->remaps_game_active - || !string_is_empty(runloop_st->name.remapfile) - ) - { - input_remapping_deinit(true); - input_remapping_set_defaults(true); - } - else - input_remapping_restore_global_config(true); + /* This case occurs when a core (internally) + * requests a shutdown event */ + RARCH_LOG("[Environ]: SHUTDOWN.\n"); runloop_st->shutdown_initiated = true; runloop_st->core_shutdown_initiated = true; +#ifdef HAVE_MENU + /* Ensure that menu stack is flushed appropriately + * after the core has stopped running */ + if (menu_st) + { + const char *content_path = path_get(RARCH_PATH_CONTENT); + + menu_st->pending_env_shutdown_flush = true; + if (!string_is_empty(content_path)) + strlcpy(menu_st->pending_env_shutdown_content_path, + content_path, + sizeof(menu_st->pending_env_shutdown_content_path)); + else + menu_st->pending_env_shutdown_content_path[0] = '\0'; + } +#endif break; + } case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL: if (system) @@ -6531,30 +6517,36 @@ static enum runloop_state_enum runloop_check_state( if (runloop_exec) runloop_exec = false; - if (runloop_st->core_shutdown_initiated && - settings->bools.load_dummy_on_core_shutdown) + if (runloop_st->core_shutdown_initiated) { - content_ctx_info_t content_info; + bool load_dummy_core = false; - content_info.argc = 0; - content_info.argv = NULL; - content_info.args = NULL; - content_info.environ_get = NULL; + runloop_st->core_shutdown_initiated = false; - if (task_push_start_dummy_core(&content_info)) + /* Check whether dummy core should be loaded + * instead of exiting RetroArch completely + * (aborts shutdown if invoked) */ + if (settings->bools.load_dummy_on_core_shutdown) { - /* Loads dummy core instead of exiting RetroArch completely. - * Aborts core shutdown if invoked. */ - runloop_st->shutdown_initiated = false; - runloop_st->core_shutdown_initiated = false; + load_dummy_core = true; + runloop_st->shutdown_initiated = false; } - else - quit_runloop = true; + + /* Unload current core, and load dummy if + * required */ + if (!command_event(CMD_EVENT_UNLOAD_CORE, &load_dummy_core)) + { + runloop_st->shutdown_initiated = true; + quit_runloop = true; + } + + if (!load_dummy_core) + quit_runloop = true; } else quit_runloop = true; - runloop_st->core_running = false; + runloop_st->core_running = false; if (quit_runloop) {