Merge pull request #326 from libretro/coreinfo

Integration of core info files in RGUI.
This commit is contained in:
Squarepusher 2013-10-06 04:54:46 -07:00
commit 8a674d07e9
15 changed files with 473 additions and 147 deletions

View File

@ -22,6 +22,7 @@ OBJ = frontend/frontend.o \
core_options.o \
compat/compat.o \
cheats.o \
core_info.o \
conf/config_file.o \
screenshot.o \
gfx/scaler/scaler.o \

View File

@ -23,6 +23,7 @@ OBJ = frontend/frontend.o \
compat/compat.o \
screenshot.o \
cheats.o \
core_info.o \
audio/utils.o \
input/overlay.o \
fifo_buffer.o \

View File

@ -26,7 +26,7 @@ NSArray* apple_get_modules()
{
if (!moduleList)
{
coreList = get_core_info_list(apple_platform.coreDirectory.UTF8String);
coreList = core_info_list_new(apple_platform.coreDirectory.UTF8String);
if (!coreList)
return nil;
@ -182,4 +182,4 @@ static NSString* build_string_pair(NSString* stringA, NSString* stringB)
@end
#endif
#endif

View File

@ -87,7 +87,7 @@ RetroArch::RetroArch()
//Get core DropDown reference to populate it in C++
coreSelection = mAppPane->findChild<DropDown*>("dropdown_core");
connect(coreSelection, SIGNAL(selectedValueChanged(QVariant)), this, SLOT(onCoreSelected(QVariant)));
core_info_list = get_core_info_list(g_settings.libretro);
core_info_list = core_info_list_new(g_settings.libretro);
populateCores(core_info_list);
Application::instance()->setScene(mAppPane);
@ -112,7 +112,7 @@ RetroArch::RetroArch()
RetroArch::~RetroArch()
{
free_core_info_list(core_info_list);
core_info_list_free(core_info_list);
}
void RetroArch::aboutToQuit()

View File

@ -17,55 +17,58 @@
#include "general.h"
#include "file.h"
#include "file_ext.h"
#include "file_extract.h"
#include "config.def.h"
core_info_list_t *get_core_info_list(const char *modules_path)
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
core_info_list_t *core_info_list_new(const char *modules_path)
{
struct string_list *contents = dir_list_new(modules_path, EXT_EXECUTABLES, false);
core_info_t *core_info;
core_info_list_t *core_info_list;
unsigned i;
core_info_t *core_info = NULL;
core_info_list_t *core_info_list = NULL;
if (!contents)
return NULL;
core_info = (core_info_t*)malloc(contents->size * sizeof(core_info_t));
memset(core_info, 0, contents->size * sizeof(core_info_t));
core_info_list = (core_info_list_t*)calloc(1, sizeof(*core_info_list));
if (!core_info_list)
goto error;
core_info = (core_info_t*)calloc(contents->size, sizeof(*core_info));
if (!core_info)
goto error;
core_info_list = (core_info_list_t*)malloc(sizeof(core_info_list_t));
memset(core_info_list, 0, sizeof(core_info_list_t));
core_info_list->list = core_info;
core_info_list->count = contents->size;
for (i = 0; i < contents->size; i ++)
for (size_t i = 0; i < contents->size; i++)
{
char buffer[PATH_MAX];
char info_path[PATH_MAX];
char *substr;
core_info[i].path = strdup(contents->elems[i].data);
if (!core_info[i].path)
break;
// NOTE: This assumes all modules are named module_name_{tag}.ext
// {tag} must not contain an underscore. (This isn't true for PC versions)
snprintf(buffer, PATH_MAX, "%s", contents->elems[i].data);
substr = strrchr(buffer, '_');
#if defined(IOS) || defined(HAVE_BB10) || defined(__QNX__)
// Libs are deployed with a suffix (*_ios.dylib, *_qnx.so, etc).
char buffer[PATH_MAX];
strlcpy(buffer, contents->elems[i].data, sizeof(buffer));
char *substr = strrchr(buffer, '_');
if (substr)
*substr = 0;
// NOTE: Can't just use fill_pathname on iOS as it will cut at RetroArch.app;
// perhaps fill_pathname shouldn't cut before the last path element.
if (substr)
snprintf(info_path, PATH_MAX, "%s.info", buffer);
else
fill_pathname(info_path, buffer, ".info", PATH_MAX);
*substr = '\0';
fill_pathname(info_path, buffer, ".info", sizeof(info_path));
#else
fill_pathname(info_path, core_info[i].path, ".info", sizeof(info_path));
#endif
core_info[i].data = config_file_new(info_path);
if (core_info[i].data)
{
config_get_string(core_info[i].data, "display_name", &core_info[i].display_name);
if (config_get_string(core_info[i].data, "supported_extensions", &core_info[i].supported_extensions) &&
core_info[i].supported_extensions)
core_info[i].supported_extensions_list = string_split(core_info[i].supported_extensions, "|");
@ -75,19 +78,48 @@ core_info_list_t *get_core_info_list(const char *modules_path)
core_info[i].display_name = strdup(path_basename(core_info[i].path));
}
dir_list_free(contents);
size_t all_ext_len = 0;
for (size_t i = 0; i < core_info_list->count; i++)
{
all_ext_len += core_info_list->list[i].supported_extensions ?
(strlen(core_info_list->list[i].supported_extensions) + 2) : 0;
}
if (all_ext_len)
{
all_ext_len += strlen("|zip");
core_info_list->all_ext = (char*)calloc(1, all_ext_len);
}
if (core_info_list->all_ext)
{
for (size_t i = 0; i < core_info_list->count; i++)
{
if (core_info_list->list[i].supported_extensions)
{
strlcat(core_info_list->all_ext, core_info_list->list[i].supported_extensions, all_ext_len);
strlcat(core_info_list->all_ext, "|", all_ext_len);
}
}
strlcat(core_info_list->all_ext, "|zip", all_ext_len);
}
dir_list_free(contents);
return core_info_list;
error:
if (contents)
dir_list_free(contents);
core_info_list_free(core_info_list);
return NULL;
}
void free_core_info_list(core_info_list_t *core_info_list)
void core_info_list_free(core_info_list_t *core_info_list)
{
int i;
if (!core_info_list)
return;
for (i = 0; i < core_info_list->count; i++)
for (size_t i = 0; i < core_info_list->count; i++)
{
free(core_info_list->list[i].path);
free(core_info_list->list[i].display_name);
@ -96,11 +128,38 @@ void free_core_info_list(core_info_list_t *core_info_list)
config_file_free(core_info_list->list[i].data);
}
free(core_info_list->all_ext);
free(core_info_list->list);
free(core_info_list);
}
bool does_core_support_file(core_info_t* core, const char *path)
bool core_info_list_get_display_name(core_info_list_t *core_info_list, const char *path, char *buf, size_t size)
{
for (size_t i = 0; i < core_info_list->count; i++)
{
const core_info_t *info = &core_info_list->list[i];
if (!strcmp(info->path, path) && info->display_name)
{
strlcpy(buf, info->display_name, size);
return true;
}
}
return false;
}
bool core_info_does_support_any_file(const core_info_t *core, const struct string_list *list)
{
if (!list || !core || !core->supported_extensions_list)
return false;
for (size_t i = 0; i < list->size; i++)
if (string_list_find_elem_prefix(core->supported_extensions_list, ".", path_get_extension(list->elems[i].data)))
return true;
return false;
}
bool core_info_does_support_file(const core_info_t *core, const char *path)
{
if (!path || !core || !core->supported_extensions_list)
return false;
@ -108,3 +167,60 @@ bool does_core_support_file(core_info_t* core, const char *path)
return string_list_find_elem_prefix(core->supported_extensions_list, ".", path_get_extension(path));
}
const char *core_info_list_get_all_extensions(core_info_list_t *core_info_list)
{
return core_info_list->all_ext;
}
// qsort_r() is not in standard C, sadly.
static const char *core_info_tmp_path;
static const struct string_list *core_info_tmp_list;
static int core_info_qsort_cmp(const void *a_, const void *b_)
{
const core_info_t *a = (const core_info_t*)a_;
const core_info_t *b = (const core_info_t*)b_;
int support_a = core_info_does_support_any_file(a, core_info_tmp_list) ||
core_info_does_support_file(a, core_info_tmp_path);
int support_b = core_info_does_support_any_file(b, core_info_tmp_list) ||
core_info_does_support_file(b, core_info_tmp_path);
if (support_a != support_b)
return support_b - support_a;
else
return strcasecmp(a->display_name, b->display_name);
}
void core_info_list_get_supported_cores(core_info_list_t *core_info_list, const char *path,
const core_info_t **infos, size_t *num_infos)
{
core_info_tmp_path = path;
#ifdef HAVE_ZLIB
struct string_list *list = NULL;
if (!strcasecmp(path_get_extension(path), "zip"))
list = zlib_get_file_list(path);
core_info_tmp_list = list;
#endif
// Let supported core come first in list so we can return a pointer to them.
qsort(core_info_list->list, core_info_list->count, sizeof(core_info_t), core_info_qsort_cmp);
size_t supported = 0;
for (size_t i = 0; i < core_info_list->count; i++, supported++)
{
const core_info_t *core = &core_info_list->list[i];
if (!core_info_does_support_file(core, path) && !core_info_does_support_any_file(core, list))
break;
}
#ifdef HAVE_ZLIB
if (list)
string_list_free(list);
#endif
*infos = core_info_list->list;
*num_infos = supported;
}

View File

@ -16,29 +16,41 @@
#ifndef CORE_INFO_H_
#define CORE_INFO_H_
#include "conf/config_file.h"
#include "file.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "conf/config_file.h"
typedef struct {
char * path;
config_file_t* data;
char * display_name;
char * supported_extensions;
struct string_list * supported_extensions_list;
char *path;
config_file_t *data;
char *display_name;
char *supported_extensions;
struct string_list *supported_extensions_list;
} core_info_t;
typedef struct {
core_info_t *list;
int count;
size_t count;
char *all_ext;
} core_info_list_t;
core_info_list_t *get_core_info_list(const char *modules_path);
void free_core_info_list(core_info_list_t * core_info_list);
core_info_list_t *core_info_list_new(const char *modules_path);
void core_info_list_free(core_info_list_t *core_info_list);
bool does_core_support_file(core_info_t* core, const char *path);
bool core_info_does_support_file(const core_info_t *core, const char *path);
bool core_info_does_support_any_file(const core_info_t *core, const struct string_list *list);
// Non-reentrant, does not allocate. Returns pointer to internal state.
void core_info_list_get_supported_cores(core_info_list_t *core_info_list, const char *path,
const core_info_t **infos, size_t *num_infos);
const char *core_info_list_get_all_extensions(core_info_list_t *core_info_list);
bool core_info_list_get_display_name(core_info_list_t *core_info_list, const char *path, char *buf, size_t size);
#ifdef __cplusplus
}

8
file.h
View File

@ -68,15 +68,20 @@ void dir_list_free(struct string_list *list);
bool string_list_find_elem(const struct string_list *list, const char *elem);
bool string_list_find_elem_prefix(const struct string_list *list, const char *prefix, const char *elem);
struct string_list *string_split(const char *str, const char *delim);
struct string_list *string_list_new(void);
bool string_list_append(struct string_list *list, const char *elem, union string_list_elem_attr attr);
void string_list_free(struct string_list *list);
bool path_is_directory(const char *path);
bool path_file_exists(const char *path);
// Gets extension of file. Only '.'s after the last slash are considered.
const char *path_get_extension(const char *path);
bool path_mkdir(const char *dir);
// Removes all text after and including the last '.'
// Removes all text after and including the last '.'.
// Only '.'s after the last slash are considered.
char *path_remove_extension(char *path);
// Returns basename from path.
@ -100,6 +105,7 @@ bool path_is_absolute(const char *path);
// Replaces filename extension with 'replace' and outputs result to out_path.
// The extension here is considered to be the string from the last '.' to the end.
// Only '.'s after the last slash are considered as extensions.
// If no '.' is present, in_path and replace will simply be concatenated.
// 'size' is buffer size of 'out_path'.
// E.g.: in_path = "/foo/bar/baz/boo.c", replace = ".asm" => out_path = "/foo/bar/baz/boo.asm"

View File

@ -18,6 +18,7 @@
#include "compat/strl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WANT_MINIZ
#include "deps/miniz/zlib.h"
@ -46,7 +47,7 @@ static uint32_t read_le(const uint8_t *data, unsigned size)
return val;
}
static bool inflate_data_to_file(const char *path, uint8_t *cdata,
static bool inflate_data_to_file(const char *path, const uint8_t *cdata,
uint32_t csize, uint32_t size, uint32_t crc32)
{
bool ret = true;
@ -60,7 +61,7 @@ static bool inflate_data_to_file(const char *path, uint8_t *cdata,
if (inflateInit2(&stream, -MAX_WBITS) != Z_OK)
GOTO_END_ERROR();
stream.next_in = cdata;
stream.next_in = (uint8_t*)cdata;
stream.avail_in = csize;
stream.next_out = out_data;
stream.avail_out = size;
@ -85,24 +86,14 @@ end:
return ret;
}
bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts)
bool zlib_parse_file(const char *file, zlib_file_cb file_cb, void *userdata)
{
const uint8_t *footer = NULL;
const uint8_t *directory = NULL;
bool ret = true;
if (!valid_exts)
{
RARCH_ERR("Libretro implementation does not have any valid extensions. Cannot unzip without knowing this.\n");
return false;
}
struct string_list *list = string_split(valid_exts, "|");
if (!list)
return false;
uint8_t *data = NULL;
ssize_t zip_size = read_file(zip_path, (void**)&data);
ssize_t zip_size = read_file(file, (void**)&data);
if (zip_size < 22)
GOTO_END_ERROR();
@ -150,44 +141,126 @@ bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *va
RARCH_LOG("OFFSET: %u, CSIZE: %u, SIZE: %u.\n", offset + 30 + offsetNL + offsetEL, csize, size);
// Extract first ROM that matches our list.
const char *ext = path_get_extension(filename);
if (ext && string_list_find_elem(list, ext))
{
char new_path[PATH_MAX];
fill_pathname_resolve_relative(new_path, zip_path,
path_basename(filename), sizeof(new_path));
switch (cmode)
{
case 0: // Uncompressed
if (!write_file(new_path, cdata, size))
GOTO_END_ERROR();
goto end;
case 8: // Deflate
if (inflate_data_to_file(new_path, cdata, csize, size, crc32))
{
strlcpy(zip_path, new_path, zip_path_size);
goto end;
}
else
GOTO_END_ERROR();
default:
GOTO_END_ERROR();
}
}
if (!file_cb(filename, cdata, cmode, csize, size, crc32, userdata))
break;
directory += 46 + namelength + extralength + commentlength;
}
RARCH_ERR("Didn't find any ROMS that matched valid extensions for libretro implementation.\n");
GOTO_END_ERROR();
end:
free(data);
string_list_free(list);
return ret;
}
struct zip_extract_userdata
{
char *zip_path;
size_t zip_path_size;
struct string_list *ext;
bool found_rom;
};
static bool zip_extract_cb(const char *name, const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
uint32_t crc32, void *userdata)
{
struct zip_extract_userdata *data = (struct zip_extract_userdata*)userdata;
// Extract first ROM that matches our list.
const char *ext = path_get_extension(name);
if (ext && string_list_find_elem(data->ext, ext))
{
char new_path[PATH_MAX];
fill_pathname_resolve_relative(new_path, data->zip_path,
path_basename(name), sizeof(new_path));
switch (cmode)
{
case 0: // Uncompressed
data->found_rom = write_file(new_path, cdata, size);
return false;
case 8: // Deflate
if (inflate_data_to_file(new_path, cdata, csize, size, crc32))
{
strlcpy(data->zip_path, new_path, data->zip_path_size);
data->found_rom = true;
return false;
}
else
return false;
default:
return false;
}
}
return true;
}
bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts)
{
if (!valid_exts)
{
RARCH_ERR("Libretro implementation does not have any valid extensions. Cannot unzip without knowing this.\n");
return false;
}
bool ret = true;
struct string_list *list = string_split(valid_exts, "|");
if (!list)
GOTO_END_ERROR();
struct zip_extract_userdata userdata = {0};
userdata.zip_path = zip_path;
userdata.zip_path_size = zip_path_size;
userdata.ext = list;
if (!zlib_parse_file(zip_path, zip_extract_cb, &userdata))
{
RARCH_ERR("Parsing ZIP failed.\n");
GOTO_END_ERROR();
}
if (!userdata.found_rom)
{
RARCH_ERR("Didn't find any ROMS that matched valid extensions for libretro implementation.\n");
GOTO_END_ERROR();
}
end:
if (list)
string_list_free(list);
return ret;
}
static bool zlib_get_file_list_cb(const char *path, const uint8_t *cdata, unsigned cmode,
uint32_t csize, uint32_t size,
uint32_t crc32, void *userdata)
{
(void)cdata;
(void)cmode;
(void)csize;
(void)size;
(void)crc32;
struct string_list *list = (struct string_list*)userdata;
union string_list_elem_attr attr;
memset(&attr, 0, sizeof(attr));
return string_list_append(list, path, attr);
}
struct string_list *zlib_get_file_list(const char *path)
{
struct string_list *list = string_list_new();
if (!list)
return NULL;
if (!zlib_parse_file(path, zlib_get_file_list_cb, list))
{
RARCH_ERR("Parsing ZIP failed.\n");
string_list_free(list);
return NULL;
}
else
return list;
}

View File

@ -17,9 +17,21 @@
#define FILE_EXTRACT_H__
#include "boolean.h"
#include "file.h"
#include <stddef.h>
#include <stdint.h>
// Returns true when parsing should continue. False to stop.
typedef bool (*zlib_file_cb)(const char *name,
const uint8_t *cdata, unsigned cmode, uint32_t csize, uint32_t size,
uint32_t crc32, void *userdata);
// Low-level file parsing. Enumerates over all files and calls file_cb with userdata.
bool zlib_parse_file(const char *file, zlib_file_cb file_cb, void *userdata);
// Built with zlib_parse_file.
bool zlib_extract_first_rom(char *zip_path, size_t zip_path_size, const char *valid_exts);
struct string_list *zlib_get_file_list(const char *path);
#endif

View File

@ -79,7 +79,7 @@ static bool string_list_capacity(struct string_list *list, size_t cap)
return true;
}
static struct string_list *string_list_new(void)
struct string_list *string_list_new(void)
{
struct string_list *list = (struct string_list*)calloc(1, sizeof(*list));
if (!list)
@ -94,7 +94,7 @@ static struct string_list *string_list_new(void)
return list;
}
static bool string_list_append(struct string_list *list, const char *elem, union string_list_elem_attr attr)
bool string_list_append(struct string_list *list, const char *elem, union string_list_elem_attr attr)
{
if (list->size >= list->cap &&
!string_list_capacity(list, list->cap * 2))
@ -180,7 +180,7 @@ bool string_list_find_elem_prefix(const struct string_list *list, const char *pr
const char *path_get_extension(const char *path)
{
const char *ext = strrchr(path, '.');
const char *ext = strrchr(path_basename(path), '.');
if (ext)
return ext + 1;
else
@ -189,7 +189,7 @@ const char *path_get_extension(const char *path)
char *path_remove_extension(char *path)
{
char *last = strrchr(path, '.');
char *last = strrchr(path_basename(path), '.');
if (*last)
*last = '\0';
return last;
@ -417,7 +417,7 @@ void fill_pathname(char *out_path, const char *in_path, const char *replace, siz
char tmp_path[PATH_MAX];
rarch_assert(strlcpy(tmp_path, in_path, sizeof(tmp_path)) < sizeof(tmp_path));
char *tok = strrchr(tmp_path, '.');
char *tok = strrchr(path_basename(tmp_path), '.');
if (tok)
*tok = '\0';

View File

@ -408,6 +408,11 @@ static void menu_update_libretro_info(void)
#else
retro_get_system_info(&rgui->info);
#endif
core_info_list_free(rgui->core_info);
rgui->core_info = NULL;
if (*rgui->libretro_dir)
rgui->core_info = core_info_list_new(rgui->libretro_dir);
}
bool load_menu_game(void)
@ -513,6 +518,7 @@ void menu_free(void)
#endif
rom_history_free(rgui->history);
core_info_list_free(rgui->core_info);
free(rgui);
}
@ -931,3 +937,37 @@ void menu_key_event(bool down, unsigned keycode, uint32_t character, uint16_t ke
(void)key_modifiers;
}
void menu_resolve_libretro_names(rgui_list_t *list, const char *dir)
{
for (size_t i = 0; i < list->size; i++)
{
const char *path;
unsigned type = 0;
rgui_list_get_at_offset(list, i, &path, &type);
if (type != RGUI_FILE_PLAIN)
continue;
char core_path[PATH_MAX];
fill_pathname_join(core_path, dir, path, sizeof(core_path));
char display_name[256];
if (rgui->core_info &&
core_info_list_get_display_name(rgui->core_info,
core_path, display_name, sizeof(display_name)))
rgui_list_set_alt_at_offset(list, i, display_name);
}
}
void menu_resolve_supported_cores(rgui_handle_t *rgui)
{
const core_info_t *info = NULL;
size_t cores = 0;
core_info_list_get_supported_cores(rgui->core_info, rgui->deferred_path, &info, &cores);
for (size_t i = 0; i < cores; i++)
{
rgui_list_push(rgui->selection_buf, info[i].path, RGUI_FILE_PLAIN, 0);
rgui_list_set_alt_at_offset(rgui->selection_buf, i, info[i].display_name);
}
}

View File

@ -24,6 +24,7 @@
#endif
#include "../../performance.h"
#include "../../core_info.h"
#ifdef HAVE_RGUI
#define MENU_TEXTURE_FULLSCREEN false
@ -99,8 +100,10 @@ typedef enum
// settings options are done here too
RGUI_SETTINGS_OPEN_FILEBROWSER,
RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE,
RGUI_SETTINGS_OPEN_HISTORY,
RGUI_SETTINGS_CORE,
RGUI_SETTINGS_DEFERRED_CORE,
RGUI_SETTINGS_CONFIG,
RGUI_SETTINGS_SAVE_CONFIG,
RGUI_SETTINGS_CORE_OPTIONS,
@ -290,6 +293,10 @@ typedef struct
bool msg_force;
bool push_start_screen;
core_info_list_t *core_info;
bool defer_core;
char deferred_path[PATH_MAX];
// Quick jumping indices with L/R.
// Rebuilt when parsing directory.
size_t scroll_indices[2 * (26 + 2) + 1];
@ -346,6 +353,9 @@ void shader_manager_set_preset(struct gfx_shader *shader,
void menu_ticker_line(char *buf, size_t len, unsigned tick, const char *str, bool selected);
void menu_resolve_libretro_names(rgui_list_t *list, const char *dir);
void menu_resolve_supported_cores(rgui_handle_t *rgui);
void load_menu_game_prepare(void);
bool load_menu_game(void);
void load_menu_game_history(unsigned game_index);

View File

@ -565,7 +565,11 @@ int menu_set_settings(unsigned setting, unsigned action)
#ifdef HAVE_DYNAMIC
case RGUI_LIBRETRO_DIR_PATH:
if (action == RGUI_ACTION_START)
{
*rgui->libretro_dir = '\0';
core_info_list_free(rgui->core_info);
rgui->core_info = NULL;
}
break;
#endif
case RGUI_CONFIG_DIR_PATH:

View File

@ -203,32 +203,6 @@ static int rgui_core_setting_toggle(unsigned setting, rgui_action_t action)
return 0;
}
static void rgui_resolve_libretro_names(rgui_list_t *list, const char *dir)
{
for (size_t i = 0; i < list->size; i++)
{
const char *path;
unsigned type = 0;
rgui_list_get_at_offset(list, i, &path, &type);
if (type != RGUI_FILE_PLAIN)
continue;
char core_path[PATH_MAX];
fill_pathname_join(core_path, dir, path, sizeof(core_path));
char info_path[PATH_MAX];
fill_pathname(info_path, core_path, ".info", sizeof(info_path));
config_file_t *conf = config_file_new(info_path);
if (!conf)
continue;
char display_name[256];
if (config_get_array(conf, "display_name", display_name, sizeof(display_name)))
rgui_list_set_alt_at_offset(list, i, display_name);
config_file_free(conf);
}
}
static int rgui_settings_toggle_setting(rgui_handle_t *rgui, unsigned setting, rgui_action_t action, unsigned menu_type)
{
#ifdef HAVE_SHADER_MANAGER
@ -279,7 +253,18 @@ static void rgui_settings_populate_entries(rgui_handle_t *rgui)
#endif
if (rgui->history)
rgui_list_push(rgui->selection_buf, "Load Game (History)", RGUI_SETTINGS_OPEN_HISTORY, 0);
rgui_list_push(rgui->selection_buf, "Load Game", RGUI_SETTINGS_OPEN_FILEBROWSER, 0);
if (rgui->core_info && rgui->core_info->count)
rgui_list_push(rgui->selection_buf, "Load Game (Detect Core)", RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE, 0);
if (rgui->info.library_name || g_extern.system.info.library_name)
{
char load_game_core_msg[64];
snprintf(load_game_core_msg, sizeof(load_game_core_msg), "Load Game (%s)",
rgui->info.library_name ? rgui->info.library_name : g_extern.system.info.library_name);
rgui_list_push(rgui->selection_buf, load_game_core_msg, RGUI_SETTINGS_OPEN_FILEBROWSER, 0);
}
rgui_list_push(rgui->selection_buf, "Core Options", RGUI_SETTINGS_CORE_OPTIONS, 0);
rgui_list_push(rgui->selection_buf, "Video Options", RGUI_SETTINGS_VIDEO_OPTIONS, 0);
rgui_list_push(rgui->selection_buf, "Audio Options", RGUI_SETTINGS_AUDIO_OPTIONS, 0);
@ -866,8 +851,10 @@ static int rgui_settings_iterate(rgui_handle_t *rgui, rgui_action_t action)
case RGUI_ACTION_RIGHT:
case RGUI_ACTION_OK:
case RGUI_ACTION_START:
if (type == RGUI_SETTINGS_OPEN_FILEBROWSER && action == RGUI_ACTION_OK)
if ((type == RGUI_SETTINGS_OPEN_FILEBROWSER || type == RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE)
&& action == RGUI_ACTION_OK)
{
rgui->defer_core = type == RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE;
rgui_list_push(rgui->menu_stack, rgui->base_path, RGUI_FILE_DIRECTORY, rgui->selection_ptr);
rgui->selection_ptr = 0;
rgui->need_refresh = true;
@ -1140,6 +1127,8 @@ static bool rgui_directory_parse(rgui_handle_t *rgui, const char *directory, uns
#endif
else if (menu_type_is_directory_browser(menu_type))
exts = ""; // we ignore files anyway
else if (rgui->defer_core)
exts = rgui->core_info ? core_info_list_get_all_extensions(rgui->core_info) : "";
else if (rgui->info.valid_extensions)
{
exts = ext_buf;
@ -1314,7 +1303,23 @@ static int rgui_iterate(void *data, unsigned action)
}
else
#endif
if (menu_type == RGUI_SETTINGS_CORE)
if (menu_type == RGUI_SETTINGS_DEFERRED_CORE)
{
// FIXME: Add for consoles.
#ifdef HAVE_DYNAMIC
strlcpy(g_settings.libretro, path, sizeof(g_settings.libretro));
libretro_free_system_info(&rgui->info);
libretro_get_system_info(g_settings.libretro, &rgui->info,
&rgui->load_no_rom);
strlcpy(g_extern.fullpath, rgui->deferred_path, sizeof(g_extern.fullpath));
g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME);
rgui->msg_force = true;
ret = -1;
#endif
rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS);
}
else if (menu_type == RGUI_SETTINGS_CORE)
{
#if defined(HAVE_DYNAMIC)
fill_pathname_join(g_settings.libretro, dir, path, sizeof(g_settings.libretro));
@ -1422,6 +1427,10 @@ static int rgui_iterate(void *data, unsigned action)
else if (menu_type == RGUI_LIBRETRO_DIR_PATH)
{
strlcpy(rgui->libretro_dir, dir, sizeof(rgui->libretro_dir));
core_info_list_free(rgui->core_info);
rgui->core_info = NULL;
if (*rgui->libretro_dir)
rgui->core_info = core_info_list_new(rgui->libretro_dir);
rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS_PATH_OPTIONS);
}
else if (menu_type == RGUI_CONFIG_DIR_PATH)
@ -1442,12 +1451,48 @@ static int rgui_iterate(void *data, unsigned action)
}
else
{
fill_pathname_join(g_extern.fullpath, dir, path, sizeof(g_extern.fullpath));
g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME);
if (rgui->defer_core)
{
fill_pathname_join(rgui->deferred_path, dir, path, sizeof(rgui->deferred_path));
rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS);
rgui->msg_force = true;
ret = -1;
const core_info_t *info = NULL;
size_t supported = 0;
if (rgui->core_info)
core_info_list_get_supported_cores(rgui->core_info, rgui->deferred_path, &info, &supported);
if (supported == 1) // Can make a decision right now.
{
strlcpy(g_extern.fullpath, rgui->deferred_path, sizeof(g_extern.fullpath));
strlcpy(g_settings.libretro, info->path, sizeof(g_settings.libretro));
#ifdef HAVE_DYNAMIC
libretro_free_system_info(&rgui->info);
libretro_get_system_info(g_settings.libretro, &rgui->info,
&rgui->load_no_rom);
#endif
g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME);
rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS);
rgui->msg_force = true;
ret = -1;
}
else // Present a selection.
{
rgui_list_push(rgui->menu_stack, rgui->libretro_dir, RGUI_SETTINGS_DEFERRED_CORE, rgui->selection_ptr);
rgui->selection_ptr = 0;
rgui->need_refresh = true;
}
}
else
{
fill_pathname_join(g_extern.fullpath, dir, path, sizeof(g_extern.fullpath));
g_extern.lifecycle_mode_state |= (1ULL << MODE_LOAD_GAME);
rgui_flush_menu_stack_type(rgui, RGUI_SETTINGS);
rgui->msg_force = true;
ret = -1;
}
}
}
break;
@ -1477,6 +1522,7 @@ static int rgui_iterate(void *data, unsigned action)
#ifdef HAVE_OVERLAY
menu_type == RGUI_SETTINGS_OVERLAY_PRESET ||
#endif
menu_type == RGUI_SETTINGS_DEFERRED_CORE ||
menu_type == RGUI_SETTINGS_CORE ||
menu_type == RGUI_SETTINGS_CONFIG ||
menu_type == RGUI_SETTINGS_OPEN_HISTORY ||
@ -1488,11 +1534,13 @@ static int rgui_iterate(void *data, unsigned action)
rgui->scroll_indices_size = 0;
if (menu_type == RGUI_SETTINGS_OPEN_HISTORY)
history_parse(rgui);
else
else if (menu_type != RGUI_SETTINGS_DEFERRED_CORE)
rgui_directory_parse(rgui, dir, menu_type, rgui->selection_buf);
if (menu_type == RGUI_SETTINGS_CORE)
rgui_resolve_libretro_names(rgui->selection_buf, dir);
menu_resolve_libretro_names(rgui->selection_buf, dir);
else if (menu_type == RGUI_SETTINGS_DEFERRED_CORE)
menu_resolve_supported_cores(rgui);
// Before a refresh, we could have deleted a file on disk, causing
// selection_ptr to suddendly be out of range. Ensure it doesn't overflow.

View File

@ -232,6 +232,8 @@ static void render_text(rgui_handle_t *rgui)
if (menu_type == RGUI_SETTINGS_CORE)
snprintf(title, sizeof(title), "CORE SELECTION %s", dir);
else if (menu_type == RGUI_SETTINGS_DEFERRED_CORE)
snprintf(title, sizeof(title), "DETECTED CORES %s", dir);
else if (menu_type == RGUI_SETTINGS_CONFIG)
snprintf(title, sizeof(title), "CONFIG %s", dir);
else if (menu_type == RGUI_SETTINGS_DISK_APPEND)
@ -292,13 +294,17 @@ static void render_text(rgui_handle_t *rgui)
snprintf(title, sizeof(title), "SYSTEM DIR %s", dir);
else
{
const char *core_name = rgui->info.library_name;
if (!core_name)
core_name = g_extern.system.info.library_name;
if (!core_name)
core_name = "No Core";
snprintf(title, sizeof(title), "GAME (%s) %s", core_name, dir);
if (rgui->defer_core)
snprintf(title, sizeof(title), "GAME %s", dir);
else
{
const char *core_name = rgui->info.library_name;
if (!core_name)
core_name = g_extern.system.info.library_name;
if (!core_name)
core_name = "No Core";
snprintf(title, sizeof(title), "GAME (%s) %s", core_name, dir);
}
}
char title_buf[256];
@ -361,9 +367,8 @@ static void render_text(rgui_handle_t *rgui)
}
else
#endif
#ifdef HAVE_DYNAMIC
// Pretty-print libretro cores from menu.
if (menu_type == RGUI_SETTINGS_CORE)
if (menu_type == RGUI_SETTINGS_CORE || menu_type == RGUI_SETTINGS_DEFERRED_CORE)
{
if (type == RGUI_FILE_PLAIN)
{
@ -378,10 +383,7 @@ static void render_text(rgui_handle_t *rgui)
w = 5;
}
}
else
#endif
if (menu_type == RGUI_SETTINGS_CORE ||
menu_type == RGUI_SETTINGS_CONFIG ||
else if (menu_type == RGUI_SETTINGS_CONFIG ||
#ifdef HAVE_OVERLAY
menu_type == RGUI_SETTINGS_OVERLAY_PRESET ||
#endif
@ -569,6 +571,7 @@ static void render_text(rgui_handle_t *rgui)
strlcpy(type_str, "<default>", sizeof(type_str));
break;
case RGUI_SETTINGS_OPEN_FILEBROWSER:
case RGUI_SETTINGS_OPEN_FILEBROWSER_DEFERRED_CORE:
case RGUI_SETTINGS_OPEN_HISTORY:
case RGUI_SETTINGS_CORE_OPTIONS:
case RGUI_SETTINGS_CUSTOM_VIEWPORT: