Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add disk control interface API extension #10019

Merged
merged 1 commit into from
Jan 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions core.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ typedef struct rarch_system_info

bool supports_vfs;

struct retro_disk_control_callback disk_control_cb;
struct retro_location_callback location_cb;
struct retro_disk_control_ext_callback disk_control_cb;
struct retro_location_callback location_cb;

struct
{
Expand Down
132 changes: 121 additions & 11 deletions libretro-common/include/libretro.h
Original file line number Diff line number Diff line change
Expand Up @@ -1117,7 +1117,7 @@ enum retro_mod
* This may be still be done regardless of the core options
* interface version.
*
* If version is 1 however, core options may instead be set by
* If version is >= 1 however, core options may instead be set by
* passing an array of retro_core_option_definition structs to
* RETRO_ENVIRONMENT_SET_CORE_OPTIONS, or a 2D array of
* retro_core_option_definition structs to RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL.
Expand All @@ -1132,8 +1132,8 @@ enum retro_mod
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
* returns an API version of 1.
* This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
* returns an API version of >= 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as
* possible (ideally in retro_set_environment).
Expand Down Expand Up @@ -1169,8 +1169,6 @@ enum retro_mod
* i.e. it should be feasible to cycle through options
* without a keyboard.
*
* First entry should be treated as a default.
*
* Example entry:
* {
* "foo_option",
Expand All @@ -1196,8 +1194,8 @@ enum retro_mod
* GET_VARIABLE.
* This allows the frontend to present these variables to
* a user dynamically.
* This should only be called if RETRO_ENVIRONMENT_GET_ENHANCED_CORE_OPTIONS
* returns an API version of 1.
* This should only be called if RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION
* returns an API version of >= 1.
* This should be called instead of RETRO_ENVIRONMENT_SET_VARIABLES.
* This should be called the first time as early as
* possible (ideally in retro_set_environment).
Expand Down Expand Up @@ -1257,7 +1255,38 @@ enum retro_mod
*
* 'data' points to an unsigned variable
*/


#define RETRO_ENVIRONMENT_GET_DISK_CONTROL_INTERFACE_VERSION 57
/* unsigned * --
* Unsigned value is the API version number of the disk control
* interface supported by the frontend. If callback return false,
* API version is assumed to be 0.
*
* In legacy code, the disk control interface is defined by passing
* a struct of type retro_disk_control_callback to
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
* This may be still be done regardless of the disk control
* interface version.
*
* If version is >= 1 however, the disk control interface may
* instead be defined by passing a struct of type
* retro_disk_control_ext_callback to
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
* This allows the core to provide additional information about
* disk images to the frontend and/or enables extra
* disk control functionality by the frontend.
*/

#define RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE 58
/* const struct retro_disk_control_ext_callback * --
* Sets an interface which frontend can use to eject and insert
* disk images, and also obtain information about individual
* disk image files registered by the core.
* This is used for games which consist of multiple images and
* must be manually swapped out by the user (e.g. PSX, floppy disk
* based systems).
*/

/* VFS functionality */

/* File paths:
Expand Down Expand Up @@ -2307,7 +2336,8 @@ struct retro_keyboard_callback
retro_keyboard_event_t callback;
};

/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
/* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE &
* RETRO_ENVIRONMENT_SET_DISK_CONTROL_EXT_INTERFACE.
* Should be set for implementations which can swap out multiple disk
* images in runtime.
*
Expand Down Expand Up @@ -2365,6 +2395,53 @@ typedef bool (RETRO_CALLCONV *retro_replace_image_index_t)(unsigned index,
* with replace_image_index. */
typedef bool (RETRO_CALLCONV *retro_add_image_index_t)(void);

/* Sets initial image to insert in drive when calling
* core_load_game().
* Since we cannot pass the initial index when loading
* content (this would require a major API change), this
* is set by the frontend *before* calling the core's
* retro_load_game()/retro_load_game_special() implementation.
* A core should therefore cache the index/path values and handle
* them inside retro_load_game()/retro_load_game_special().
* - If 'index' is invalid (index >= get_num_images()), the
* core should ignore the set value and instead use 0
* - 'path' is used purely for error checking - i.e. when
* content is loaded, the core should verify that the
* disk specified by 'index' has the specified file path.
* This is to guard against auto selecting the wrong image
* if (for example) the user should modify an existing M3U
* playlist. We have to let the core handle this because
* set_initial_image() must be called before loading content,
* i.e. the frontend cannot access image paths in advance
* and thus cannot perform the error check itself.
* If set path and content path do not match, the core should
* ignore the set 'index' value and instead use 0
* Returns 'false' if index or 'path' are invalid, or core
* does not support this functionality
*/
typedef bool (RETRO_CALLCONV *retro_set_initial_image_t)(unsigned index, const char *path);

/* Fetches the path of the specified disk image file.
* Returns 'false' if index is invalid (index >= get_num_images())
* or path is otherwise unavailable.
*/
typedef bool (RETRO_CALLCONV *retro_get_image_path_t)(unsigned index, char *path, size_t len);

/* Fetches a core-provided 'label' for the specified disk
* image file. In the simplest case this may be a file name
* (without extension), but for cores with more complex
* content requirements information may be provided to
* facilitate user disk swapping - for example, a core
* running floppy-disk-based content may uniquely label
* save disks, data disks, level disks, etc. with names
* corresponding to in-game disk change prompts (so the
* frontend can provide better user guidance than a 'dumb'
* disk index value).
* Returns 'false' if index is invalid (index >= get_num_images())
* or label is otherwise unavailable.
*/
typedef bool (RETRO_CALLCONV *retro_get_image_label_t)(unsigned index, char *label, size_t len);

struct retro_disk_control_callback
{
retro_set_eject_state_t set_eject_state;
Expand All @@ -2378,6 +2455,27 @@ struct retro_disk_control_callback
retro_add_image_index_t add_image_index;
};

struct retro_disk_control_ext_callback
{
retro_set_eject_state_t set_eject_state;
retro_get_eject_state_t get_eject_state;

retro_get_image_index_t get_image_index;
retro_set_image_index_t set_image_index;
retro_get_num_images_t get_num_images;

retro_replace_image_index_t replace_image_index;
retro_add_image_index_t add_image_index;

/* NOTE: Frontend will only attempt to record/restore
* last used disk index if both set_initial_image()
* and get_image_path() are implemented */
retro_set_initial_image_t set_initial_image; /* Optional - may be NULL */

retro_get_image_path_t get_image_path; /* Optional - may be NULL */
retro_get_image_label_t get_image_label; /* Optional - may be NULL */
};

enum retro_pixel_format
{
/* 0RGB1555, native endian.
Expand Down Expand Up @@ -2522,8 +2620,20 @@ struct retro_core_option_display
};

/* Maximum number of values permitted for a core option
* NOTE: This may be increased on a core-by-core basis
* if required (doing so has no effect on the frontend) */
* > Note: We have to set a maximum value due the limitations
* of the C language - i.e. it is not possible to create an
* array of structs each containing a variable sized array,
* so the retro_core_option_definition values array must
* have a fixed size. The size limit of 128 is a balancing
* act - it needs to be large enough to support all 'sane'
* core options, but setting it too large may impact low memory
* platforms. In practise, if a core option has more than
* 128 values then the implementation is likely flawed.
* To quote the above API reference:
* "The number of possible options should be very limited
* i.e. it should be feasible to cycle through options
* without a keyboard."
*/
#define RETRO_NUM_CORE_OPTION_VALUES_MAX 128

struct retro_core_option_value
Expand Down
6 changes: 3 additions & 3 deletions menu/cbs/menu_cbs_get_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,9 +762,9 @@ static void menu_action_setting_disp_set_label_menu_disk_index(
const char *path,
char *s2, size_t len2)
{
unsigned images = 0, current = 0;
struct retro_disk_control_callback *control = NULL;
rarch_system_info_t *system = runloop_get_system_info();
unsigned images = 0, current = 0;
struct retro_disk_control_ext_callback *control = NULL;
rarch_system_info_t *system = runloop_get_system_info();

if (!system)
return;
Expand Down
4 changes: 2 additions & 2 deletions menu/cbs/menu_cbs_ok.c
Original file line number Diff line number Diff line change
Expand Up @@ -6115,8 +6115,8 @@ static int action_ok_disk_cycle_tray_status(const char *path,
/* Get disk eject state *before* toggling drive status */
if (sys_info)
{
const struct retro_disk_control_callback *control =
(const struct retro_disk_control_callback*)
const struct retro_disk_control_ext_callback *control =
(const struct retro_disk_control_ext_callback*)
&sys_info->disk_control_cb;

if (control)
Expand Down
55 changes: 45 additions & 10 deletions menu/menu_displaylist.c
Original file line number Diff line number Diff line change
Expand Up @@ -3242,17 +3242,17 @@ static unsigned menu_displaylist_parse_content_information(
static unsigned menu_displaylist_parse_disk_options(
file_list_t *list)
{
unsigned count = 0;
rarch_system_info_t *sys_info =
unsigned count = 0;
rarch_system_info_t *sys_info =
runloop_get_system_info();
const struct retro_disk_control_callback *control = NULL;
const struct retro_disk_control_ext_callback *control = NULL;
bool disk_ejected;

/* Sanity Check */
if (!sys_info)
return count;

control = (const struct retro_disk_control_callback*)
control = (const struct retro_disk_control_ext_callback*)
&sys_info->disk_control_cb;

if (!control ||
Expand Down Expand Up @@ -5356,8 +5356,8 @@ unsigned menu_displaylist_build_list(file_list_t *list, enum menu_displaylist_ct

if (sys_info)
{
const struct retro_disk_control_callback *control =
(const struct retro_disk_control_callback*)
const struct retro_disk_control_ext_callback *control =
(const struct retro_disk_control_ext_callback*)
&sys_info->disk_control_cb;

/* Check that the required disk control interface
Expand All @@ -5368,21 +5368,56 @@ unsigned menu_displaylist_build_list(file_list_t *list, enum menu_displaylist_ct
{
unsigned num_images = control->get_num_images();
unsigned current_image = control->get_image_index();
unsigned num_digits = 0;
unsigned i;

/* If core supports labels, index value string
* should be padded to maximum width (otherwise
* labels will be misaligned/ugly) */
if (control->get_image_label)
{
unsigned digit_counter = num_images;
do
{
num_digits++;
digit_counter = digit_counter / 10;
}
while (digit_counter > 0);
}

/* Loop through disk images */
for (i = 0; i < num_images; i++)
{
char current_image_str[256];
char current_image_str[PATH_MAX_LENGTH];
char image_label[PATH_MAX_LENGTH];

current_image_str[0] = '\0';
image_label[0] = '\0';

/* Get image label, if supported by core */
if (control->get_image_label)
if (!control->get_image_label(i, image_label, sizeof(image_label)))
image_label[0] = '\0';

/* Get string representation of disk index
* > Note that displayed index starts at '1',
* not '0' */
snprintf(
current_image_str, sizeof(current_image_str),
"%u", i + 1);
if (!string_is_empty(image_label))
{
/* Note: 2-space gap is intentional
* (for clarity) */
int n = snprintf(
current_image_str, sizeof(current_image_str),
"%0*u: %s", num_digits, i + 1, image_label);

/* Suppress GCC warnings... */
if ((n < 0) || (n >= PATH_MAX_LENGTH))
n = 0;
}
else
snprintf(
current_image_str, sizeof(current_image_str),
"%0*u", num_digits, i + 1);

/* Add menu entry */
if (menu_entries_append_enum(list,
Expand Down