diff --git a/command.c b/command.c index 04118a1728..83dc781f8b 100644 --- a/command.c +++ b/command.c @@ -1955,6 +1955,20 @@ bool command_event(enum event_command cmd, void *data) break; case CMD_EVENT_UNLOAD_CORE: case CMD_EVENT_QUIT: +#ifdef HAVE_MENU + if (settings->confirm_on_exit) + { + if (menu_driver_ctl(RARCH_MENU_CTL_IS_QUIT_CONFIRM, NULL)) + { + runloop_ctl(RUNLOOP_CTL_SET_QUIT, NULL); + } + else if (!menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_QUIT_CONFIRM, NULL)) + { + runloop_ctl(RUNLOOP_CTL_SHOW_MESSAGE, NULL); + break; + } + } +#endif command_event(CMD_EVENT_AUTOSAVE_STATE, NULL); command_event(CMD_EVENT_DISABLE_OVERRIDES, NULL); command_event(CMD_EVENT_RESTORE_DEFAULT_SHADER_PRESET, NULL); diff --git a/config.def.h b/config.def.h index afae6bf19a..c04d125fba 100644 --- a/config.def.h +++ b/config.def.h @@ -511,6 +511,8 @@ static unsigned aspect_ratio_idx = ASPECT_RATIO_CORE; /* Save configuration file on exit. */ static bool config_save_on_exit = true; +static bool confirm_on_exit = false; + static bool show_hidden_files = true; static const bool overlay_hide_in_menu = true; diff --git a/configuration.c b/configuration.c index e83bd56760..4ec8136f92 100644 --- a/configuration.c +++ b/configuration.c @@ -795,6 +795,7 @@ static int populate_settings_bool(settings_t *settings, struct config_bool_setti SETTING_BOOL("sort_savefiles_enable", &settings->sort_savefiles_enable, true, default_sort_savefiles_enable, false); SETTING_BOOL("sort_savestates_enable", &settings->sort_savestates_enable, true, default_sort_savestates_enable, false); SETTING_BOOL("config_save_on_exit", &settings->config_save_on_exit, true, config_save_on_exit, false); + SETTING_BOOL("confirm_on_exit", &settings->confirm_on_exit, true, confirm_on_exit, false); SETTING_BOOL("show_hidden_files", &settings->show_hidden_files, true, show_hidden_files, false); SETTING_BOOL("input_autodetect_enable", &settings->input.autodetect_enable, true, input_autodetect_enable, false); SETTING_BOOL("audio_rate_control", &settings->audio.rate_control, true, rate_control, false); diff --git a/configuration.h b/configuration.h index e0b78dd2e7..ede199aa06 100644 --- a/configuration.h +++ b/configuration.h @@ -445,6 +445,7 @@ typedef struct settings #endif bool config_save_on_exit; + bool confirm_on_exit; bool show_hidden_files; #ifdef HAVE_LAKKA diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index fb56626bc2..cc3c847dca 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -991,6 +991,9 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) #endif ); break; + case MENU_ENUM_LABEL_CONFIRM_ON_EXIT: + snprintf(s, len, "Are you sure you want to quit?"); + break; case MENU_ENUM_LABEL_SHOW_HIDDEN_FILES: snprintf(s, len, "Show hidden files\n" "and folders."); @@ -2522,6 +2525,8 @@ static const char *menu_hash_to_str_us_label_enum(enum msg_hash_enums msg) return "auto_overrides_enable"; case MENU_ENUM_LABEL_CONFIG_SAVE_ON_EXIT: return "config_save_on_exit"; + case MENU_ENUM_LABEL_CONFIRM_ON_EXIT: + return "confirm_on_exit"; case MENU_ENUM_LABEL_SHOW_HIDDEN_FILES: return "show_hidden_files"; case MENU_ENUM_LABEL_VIDEO_SMOOTH: @@ -3847,6 +3852,8 @@ const char *msg_hash_to_str_us(enum msg_hash_enums msg) return "Load Override Files Automatically"; case MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT: return "Save Configuration On Exit"; + case MENU_ENUM_LABEL_VALUE_CONFIRM_ON_EXIT: + return "Ask For Confirmation On Exit"; case MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES: return "Show Hidden Files and Folders"; case MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH: diff --git a/menu/drivers/menu_generic.c b/menu/drivers/menu_generic.c index 2e0a87ede5..f7d7df1741 100644 --- a/menu/drivers/menu_generic.c +++ b/menu/drivers/menu_generic.c @@ -77,6 +77,11 @@ static int action_iterate_help(menu_handle_t *menu, } } break; + case MENU_HELP_CONFIRM_ON_EXIT: + menu_hash_get_help_enum( + MENU_ENUM_LABEL_CONFIRM_ON_EXIT, + s, len); + break; case MENU_HELP_CONTROLS: { unsigned i; @@ -303,7 +308,25 @@ int generic_menu_iterate(void *data, void *userdata, enum menu_action action) BIT64_SET(menu->state, MENU_STATE_RENDER_MESSAGEBOX); BIT64_SET(menu->state, MENU_STATE_POST_ITERATE); if (ret == 1 || action == MENU_ACTION_OK) + { + if (menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_QUIT_CONFIRM, NULL)) + { + menu_driver_ctl(RARCH_MENU_CTL_SET_QUIT_CONFIRM, NULL); + command_event(CMD_EVENT_QUIT, NULL); + } + BIT64_SET(menu->state, MENU_STATE_POP_STACK); + } + + if (action == MENU_ACTION_CANCEL) + { + if (menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_QUIT_CONFIRM, NULL)) + { + menu_driver_ctl(RARCH_MENU_CTL_UNSET_PENDING_QUIT_CONFIRM, NULL); + BIT64_SET(menu->state, MENU_STATE_POP_STACK); + } + } + break; case ITERATE_TYPE_BIND: { @@ -432,16 +455,16 @@ int generic_menu_iterate(void *data, void *userdata, enum menu_action action) /* Have to defer it so we let settings refresh. */ if (menu->push_help_screen) { - menu_displaylist_info_t info = {0}; - - info.list = menu_stack; - strlcpy(info.label, - msg_hash_to_str(MENU_ENUM_LABEL_HELP), - sizeof(info.label)); - info.enum_idx = MENU_ENUM_LABEL_HELP; - - menu_displaylist_ctl(DISPLAYLIST_HELP, &info); + menu_display_show_message(); } + + if (action == MENU_ACTION_SHOW_MESSAGE) + { + menu->help_screen_type = MENU_HELP_CONFIRM_ON_EXIT; + menu_driver_ctl(RARCH_MENU_CTL_SET_PENDING_QUIT_CONFIRM, NULL); + menu_display_show_message(); + } + break; } diff --git a/menu/menu_display.c b/menu/menu_display.c index 222d882c5a..fc511bc024 100644 --- a/menu/menu_display.c +++ b/menu/menu_display.c @@ -834,3 +834,16 @@ void menu_display_reset_textures_list(const char *texture_path, const char *icon TEXTURE_FILTER_MIPMAP_LINEAR, item); image_texture_free(&ti); } + +void menu_display_show_message() { + file_list_t *menu_stack = menu_entries_get_menu_stack_ptr(0); + menu_displaylist_info_t info = {0}; + + info.list = menu_stack; + strlcpy(info.label, + msg_hash_to_str(MENU_ENUM_LABEL_HELP), + sizeof(info.label)); + info.enum_idx = MENU_ENUM_LABEL_HELP; + + menu_displaylist_ctl(DISPLAYLIST_HELP, &info); +} diff --git a/menu/menu_display.h b/menu/menu_display.h index 145d129519..fbd966f6e6 100644 --- a/menu/menu_display.h +++ b/menu/menu_display.h @@ -246,6 +246,8 @@ void menu_display_draw_cursor( void menu_display_draw_text(const char *msg, int width, int height, struct font_params *params); +void menu_display_show_message(); + bool menu_display_shader_pipeline_active(void); void menu_display_set_alpha(float *color, float alpha_value); diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 227ed5a403..2dad0e7e82 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -4337,6 +4337,9 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type, void *data) menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_CONFIG_SAVE_ON_EXIT, PARSE_ONLY_BOOL, false); + menu_displaylist_parse_settings_enum(menu, info, + MENU_ENUM_LABEL_CONFIRM_ON_EXIT, + PARSE_ONLY_BOOL, false); menu_displaylist_parse_settings_enum(menu, info, MENU_ENUM_LABEL_CORE_SPECIFIC_CONFIG, PARSE_ONLY_BOOL, false); diff --git a/menu/menu_driver.c b/menu/menu_driver.c index 4a12bbc409..f3ebb41665 100644 --- a/menu/menu_driver.c +++ b/menu/menu_driver.c @@ -70,8 +70,10 @@ static bool menu_driver_prevent_populate = false; static bool menu_driver_load_no_content = false; static bool menu_driver_alive = false; static bool menu_driver_data_own = false; -static bool menu_driver_pending_quit = false; static bool menu_driver_pending_shutdown = false; +static bool menu_driver_pending_quit = false; +static bool menu_driver_pending_quit_confirm = false; +static bool menu_driver_quit_confirm = false; static playlist_t *menu_driver_playlist = NULL; static struct video_shader *menu_driver_shader = NULL; static menu_handle_t *menu_driver_data = NULL; @@ -338,6 +340,19 @@ bool menu_driver_ctl(enum rarch_menu_ctl_state state, void *data) case RARCH_MENU_CTL_UNSET_PENDING_SHUTDOWN: menu_driver_pending_shutdown = false; break; + case RARCH_MENU_CTL_IS_PENDING_QUIT_CONFIRM: + return menu_driver_pending_quit_confirm; + case RARCH_MENU_CTL_SET_PENDING_QUIT_CONFIRM: + menu_driver_pending_quit_confirm = true; + break; + case RARCH_MENU_CTL_UNSET_PENDING_QUIT_CONFIRM: + menu_driver_pending_quit_confirm = false; + break; + case RARCH_MENU_CTL_IS_QUIT_CONFIRM: + return menu_driver_quit_confirm; + case RARCH_MENU_CTL_SET_QUIT_CONFIRM: + menu_driver_quit_confirm = true; + break; case RARCH_MENU_CTL_DESTROY: menu_driver_pending_quick_menu = false; menu_driver_pending_quit = false; diff --git a/menu/menu_driver.h b/menu/menu_driver.h index c28e227ceb..38d76b4545 100644 --- a/menu/menu_driver.h +++ b/menu/menu_driver.h @@ -68,6 +68,7 @@ enum menu_help_type { MENU_HELP_NONE = 0, MENU_HELP_WELCOME, + MENU_HELP_CONFIRM_ON_EXIT, MENU_HELP_EXTRACT, MENU_HELP_CONTROLS, MENU_HELP_CHEEVOS_DESCRIPTION, @@ -108,6 +109,11 @@ enum rarch_menu_ctl_state RARCH_MENU_CTL_IS_PENDING_SHUTDOWN, RARCH_MENU_CTL_SET_PENDING_SHUTDOWN, RARCH_MENU_CTL_UNSET_PENDING_SHUTDOWN, + RARCH_MENU_CTL_IS_PENDING_QUIT_CONFIRM, + RARCH_MENU_CTL_SET_PENDING_QUIT_CONFIRM, + RARCH_MENU_CTL_UNSET_PENDING_QUIT_CONFIRM, + RARCH_MENU_CTL_IS_QUIT_CONFIRM, + RARCH_MENU_CTL_SET_QUIT_CONFIRM, RARCH_MENU_CTL_DEINIT, RARCH_MENU_CTL_INIT, RARCH_MENU_CTL_SHADER_DEINIT, diff --git a/menu/menu_input.h b/menu/menu_input.h index 7b7a8b8a26..3005556457 100644 --- a/menu/menu_input.h +++ b/menu/menu_input.h @@ -42,7 +42,8 @@ enum menu_action MENU_ACTION_SCROLL_UP, MENU_ACTION_TOGGLE, MENU_ACTION_POINTER_MOVED, - MENU_ACTION_POINTER_PRESSED + MENU_ACTION_POINTER_PRESSED, + MENU_ACTION_SHOW_MESSAGE }; enum menu_input_pointer_state diff --git a/menu/menu_setting.c b/menu/menu_setting.c index c3c0121ee8..7cf9ed40e2 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -2898,6 +2898,22 @@ static bool setting_append_list( SD_FLAG_NONE); menu_settings_list_current_add_enum_idx(list, list_info, MENU_ENUM_LABEL_CONFIG_SAVE_ON_EXIT); + CONFIG_BOOL( + list, list_info, + &settings->confirm_on_exit, + msg_hash_to_str(MENU_ENUM_LABEL_CONFIRM_ON_EXIT), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONFIRM_ON_EXIT), + confirm_on_exit, + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF), + msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON), + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + menu_settings_list_current_add_enum_idx(list, list_info, MENU_ENUM_LABEL_CONFIRM_ON_EXIT); + CONFIG_BOOL( list, list_info, &settings->show_hidden_files, diff --git a/msg_hash.h b/msg_hash.h index cfed2d7095..89baea038c 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1147,6 +1147,9 @@ enum msg_hash_enums MENU_ENUM_LABEL_CONFIG_SAVE_ON_EXIT, MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT, + MENU_ENUM_LABEL_CONFIRM_ON_EXIT, + MENU_ENUM_LABEL_VALUE_CONFIRM_ON_EXIT, + MENU_ENUM_LABEL_SHOW_HIDDEN_FILES, MENU_ENUM_LABEL_VALUE_SHOW_HIDDEN_FILES, diff --git a/retroarch.cfg b/retroarch.cfg index f03e81c55f..bd2554fdf6 100644 --- a/retroarch.cfg +++ b/retroarch.cfg @@ -119,6 +119,9 @@ # Overwrites the config. #include's and comments are not preserved. # config_save_on_exit = true +# Ask for confirmation on exit. +# confirm_on_exit = false + # Load up a specific config file based on the core being used. # core_specific_config = false diff --git a/runloop.c b/runloop.c index 6f3fe104af..5272d5c659 100644 --- a/runloop.c +++ b/runloop.c @@ -124,6 +124,7 @@ static bool runloop_core_shutdown_initiated = false; static bool runloop_perfcnt_enable = false; static bool runloop_overrides_active = false; static bool runloop_game_options_active = false; +static bool runloop_quit = false; static core_option_manager_t *runloop_core_options = NULL; #ifdef HAVE_THREADS static slock_t *_runloop_msg_queue_lock = NULL; @@ -752,6 +753,36 @@ static bool runloop_is_frame_count_end(void) return runloop_max_frames && (*frame_count >= runloop_max_frames); } +#ifdef HAVE_MENU +static int runloop_iterate_menu(enum menu_action action, unsigned *sleep_ms) +{ + menu_ctx_iterate_t iter; + settings_t *settings = config_get_ptr(); + bool focused = runloop_is_focused() && + !ui_companion_is_on_foreground(); + bool is_idle = runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL); + + iter.action = action; + + if (!menu_driver_ctl(RARCH_MENU_CTL_ITERATE, &iter)) + rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); + + if (focused || !is_idle) + menu_driver_ctl(RARCH_MENU_CTL_RENDER, NULL); + + if (sleep_ms && (!focused || is_idle)) + { + *sleep_ms = 10; + return 1; + } + + if (!settings->menu.throttle_framerate && !settings->fastforward_ratio) + return 0; + + return -1; +} +#endif + bool runloop_ctl(enum runloop_ctl_state state, void *data) { @@ -1255,6 +1286,16 @@ bool runloop_ctl(enum runloop_ctl_state state, void *data) httpserver_destroy(); #endif break; + case RUNLOOP_CTL_SHOW_MESSAGE: +#ifdef HAVE_MENU + runloop_iterate_menu(MENU_ACTION_SHOW_MESSAGE, NULL); +#endif + break; + case RUNLOOP_CTL_IS_QUIT: + return runloop_quit; + case RUNLOOP_CTL_SET_QUIT: + runloop_quit = true; + break; case RUNLOOP_CTL_NONE: default: break; @@ -1263,7 +1304,6 @@ bool runloop_ctl(enum runloop_ctl_state state, void *data) return true; } - #ifdef HAVE_OVERLAY static void runloop_iterate_linefeed_overlay(settings_t *settings) { @@ -1350,36 +1390,6 @@ static INLINE int runloop_iterate_time_to_exit(bool quit_key_pressed) return -1; } -#ifdef HAVE_MENU -static int runloop_iterate_menu(enum menu_action action, unsigned *sleep_ms) -{ - menu_ctx_iterate_t iter; - settings_t *settings = config_get_ptr(); - bool focused = runloop_is_focused() && - !ui_companion_is_on_foreground(); - bool is_idle = runloop_ctl(RUNLOOP_CTL_IS_IDLE, NULL); - - iter.action = action; - - if (!menu_driver_ctl(RARCH_MENU_CTL_ITERATE, &iter)) - rarch_ctl(RARCH_CTL_MENU_RUNNING_FINISHED, NULL); - - if (focused || !is_idle) - menu_driver_ctl(RARCH_MENU_CTL_RENDER, NULL); - - if (!focused || is_idle) - { - *sleep_ms = 10; - return 1; - } - - if (!settings->menu.throttle_framerate && !settings->fastforward_ratio) - return 0; - - return -1; -} -#endif - /** * runloop_iterate: * @@ -1501,6 +1511,32 @@ int runloop_iterate(unsigned *sleep_ms) runloop_iterate_linefeed_overlay(settings); #endif +#ifdef HAVE_MENU + if (runloop_iterate_time_to_exit( + runloop_cmd_press(cmd_ptr, RARCH_QUIT_KEY)) != 1 || + runloop_ctl(RUNLOOP_CTL_IS_QUIT, NULL)) + { + if (settings->confirm_on_exit) + { + if(!menu_driver_ctl(RARCH_MENU_CTL_IS_PENDING_QUIT_CONFIRM, NULL)) + { + command_event(CMD_EVENT_QUIT, NULL); + } + else if (menu_driver_ctl(RARCH_MENU_CTL_IS_QUIT_CONFIRM, NULL)) + { + frame_limit_last_time = 0.0; + command_event(CMD_EVENT_QUIT, NULL); + return -1; + } + } + else + { + frame_limit_last_time = 0.0; + command_event(CMD_EVENT_QUIT, NULL); + return -1; + } + } +#else if (runloop_iterate_time_to_exit( runloop_cmd_press(cmd_ptr, RARCH_QUIT_KEY)) != 1) { @@ -1508,6 +1544,7 @@ int runloop_iterate(unsigned *sleep_ms) command_event(CMD_EVENT_QUIT, NULL); return -1; } +#endif #ifdef HAVE_MENU diff --git a/runloop.h b/runloop.h index c2c7625236..22e9db7760 100644 --- a/runloop.h +++ b/runloop.h @@ -132,7 +132,12 @@ enum runloop_ctl_state /* HTTP server */ RUNLOOP_CTL_HTTPSERVER_INIT, - RUNLOOP_CTL_HTTPSERVER_DESTROY + RUNLOOP_CTL_HTTPSERVER_DESTROY, + + RUNLOOP_CTL_SHOW_MESSAGE, + + RUNLOOP_CTL_IS_QUIT, + RUNLOOP_CTL_SET_QUIT }; typedef struct rarch_dir