diff --git a/core_option_manager.c b/core_option_manager.c index e99c5ffd98..3ec18f572e 100644 --- a/core_option_manager.c +++ b/core_option_manager.c @@ -20,6 +20,10 @@ #include "cheevos/cheevos.h" #endif +#ifdef HAVE_MENU +#include "menu/menu_driver.h" +#endif + #include "core_option_manager.h" #define CORE_OPTION_MANAGER_MAP_TAG "#" @@ -1637,15 +1641,24 @@ bool core_option_manager_get_visible(core_option_manager_t *opt, /** * core_option_manager_set_val: * - * @opt : options manager handle - * @idx : core option index - * @val_idx : index of the value to set + * @opt : options manager handle + * @idx : core option index + * @val_idx : index of the value to set + * @refresh_menu : flag specifying whether menu + * should be refreshed if changes + * to option visibility are detected * * Sets the core option at index @idx to the * option value corresponding to @val_idx. + * After setting the option value, a request + * will be made for the core to update the + * in-menu visibility of all options; if + * visibility changes are detected and + * @refresh_menu is true, the menu will be + * redrawn. **/ void core_option_manager_set_val(core_option_manager_t *opt, - size_t idx, size_t val_idx) + size_t idx, size_t val_idx, bool refresh_menu) { struct core_option *option = NULL; @@ -1660,22 +1673,44 @@ void core_option_manager_set_val(core_option_manager_t *opt, #ifdef HAVE_CHEEVOS rcheevos_validate_config_settings(); #endif + +#ifdef HAVE_MENU + /* Refresh menu (if required) if core option + * visibility has changed as a result of modifying + * the current option value */ + if (rarch_ctl(RARCH_CTL_CORE_OPTION_UPDATE_DISPLAY, NULL) && + refresh_menu) + { + bool refresh = false; + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + } +#endif } /** * core_option_manager_adjust_val: * - * @opt : options manager handle - * @idx : core option index - * @adjustment : offset to apply from current - * value index + * @opt : options manager handle + * @idx : core option index + * @adjustment : offset to apply from current + * value index + * @refresh_menu : flag specifying whether menu + * should be refreshed if changes + * to option visibility are detected * - * Modifies the value of the core option at index - * @idx by incrementing the current option value index - * by @adjustment. + * Modifies the value of the core option at + * index @idx by incrementing the current option + * value index by @adjustment. + * After setting the option value, a request + * will be made for the core to update the + * in-menu visibility of all options; if + * visibility changes are detected and + * @refresh_menu is true, the menu will be + * redrawn. **/ void core_option_manager_adjust_val(core_option_manager_t* opt, - size_t idx, int adjustment) + size_t idx, int adjustment, bool refresh_menu) { struct core_option* option = NULL; @@ -1690,18 +1725,41 @@ void core_option_manager_adjust_val(core_option_manager_t* opt, #ifdef HAVE_CHEEVOS rcheevos_validate_config_settings(); #endif + +#ifdef HAVE_MENU + /* Refresh menu (if required) if core option + * visibility has changed as a result of modifying + * the current option value */ + if (rarch_ctl(RARCH_CTL_CORE_OPTION_UPDATE_DISPLAY, NULL) && + refresh_menu) + { + bool refresh = false; + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + } +#endif } /** * core_option_manager_set_default: * - * @opt : options manager handle - * @idx : core option index + * @opt : options manager handle + * @idx : core option index + * @refresh_menu : flag specifying whether menu + * should be refreshed if changes + * to option visibility are detected * - * Resets the core option at index @idx to its - * default value. + * Resets the core option at index @idx to + * its default value. + * After setting the option value, a request + * will be made for the core to update the + * in-menu visibility of all options; if + * visibility changes are detected and + * @refresh_menu is true, the menu will be + * redrawn. **/ -void core_option_manager_set_default(core_option_manager_t *opt, size_t idx) +void core_option_manager_set_default(core_option_manager_t *opt, + size_t idx, bool refresh_menu) { if (!opt || (idx >= opt->size)) @@ -1713,6 +1771,19 @@ void core_option_manager_set_default(core_option_manager_t *opt, size_t idx) #ifdef HAVE_CHEEVOS rcheevos_validate_config_settings(); #endif + +#ifdef HAVE_MENU + /* Refresh menu (if required) if core option + * visibility has changed as a result of modifying + * the current option value */ + if (rarch_ctl(RARCH_CTL_CORE_OPTION_UPDATE_DISPLAY, NULL) && + refresh_menu) + { + bool refresh = false; + menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh); + menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL); + } +#endif } /** diff --git a/core_option_manager.h b/core_option_manager.h index c7c6405b10..0a29668c9d 100644 --- a/core_option_manager.h +++ b/core_option_manager.h @@ -373,41 +373,69 @@ bool core_option_manager_get_visible(core_option_manager_t *opt, /** * core_option_manager_set_val: * - * @opt : options manager handle - * @idx : core option index - * @val_idx : index of the value to set + * @opt : options manager handle + * @idx : core option index + * @val_idx : index of the value to set + * @refresh_menu : flag specifying whether menu + * should be refreshed if changes + * to option visibility are detected * * Sets the core option at index @idx to the * option value corresponding to @val_idx. + * After setting the option value, a request + * will be made for the core to update the + * in-menu visibility of all options; if + * visibility changes are detected and + * @refresh_menu is true, the menu will be + * redrawn. **/ void core_option_manager_set_val(core_option_manager_t *opt, - size_t idx, size_t val_idx); + size_t idx, size_t val_idx, bool refresh_menu); /** * core_option_manager_adjust_val: * - * @opt : options manager handle - * @idx : core option index - * @adjustment : offset to apply from current - * value index + * @opt : options manager handle + * @idx : core option index + * @adjustment : offset to apply from current + * value index + * @refresh_menu : flag specifying whether menu + * should be refreshed if changes + * to option visibility are detected * - * Modifies the value of the core option at index - * @idx by incrementing the current option value index - * by @adjustment. + * Modifies the value of the core option at + * index @idx by incrementing the current option + * value index by @adjustment. + * After setting the option value, a request + * will be made for the core to update the + * in-menu visibility of all options; if + * visibility changes are detected and + * @refresh_menu is true, the menu will be + * redrawn. **/ void core_option_manager_adjust_val(core_option_manager_t* opt, - size_t idx, int adjustment); + size_t idx, int adjustment, bool refresh_menu); /** * core_option_manager_set_default: * - * @opt : options manager handle - * @idx : core option index + * @opt : options manager handle + * @idx : core option index + * @refresh_menu : flag specifying whether menu + * should be refreshed if changes + * to option visibility are detected * - * Resets the core option at index @idx to its - * default value. + * Resets the core option at index @idx to + * its default value. + * After setting the option value, a request + * will be made for the core to update the + * in-menu visibility of all options; if + * visibility changes are detected and + * @refresh_menu is true, the menu will be + * redrawn. **/ -void core_option_manager_set_default(core_option_manager_t *opt, size_t idx); +void core_option_manager_set_default(core_option_manager_t *opt, + size_t idx, bool refresh_menu); /** * core_option_manager_set_visible: diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 076dd25d97..d9e28bfc7c 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -1712,6 +1712,16 @@ enum retro_mod * the retro_core_options_v2_intl::local struct will be ignored. */ +#define RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK 69 + /* const struct retro_core_options_update_display_callback * -- + * Allows a frontend to signal that a core must update + * the visibility of any dynamically hidden core options, + * and enables the frontend to detect visibility changes. + * Used by the frontend to update the menu display status + * of core options without requiring a call of retro_run(). + * Must be called in retro_set_environment(). + */ + /* VFS functionality */ /* File paths: @@ -3551,6 +3561,25 @@ struct retro_core_options_v2_intl struct retro_core_options_v2 *local; }; +/* Used by the frontend to monitor changes in core option + * visibility. May be called each time any core option + * value is set via the frontend. + * - On each invocation, the core must update the visibility + * of any dynamically hidden options using the + * RETRO_ENVIRONMENT_SET_CORE_OPTIONS_DISPLAY environment + * callback. + * - On the first invocation, returns 'true' if the visibility + * of any core option has changed since the last call of + * retro_load_game() or retro_load_game_special(). + * - On each subsequent invocation, returns 'true' if the + * visibility of any core option has changed since the last + * time the function was called. */ +typedef bool (RETRO_CALLCONV *retro_core_options_update_display_callback_t)(void); +struct retro_core_options_update_display_callback +{ + retro_core_options_update_display_callback_t callback; +}; + struct retro_game_info { const char *path; /* Path to game, UTF-8 encoded. diff --git a/menu/cbs/menu_cbs_ok.c b/menu/cbs/menu_cbs_ok.c index 1df5c22470..d240541df3 100644 --- a/menu/cbs/menu_cbs_ok.c +++ b/menu/cbs/menu_cbs_ok.c @@ -3826,7 +3826,7 @@ int action_ok_core_option_dropdown_list(const char *path, /* > Update value and return */ core_option_manager_set_val(coreopts, option_index, - (option->index == 0) ? 1 : 0); + (option->index == 0) ? 1 : 0, true); return 0; @@ -6051,7 +6051,8 @@ static int action_ok_push_dropdown_setting_core_options_item_special( if (!coreopts) return -1; - core_option_manager_set_val(coreopts, core_option_idx, idx); + core_option_manager_set_val(coreopts, + core_option_idx, idx, false); return action_cancel_pop_default(NULL, NULL, 0, 0); } @@ -6066,7 +6067,8 @@ static int action_ok_push_dropdown_setting_core_options_item(const char *path, if (!coreopts) return -1; - core_option_manager_set_val(coreopts, core_option_idx, idx); + core_option_manager_set_val(coreopts, + core_option_idx, idx, false); return action_cancel_pop_default(NULL, NULL, 0, 0); } diff --git a/menu/cbs/menu_cbs_start.c b/menu/cbs/menu_cbs_start.c index 94df01e533..eee4f0450c 100644 --- a/menu/cbs/menu_cbs_start.c +++ b/menu/cbs/menu_cbs_start.c @@ -369,7 +369,7 @@ static int action_start_core_setting( core_option_manager_t *coreopts = NULL; if (rarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts)) - core_option_manager_set_default(coreopts, core_idx); + core_option_manager_set_default(coreopts, core_idx, true); return 0; } diff --git a/retroarch.c b/retroarch.c index 053a7a8894..7ab4d7572b 100644 --- a/retroarch.c +++ b/retroarch.c @@ -13521,6 +13521,12 @@ static void retroarch_fastmotion_override_free(struct rarch_state *p_rarch, retroarch_set_frame_limit(p_rarch, fastforward_ratio); } +static void retroarch_core_options_callback_free(runloop_state_t *p_runloop) +{ + /* Only a single core options callback is used at present */ + p_runloop->core_options_callback.update_display = NULL; +} + static void retroarch_system_info_free(struct rarch_state *p_rarch) { rarch_system_info_t *sys_info = &runloop_state.system; @@ -16667,6 +16673,23 @@ static bool rarch_environment_cb(unsigned cmd, void *data) } break; + case RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK: + RARCH_DBG("[Environ]: RETRO_ENVIRONMENT_SET_CORE_OPTIONS_UPDATE_DISPLAY_CALLBACK.\n"); + + { + const struct retro_core_options_update_display_callback + *update_display_callback = + (const struct retro_core_options_update_display_callback*)data; + + if (update_display_callback && + update_display_callback->callback) + runloop_state.core_options_callback.update_display = + update_display_callback->callback; + else + runloop_state.core_options_callback.update_display = NULL; + } + break; + case RETRO_ENVIRONMENT_GET_MESSAGE_INTERFACE_VERSION: RARCH_LOG("[Environ]: GET_MESSAGE_INTERFACE_VERSION.\n"); /* Current API version is 1 */ @@ -18463,6 +18486,7 @@ static void uninit_libretro_symbols( retroarch_audio_buffer_status_free(p_rarch); retroarch_game_focus_free(p_rarch); retroarch_fastmotion_override_free(p_rarch, &runloop_state); + retroarch_core_options_callback_free(&runloop_state); p_rarch->camera_driver_active = false; p_rarch->location_driver_active = false; @@ -36257,6 +36281,23 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) *coreopts = runloop_state.core_options; } break; + case RARCH_CTL_CORE_OPTION_UPDATE_DISPLAY: + if (runloop_state.core_options && + runloop_state.core_options_callback.update_display) + { + /* Note: The update_display() callback may read + * core option values via RETRO_ENVIRONMENT_GET_VARIABLE. + * This will reset the 'options updated' flag. + * We therefore have to cache the current 'options updated' + * state and restore it after the update_display() function + * returns */ + bool values_updated = runloop_state.core_options->updated; + bool display_updated = runloop_state.core_options_callback.update_display(); + + runloop_state.core_options->updated = values_updated; + return display_updated; + } + return false; #ifdef HAVE_CONFIGFILE case RARCH_CTL_IS_OVERRIDES_ACTIVE: return runloop_state.overrides_active; @@ -36325,6 +36366,7 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) retroarch_audio_buffer_status_free(p_rarch); retroarch_game_focus_free(p_rarch); retroarch_fastmotion_override_free(p_rarch, &runloop_state); + retroarch_core_options_callback_free(&runloop_state); memset(&p_rarch->input_driver_analog_requested, 0, sizeof(p_rarch->input_driver_analog_requested)); break; @@ -36360,7 +36402,8 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) unsigned *idx = (unsigned*)data; if (!idx || !runloop_state.core_options) return false; - core_option_manager_adjust_val(runloop_state.core_options, *idx, -1); + core_option_manager_adjust_val(runloop_state.core_options, + *idx, -1, true); } break; case RARCH_CTL_CORE_OPTION_NEXT: @@ -36372,7 +36415,8 @@ bool rarch_ctl(enum rarch_ctl_state state, void *data) unsigned* idx = (unsigned*)data; if (!idx || !runloop_state.core_options) return false; - core_option_manager_adjust_val(runloop_state.core_options, *idx, 1); + core_option_manager_adjust_val(runloop_state.core_options, + *idx, 1, true); } break; diff --git a/retroarch.h b/retroarch.h index d49dca46cd..658a7aacfc 100644 --- a/retroarch.h +++ b/retroarch.h @@ -158,6 +158,7 @@ enum rarch_ctl_state RARCH_CTL_CORE_OPTIONS_LIST_GET, RARCH_CTL_CORE_OPTION_PREV, RARCH_CTL_CORE_OPTION_NEXT, + RARCH_CTL_CORE_OPTION_UPDATE_DISPLAY, RARCH_CTL_CORE_IS_RUNNING, /* BSV Movie */ diff --git a/retroarch_data.h b/retroarch_data.h index 893ba26bc5..e700f59768 100644 --- a/retroarch_data.h +++ b/retroarch_data.h @@ -1668,6 +1668,20 @@ struct discord_state typedef struct discord_state discord_state_t; #endif +/* Contains all callbacks associated with + * core options. + * > At present there is only a single + * callback, 'update_display' - but we + * may wish to add more in the future + * (e.g. for directly informing a core of + * core option value changes, or getting/ + * setting extended/non-standard option + * value data types) */ +typedef struct core_options_callbacks +{ + retro_core_options_update_display_callback_t update_display; +} core_options_callbacks_t; + struct runloop { retro_usec_t frame_time_last; /* int64_t alignment */ @@ -1679,6 +1693,8 @@ struct runloop size_t msg_queue_size; core_option_manager_t *core_options; + core_options_callbacks_t core_options_callback; /* ptr alignment */ + retro_keyboard_event_t key_event; /* ptr alignment */ retro_keyboard_event_t frontend_key_event; /* ptr alignment */ diff --git a/ui/drivers/qt/qt_dialogs.cpp b/ui/drivers/qt/qt_dialogs.cpp index 441337320e..b209fb6e50 100644 --- a/ui/drivers/qt/qt_dialogs.cpp +++ b/ui/drivers/qt/qt_dialogs.cpp @@ -1089,7 +1089,7 @@ void CoreOptionsDialog::onCoreOptionComboBoxCurrentIndexChanged(int index) QString str = option->vals->elems[k].data; if (!str.isEmpty() && str == val) - core_option_manager_set_val(coreopts, i, k); + core_option_manager_set_val(coreopts, i, k, true); } } }