Files
RetroArch/menu/menu_displaylist.c
T
Codex 7a3bcbdc28 media: route image and movie activation to the internal viewer
Open supported external media in the fullscreen menu viewer and keep image confirmation there across all four menu drivers. Disable the legacy imageviewer core in normal build configurations while preserving its sources and Griffin guard.
2026-10-24 01:00:53 +02:00

19123 lines
794 KiB
C

/* RetroArch - A frontend for libretro.
* Copyright (C) 2011-2017 - Daniel De Matteis
* Copyright (C) 2014-2017 - Jean-André Santoni
* Copyright (C) 2016-2019 - Andrés Suárez
* Copyright (C) 2016-2019 - Brad Parker
*
* RetroArch is free software: you can redistribute it and/or modify it under the terms
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with RetroArch.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include <memory/mem_stats.h>
#include <stddef.h>
#include <math.h>
#include <compat/strl.h>
#include <compat/strcasestr.h>
#include <array/rbuf.h>
#include <lists/file_list.h>
#include <lists/dir_list.h>
#include <file/file_path.h>
#include <file/archive_file.h>
#include <playlists/label_sanitization.h>
#include <string/stdstring.h>
#include <streams/file_stream.h>
#include <features/features_cpu.h>
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifdef HAVE_LIBRETRODB
#include "../database_info.h"
#endif
#ifdef HAVE_CHEEVOS
#include "../cheevos/cheevos.h"
#include "../cheevos/cheevos_menu.h"
#endif
#ifdef HAVE_NETWORKING
#include <net/net_http_parse.h>
#include "../../network/netplay/netplay.h"
#include "../core_updater_list.h"
#endif
#ifdef HAVE_LAKKA
#include "../../lakka.h"
#endif
#ifdef HAVE_LIBNX
#include <switch.h>
#endif
#if defined(HAVE_LIBNX)
#include "../../switch_performance_profiles.h"
#endif
#if defined(__linux__) || (defined(BSD) && !defined(__MACH__))
#include "../frontend/drivers/platform_unix.h"
#endif
#if defined(ANDROID)
#include "../play_feature_delivery/play_feature_delivery.h"
#endif
#if TARGET_OS_IPHONE
#include "JITSupport.h"
#endif
#ifdef HAVE_CDROM
#include <vfs/vfs_implementation_cdrom.h>
#include <media/media_detect_cd.h>
#endif
#include "../audio/audio_driver.h"
#include "../midi_driver.h"
#include "../record/record_driver.h"
#include "../msg_hash_lbl_str.h"
#ifdef __MACH__
#include <TargetConditionals.h>
#endif
#include "menu_cbs.h"
#include "menu_driver.h"
#include "menu_dirwalk.h"
#include "menu_entries.h"
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
#include "menu_shader.h"
#endif
#if defined(HAVE_MATERIALUI) || defined(HAVE_XMB) || defined(HAVE_OZONE)
#include "menu_screensaver.h"
#endif
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
#include "../../cores/internal_cores.h"
#endif
#include "../configuration.h"
#include "../file_path_special.h"
#include "../defaults.h"
#include "../verbosity.h"
#include "../version.h"
#ifdef HAVE_CHEATS
#include "../cheat_manager.h"
#endif
#include "../core_option_manager.h"
#include "../paths.h"
#include "../retroarch.h"
#include "../runloop.h"
#include "../core.h"
#include "../frontend/frontend_driver.h"
#include <file/file_watch.h>
#include "../ui/ui_companion_driver.h"
#include "../gfx/video_display_server.h"
#ifdef HAVE_MODELINE
#include "../gfx/modeline/modeline_edid.h"
#endif
#ifdef HAVE_GFX_WIDGETS
#include "../gfx/gfx_widgets.h"
#endif
#include "../config.features.h"
#include "../version_git.h"
#include "../list_special.h"
#include "../performance_counters.h"
#include "../core_info.h"
#include "../bluetooth/bluetooth_driver.h"
#if defined(HAVE_NETWORKING) && defined(HAVE_WIFI)
#include "../network/wifi_driver.h"
#endif
#include "../tasks/task_content.h"
#include "../tasks/tasks_internal.h"
#include "../dynamic.h"
#include "../runtime_file.h"
#include "../manual_content_scan.h"
#include "../core_backup.h"
#include "../misc/cpufreq/cpufreq.h"
#ifdef HAVE_LAKKA_SWITCH
#include "../misc/reboot2payload/reboot2payload.h"
#endif
#include "../input/input_remapping.h"
#ifdef HAVE_MICROPHONE
#include "../audio/microphone_driver.h"
#endif
#ifdef HAVE_MIST
#include "../steam/steam.h"
#endif
#ifdef _3DS
#include <3ds/services/cfgu.h> /* CFGU_GetSystemModel */
#endif
/* Spacers used for '<content> - <core name>' labels
* in playlists */
#define PL_LABEL_SPACER_DEFAULT " | "
#define PL_LABEL_SPACER_RGUI " | "
#define PL_LABEL_SPACER_MAXLEN 8
#define BYTES_TO_MB(bytes) ((bytes) / 1024 / 1024)
#define BYTES_TO_GB(bytes) (((bytes) / 1024) / 1024 / 1024)
#if defined(HAVE_NETWORKING) && defined(HAVE_IFINFO)
#include <net/net_ifinfo.h>
#endif
#include "../input/drivers_hid/winusb_bind.h"
/* TODO/FIXME - globals - need to find a way to
* get rid of these */
struct menu_displaylist_state
{
enum filebrowser_enums filebrowser_types;
};
static struct menu_displaylist_state menu_displist_st = {
FILEBROWSER_NONE /* filebrowser_types */
};
extern struct key_desc key_descriptors[RARCH_MAX_KEYS];
enum filebrowser_enums filebrowser_get_type(void)
{
struct menu_displaylist_state *p_displist = &menu_displist_st;
return p_displist->filebrowser_types;
}
#ifdef HAVE_NFSCLIENT
/* nfs://server/[export]/[subdir]; the export may be left out of the
* settings when the address carries it. */
bool menu_displaylist_build_nfs_root(char *s, size_t len)
{
size_t _len;
settings_t *settings = config_get_ptr();
const char *server = settings->arrays.nfs_server;
const char *export_p = settings->arrays.nfs_export;
const char *subdir = settings->arrays.nfs_subdir;
if (!*server)
return false;
_len = strlcpy_lit(s, "nfs://", len);
_len += strlcpy(s + _len, server, len - _len);
if (_len >= len)
return false;
if (*export_p)
{
/* with an export configured the VFS resolves paths against it,
* so the root is the server alone (plus the subdir) */
if (*subdir)
{
if (*subdir != '/')
_len += strlcpy_lit(s + _len, "/", len - _len);
_len += strlcpy(s + _len, subdir, len - _len);
}
}
return _len < len;
}
#endif
#ifdef HAVE_SMBCLIENT
bool menu_displaylist_build_smb_root(char *s, size_t len)
{
size_t _len;
settings_t *settings = config_get_ptr();
const char *server = settings->arrays.smb_client_server_address;
const char *share = settings->arrays.smb_client_share;
const char *subdir = settings->arrays.smb_client_subdir;
if (!settings->bools.smb_client_enable || !*server)
return false;
_len = strlcpy_lit(s, "smb://", len);
if (_len >= len)
return false;
_len += strlcpy(s + _len, server, len - _len);
if (_len >= len)
return false;
if (*share)
{
_len += strlcpy_lit(s + _len, "/", len - _len);
if (_len >= len)
return false;
_len += strlcpy(s + _len, share, len - _len);
if (_len >= len)
return false;
}
if (*subdir)
{
if (subdir[0] != '/')
{
_len += strlcpy_lit(s + _len, "/", len - _len);
if (_len >= len)
return false;
}
if (strlcpy(s + _len, subdir, len - _len) >= len - _len)
return false;
}
return true;
}
#endif
void filebrowser_clear_type(void)
{
struct menu_displaylist_state *p_displist = &menu_displist_st;
p_displist->filebrowser_types = FILEBROWSER_NONE;
}
void filebrowser_set_type(enum filebrowser_enums type)
{
struct menu_displaylist_state *p_displist = &menu_displist_st;
p_displist->filebrowser_types = type;
}
/* Fired on the main thread when a background directory walk
* completes (either way): mark the entries for refresh, exactly as
* the explore init task does, so the repopulation re-issues the
* request and consumes the finished listing. */
static bool menu_displaylist_playlist_within_budget(void *ud)
{
return task_nbio_slice_within_budget(ud, 0, 0);
}
static void menu_displaylist_dirwalk_refresh(unsigned tag)
{
struct menu_state *menu_st = menu_state_get_ptr();
(void)tag;
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH
| MENU_ST_FLAG_PREVENT_POPULATE;
}
/* One file entry of the current view, with its name length
* (sans extension) worked out once before sorting. */
typedef struct menu_file_browser_stem
{
menu_file_list_cbs_t *cbs;
const char *path;
size_t len;
} menu_file_browser_stem_t;
static int menu_file_browser_compare_stems(const void *a_, const void *b_)
{
const menu_file_browser_stem_t *a = (const menu_file_browser_stem_t*)a_;
const menu_file_browser_stem_t *b = (const menu_file_browser_stem_t*)b_;
size_t n = (a->len < b->len) ? a->len : b->len;
size_t k;
for (k = 0; k < n; k++)
{
int ca = TOLOWER(a->path[k]);
int cb = TOLOWER(b->path[k]);
if (ca != cb)
return ca - cb;
}
return (a->len < b->len) ? -1 : (a->len != b->len);
}
static bool menu_file_browser_entry_is_file(
const file_list_t *list, size_t i)
{
unsigned type = list->list[i].type;
return type != FILE_TYPE_DIRECTORY
&& type != FILE_TYPE_PARENT_DIRECTORY
&& type != FILE_TYPE_USE_DIRECTORY
&& type != FILE_TYPE_SCAN_DIRECTORY
&& type != FILE_TYPE_MANUAL_SCAN_DIRECTORY
&& type != MENU_SETTING_NO_ITEM
&& list->list[i].actiondata
&& list->list[i].path && *list->list[i].path;
}
static void menu_file_browser_prepare_extensions(
file_list_t *list, unsigned mode)
{
menu_file_browser_stem_t *stems;
size_t i, count = 0;
uint8_t initial;
if (mode == MENU_FILE_BROWSER_EXTENSION_DISPLAY_ALWAYS)
return;
/* Duplicates Only starts from full names, so an allocation
* failure below leaves every extension visible. */
initial = (mode == MENU_FILE_BROWSER_EXTENSION_DISPLAY_NEVER)
? MENU_FILE_BROWSER_EXTENSION_STATE_HIDDEN
: MENU_FILE_BROWSER_EXTENSION_STATE_FULL;
for (i = 0; i < list->size; i++)
{
if (menu_file_browser_entry_is_file(list, i))
{
((menu_file_list_cbs_t*)list->list[i].actiondata)
->file_extension_state = initial;
count++;
}
}
if (mode != MENU_FILE_BROWSER_EXTENSION_DISPLAY_DUPLICATES_ONLY || !count)
return;
if ( count > (size_t)-1 / sizeof(*stems)
|| !(stems = (menu_file_browser_stem_t*)
malloc(count * sizeof(*stems))))
return;
count = 0;
for (i = 0; i < list->size; i++)
{
if (menu_file_browser_entry_is_file(list, i))
{
menu_file_browser_stem_t *st = &stems[count++];
st->cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
st->path = list->list[i].path;
st->len = menu_file_browser_stem_length(st->path);
st->cbs->file_extension_state =
MENU_FILE_BROWSER_EXTENSION_STATE_HIDDEN;
}
}
/* Sort the side array only: the visible list keeps its order. */
qsort(stems, count, sizeof(*stems), menu_file_browser_compare_stems);
for (i = 1; i < count; i++)
{
if (menu_file_browser_compare_stems(&stems[i - 1], &stems[i]) == 0)
{
stems[i - 1].cbs->file_extension_state =
MENU_FILE_BROWSER_EXTENSION_STATE_HINT;
stems[i].cbs->file_extension_state =
MENU_FILE_BROWSER_EXTENSION_STATE_HINT;
}
}
free(stems);
}
/* True when Parent Directory from @dir would land on the filesystem
* root while the drive list does not offer it (webOS, Play Store
* Android). Going up then stops at the drive list - reached with
* Back - rather than listing a root the platform keeps out of reach.
* Decided by the frontend's drive list, not by platform here. */
static bool filebrowser_parent_is_hidden_root(const char *dir)
{
size_t _len;
const char *slash;
if (!dir || dir[0] != '/')
return false;
if (frontend_driver_root_in_drive_list())
return false;
_len = strlen(dir);
while (_len > 1 && dir[_len - 1] == '/')
_len--;
/* "/" itself, or a direct child of it ("/tmp", "/media/"). */
for (slash = dir + _len; slash > dir; slash--)
if (slash[-1] == '/')
break;
return slash - 1 == dir;
}
static int filebrowser_parse(
file_list_t *info_list,
const char *path,
const char *exts,
const char *label,
unsigned type_default,
unsigned type_data,
bool show_hidden_files,
bool builtin_mediaplayer_enable,
bool builtin_imageviewer_enable,
bool filter_ext
)
{
size_t i, list_size;
const struct retro_subsystem_info *subsystem = NULL;
bool ret = false;
bool walk_deferred = false;
bool list_presorted = false;
struct string_list *walk_list = NULL;
enum menu_dirwalk_status walk_status = MENU_DIRWALK_FAILED;
struct string_list str_list = {0};
settings_t *settings = config_get_ptr();
unsigned count = 0;
enum menu_displaylist_ctl_state type = (enum menu_displaylist_ctl_state)type_data;
enum filebrowser_enums filebrowser_type = filebrowser_get_type();
bool allow_parent_directory = true;
bool path_is_compressed = path && *path
&& path_is_compressed_file(path);
menu_search_terms_t *search_terms = menu_entries_search_get_terms();
#if TARGET_OS_IPHONE
char full_path[PATH_MAX_LENGTH];
fill_pathname_expand_special(full_path, path, sizeof(full_path));
#else
const char *full_path = path;
#endif
#define RESOLVE_SUBSYSTEM(runloop_st, sys_info) \
do { \
(sys_info) = &(runloop_st)->system; \
subsystem = (sys_info)->subsystem.data \
? (sys_info)->subsystem.data + content_get_subsystem() \
: (runloop_st)->subsystem_data + content_get_subsystem(); \
} while (0)
if (path_is_compressed)
{
if (filebrowser_type == FILEBROWSER_SELECT_OVERLAY)
filter_ext = true;
if (filebrowser_type == FILEBROWSER_SELECT_FILE_SUBSYSTEM)
{
runloop_state_t *runloop_st = runloop_state_get_ptr();
rarch_system_info_t *sys_info;
RESOLVE_SUBSYSTEM(runloop_st, sys_info);
if (subsystem && runloop_st->subsystem_current_count > 0)
ret = file_archive_get_file_list_noalloc(&str_list,
path,
filter_ext ? subsystem->roms[
content_get_subsystem_rom_id()].valid_extensions : NULL);
}
else
ret = file_archive_get_file_list_noalloc(&str_list,
path, filter_ext ? exts : NULL);
}
else if (path && *path)
{
if ( type_default == FILE_TYPE_SHADER_PRESET
|| type_default == FILE_TYPE_SHADER
|| type_default == FILE_TYPE_OVERLAY
|| type_default == FILE_TYPE_OSK_OVERLAY)
filter_ext = true;
if (string_is_equal(label, MENU_ENUM_LABEL_SCAN_FILE_STR))
filter_ext = false;
if ( !strcmp(label, "database_manager_list")
#if TARGET_OS_IPHONE
|| !strcmp(label, "video_filter")
|| !strcmp(label, "audio_dsp_plugin")
#endif
|| !strcmp(label, "cursor_manager_list"))
allow_parent_directory = false;
menu_dirwalk_set_refresh_cb(menu_displaylist_dirwalk_refresh);
if (filebrowser_type == FILEBROWSER_SELECT_FILE_SUBSYSTEM)
{
runloop_state_t *runloop_st = runloop_state_get_ptr();
rarch_system_info_t *sys_info;
RESOLVE_SUBSYSTEM(runloop_st, sys_info);
if ( subsystem
&& (runloop_st->subsystem_current_count > 0)
&& (content_get_subsystem_rom_id() < subsystem->num_roms))
walk_status = menu_dirwalk_request(full_path,
filter_ext ? subsystem->roms[content_get_subsystem_rom_id()].valid_extensions : NULL,
true, show_hidden_files, true,
MENU_DIRWALK_SORT_DIR_FIRST,
MENU_DIRWALK_TAG_FILEBROWSER, &walk_list);
}
else if ( type_default == FILE_TYPE_MANUAL_SCAN_DAT
|| type_default == FILE_TYPE_SIDELOAD_CORE)
walk_status = menu_dirwalk_request(full_path,
exts, true, show_hidden_files, false,
MENU_DIRWALK_SORT_DIR_FIRST,
MENU_DIRWALK_TAG_FILEBROWSER, &walk_list);
else
walk_status = menu_dirwalk_request(full_path,
filter_ext ? exts : NULL,
true, show_hidden_files, true,
MENU_DIRWALK_SORT_DIR_FIRST,
MENU_DIRWALK_TAG_FILEBROWSER, &walk_list);
if (walk_status == MENU_DIRWALK_DONE && walk_list)
{
/* Move the completed heap listing into the local list the
* append loop reads; the module sorted it already. */
str_list = *walk_list;
free(walk_list);
list_presorted = true;
ret = true;
}
else if (walk_status == MENU_DIRWALK_PENDING)
{
/* The walk continues in the background (off the main
* thread when Threaded Tasks is on); the refresh callback
* lands when it finishes and the re-issued request above
* consumes the listing. Show a placeholder meanwhile. */
walk_deferred = true;
ret = true;
}
/* MENU_DIRWALK_FAILED: ret stays false, same directory-not-
* found entry as a failed dir_list_initialize() today. */
}
switch (filebrowser_type)
{
case FILEBROWSER_SCAN_DIR:
#ifdef HAVE_LIBRETRODB
menu_entries_prepend(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY),
MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY_STR,
MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY,
FILE_TYPE_SCAN_DIRECTORY, 0, 0);
#endif
break;
case FILEBROWSER_MANUAL_SCAN_DIR:
menu_entries_prepend(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY),
MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY_STR,
MENU_ENUM_LABEL_SCAN_THIS_DIRECTORY,
FILE_TYPE_MANUAL_SCAN_DIRECTORY, 0, 0);
break;
case FILEBROWSER_SELECT_DIR:
menu_entries_prepend(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY),
MENU_ENUM_LABEL_USE_THIS_DIRECTORY_STR,
MENU_ENUM_LABEL_USE_THIS_DIRECTORY,
FILE_TYPE_USE_DIRECTORY, 0, 0);
break;
default:
if (exts && memchr(exts, '/', strlen(exts) + 1))
menu_entries_prepend(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY),
MENU_ENUM_LABEL_USE_THIS_DIRECTORY_STR,
MSG_UNKNOWN,
FILE_TYPE_USE_DIRECTORY, 0, FILE_TYPE_USE_DIRECTORY);
break;
}
if (!ret)
{
const char *str = path_is_compressed
? msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE)
: msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND);
menu_entries_append(info_list, str, "",
MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, 0, 0, 0, NULL);
goto end;
}
if (walk_deferred)
{
menu_entries_append(info_list,
msg_hash_to_str(MSG_LOADING), "",
MSG_UNKNOWN, MENU_SETTING_NO_ITEM, 0, 0, NULL);
count++;
goto end; /* the parent-directory entry still applies */
}
if (!list_presorted)
dir_list_sort(&str_list, true);
list_size = str_list.size;
for (i = 0; i < list_size; i++)
{
bool dir_only_mode;
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
enum rarch_content_type path_type = RARCH_CONTENT_NONE;
enum msg_file_type file_type = FILE_TYPE_NONE;
const char *file_path = str_list.elems[i].data;
int attr = str_list.elems[i].attr.i; /* [8] cache attr — read twice below */
if (!file_path || !*file_path)
continue;
dir_only_mode = ( filebrowser_type == FILEBROWSER_SELECT_DIR
|| filebrowser_type == FILEBROWSER_SCAN_DIR
|| filebrowser_type == FILEBROWSER_MANUAL_SCAN_DIR);
if (dir_only_mode && attr != RARCH_DIRECTORY)
continue;
if (!path_is_compressed)
{
file_path = path_basename_nocompression(file_path);
if (!file_path || !*file_path)
continue;
}
if (search_terms)
{
size_t j;
bool skip_entry = false;
for (j = 0; j < search_terms->size; j++)
{
const char *search_term = search_terms->terms[j];
if (search_term && *search_term
&& !compat_strcasestr(file_path, search_term))
{
skip_entry = true;
break;
}
}
if (skip_entry)
continue;
}
if (attr == RARCH_DIRECTORY)
{
count++;
menu_entries_append(info_list, file_path, "",
MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY,
FILE_TYPE_DIRECTORY, 0, 0, NULL);
continue;
}
/* Resolve base file type */
switch (attr)
{
case RARCH_COMPRESSED_ARCHIVE:
file_type = FILE_TYPE_CARCHIVE;
break;
case RARCH_COMPRESSED_FILE_IN_ARCHIVE:
file_type = FILE_TYPE_IN_CARCHIVE;
break;
case RARCH_PLAIN_FILE:
default:
file_type = (filebrowser_type == FILEBROWSER_SELECT_VIDEO_FONT)
? FILE_TYPE_VIDEO_FONT
: (enum msg_file_type)type_default;
if ( type == DISPLAYLIST_CORES_DETECTED
&& path_is_compressed_file(file_path))
file_type = FILE_TYPE_CARCHIVE;
break;
}
path_type = path_is_media_type(file_path);
if (filebrowser_type == FILEBROWSER_SELECT_COLLECTION)
file_type = FILE_TYPE_PLAYLIST_COLLECTION;
if (builtin_mediaplayer_enable || builtin_imageviewer_enable)
{
switch (path_type)
{
case RARCH_CONTENT_MUSIC:
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) || defined(HAVE_AUDIOMIXER)
if (builtin_mediaplayer_enable)
file_type = FILE_TYPE_MUSIC;
#endif
break;
case RARCH_CONTENT_MOVIE:
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) || defined(HAVE_WEBMPLAYER)
if (builtin_mediaplayer_enable)
file_type = FILE_TYPE_MOVIE;
#endif
break;
case RARCH_CONTENT_IMAGE:
#if defined(HAVE_IMAGEVIEWER) || defined(HAVE_MENU)
if (builtin_imageviewer_enable && type != DISPLAYLIST_IMAGES)
file_type = FILE_TYPE_IMAGEVIEWER;
else
file_type = FILE_TYPE_IMAGE;
#endif
if (filebrowser_type == FILEBROWSER_SELECT_IMAGE)
file_type = FILE_TYPE_IMAGE;
break;
default:
break;
}
}
switch (file_type)
{
case FILE_TYPE_MOVIE:
enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_MOVIE_OPEN;
break;
case FILE_TYPE_MUSIC:
enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_MUSIC_OPEN;
break;
case FILE_TYPE_IMAGE:
enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_IMAGE;
break;
case FILE_TYPE_IMAGEVIEWER:
enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_IMAGE_OPEN_WITH_VIEWER;
break;
default:
break;
}
count++;
menu_entries_append(info_list, file_path, "",
enum_idx, file_type, 0, 0, NULL);
}
dir_list_deinitialize(&str_list);
/* Content browsing only. Settings file pickers (shaders,
* overlays, configs, fonts, playlists...) keep full names,
* since there the extension is what tells the files apart.
* Duplicate hints apply only to entries in the filtered view. */
if ( settings
&& ( type == DISPLAYLIST_DEFAULT
|| type == DISPLAYLIST_CORES_DETECTED)
&& filebrowser_type != FILEBROWSER_SELECT_OVERLAY
&& filebrowser_type != FILEBROWSER_SELECT_IMAGE
&& filebrowser_type != FILEBROWSER_SELECT_VIDEO_FONT
&& filebrowser_type != FILEBROWSER_SELECT_COLLECTION)
menu_file_browser_prepare_extensions(info_list,
settings->uints.menu_file_browser_extension_display);
if (count == 0)
menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ITEMS),
MENU_ENUM_LABEL_NO_ITEMS_STR,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_NO_ITEM, 0, 0, NULL);
#if TARGET_OS_IPHONE || (TARGET_OS_OSX && defined(HAVE_APPLE_STORE))
{
struct string_list *sandbox_list = string_list_new();
dir_list_append(sandbox_list, "/private/var", NULL, true, false, false, false);
if (sandbox_list->size <= 0)
{
char dir[DIR_MAX_LENGTH];
size_t _len = fill_pathname_application_dir(dir, sizeof(dir));
if (string_ends_with(full_path, "/") && !string_ends_with(dir, "/"))
strlcpy_lit(dir + _len, "/", sizeof(dir) - _len);
if (string_is_equal(dir, full_path))
allow_parent_directory = false;
else
{
_len = fill_pathname_home_dir(dir, sizeof(dir));
if (string_ends_with(full_path, "/") && !string_ends_with(dir, "/"))
strlcpy_lit(dir + _len, "/", sizeof(dir) - _len);
if (string_is_equal(dir, full_path))
allow_parent_directory = false;
}
}
string_list_free(sandbox_list);
}
#endif
#undef RESOLVE_SUBSYSTEM
end:
if (allow_parent_directory && filebrowser_parent_is_hidden_root(full_path))
allow_parent_directory = false;
if (!path_is_compressed && allow_parent_directory)
menu_entries_prepend(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY),
path,
MENU_ENUM_LABEL_PARENT_DIRECTORY,
FILE_TYPE_PARENT_DIRECTORY, 0, 0);
return count;
}
static int menu_core_info_md5_parse(core_info_t *core_info, unsigned i, unsigned *j_ret)
{
int spc;
unsigned j;
unsigned pos = 0;
char firmware_basename[64];
char tmp[64];
strlcpy(tmp,
core_info->firmware[i].desc, sizeof(tmp));
spc = string_find_index_substring_string(tmp, " (");
if (spc >= 0)
tmp[spc] = '\0';
spc = string_find_index_substring_string(tmp, " |");
if (spc >= 0)
tmp[spc] = '\0';
fill_pathname_base(firmware_basename,
tmp, sizeof(firmware_basename));
for (j = 0; j < core_info->note_list->size; j++)
{
if ( !strstr(core_info->note_list->elems[j].data, firmware_basename)
|| !strstr(core_info->note_list->elems[j].data, "(md5)"))
continue;
pos = string_find_index_substring_string(core_info->note_list->elems[j].data, "(md5)");
break;
}
*j_ret = j;
return pos;
}
static int menu_displaylist_parse_core_info(
file_list_t *list,
uint32_t info_type,
const char *info_path,
settings_t *settings)
{
char tmp[NAME_MAX_LENGTH];
#if TARGET_OS_IPHONE
char shortened_path[NAME_MAX_LENGTH] = {0};
#endif
unsigned i, count = 0;
core_info_t *core_info = NULL;
const char *core_path = NULL;
const char *savestate_support = NULL;
bool kiosk_mode_enable = settings->bools.kiosk_mode_enable;
bool core_info_list_hide[64] = {false};
#if defined(HAVE_DYNAMIC)
enum menu_contentless_cores_display_type
contentless_display_type = (enum menu_contentless_cores_display_type)
settings->uints.menu_content_show_contentless_cores;
#endif
/* Check whether we are parsing information for a
* core updater/load/manager entry or the currently loaded core */
if ( info_type == FILE_TYPE_DOWNLOAD_CORE
|| info_type == FILE_TYPE_CORE
|| info_type == MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS)
{
core_info_t *core_info_menu = NULL;
core_path = info_path;
/* Core updater entry - search for corresponding
* core info */
if (core_info_find(core_path, &core_info_menu))
core_info = core_info_menu;
}
else if (core_info_get_current_core(&core_info) && core_info)
core_path = core_info->path;
else if (info_type == FILE_TYPE_NONE)
{
core_info_t *core_info_menu = NULL;
playlist_t *playlist = playlist_get_cached();
core_path = info_path;
if (playlist)
{
struct menu_state *menu_st = menu_state_get_ptr();
menu_handle_t *menu = menu_st->driver_data;
unsigned idx = menu->rpl_entry_selection_ptr;
const struct playlist_entry *entry = NULL;
playlist_get_index(playlist, idx, &entry);
if (entry)
{
core_path = entry->core_path;
if (!strcmp(entry->core_path, FILE_PATH_DETECT))
{
const char* default_core_path = playlist_get_default_core_path(playlist);
if ( default_core_path
&& strcmp(default_core_path, FILE_PATH_DETECT) != 0)
core_path = default_core_path;
}
}
}
/* Core updater entry - search for corresponding
* core info */
if (core_info_find(core_path, &core_info_menu))
core_info = core_info_menu;
}
if ( !core_info
|| !(core_info->flags & CORE_INFO_FLAG_HAS_INFO))
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE),
MENU_ENUM_LABEL_NO_CORE_INFORMATION_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_CORE_INFORMATION_AVAILABLE,
0, 0, 0, NULL))
count++;
goto end;
}
{
runloop_state_t *runloop_st = runloop_state_get_ptr();
unsigned i;
typedef struct menu_features_info
{
const char *name;
enum msg_hash_enums msg;
} menu_features_info_t;
menu_features_info_t info_list[] = {
{NULL, MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME},
{NULL, MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL},
{NULL, MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_VERSION},
{NULL, MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME},
{NULL, MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER},
};
info_list[0].name = core_info->core_name;
info_list[1].name = core_info->display_name;
info_list[2].name =
(string_is_equal(runloop_st->current_library_name,
core_info->core_name)
&& *runloop_st->current_library_version)
? runloop_st->current_library_version
: core_info->display_version;
info_list[3].name = core_info->systemname;
info_list[4].name = core_info->system_manufacturer;
for (i = 0; i < ARRAY_SIZE(info_list); i++)
{
size_t _len;
if (!info_list[i].name)
continue;
_len = strlcpy(tmp,
msg_hash_to_str(info_list[i].msg),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
strlcpy(tmp + _len, info_list[i].name, sizeof(tmp) - _len);
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
}
if (core_info->categories_list)
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
string_list_join_concat_special(tmp + _len, sizeof(tmp) - _len,
core_info->categories_list, ", ");
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
if (core_info->authors_list)
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
string_list_join_concat_special(tmp + _len, sizeof(tmp) - _len,
core_info->authors_list, ", ");
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
if (core_info->permissions_list)
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
string_list_join_concat_special(tmp + _len, sizeof(tmp) - _len,
core_info->permissions_list, ", ");
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
if (core_info->licenses_list)
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
string_list_join_concat_special(tmp + _len, sizeof(tmp) - _len,
core_info->licenses_list, ", ");
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
if (core_info->supported_extensions_list)
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
string_list_join_concat_special(tmp + _len, sizeof(tmp) - _len,
core_info->supported_extensions_list, ", ");
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
if (core_info->required_hw_api)
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_REQUIRED_HW_API),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
string_list_join_concat_special(tmp + _len, sizeof(tmp) - _len,
core_info->required_hw_api_list, ", ");
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
switch (core_info->savestate_support_level)
{
case CORE_INFO_SAVESTATE_BASIC:
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_BASIC);
break;
case CORE_INFO_SAVESTATE_SERIALIZED:
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SERIALIZED);
break;
case CORE_INFO_SAVESTATE_DETERMINISTIC:
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DETERMINISTIC);
break;
default:
if (core_info->savestate_support_level >
CORE_INFO_SAVESTATE_DETERMINISTIC)
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DETERMINISTIC);
else
savestate_support = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_DISABLED);
break;
}
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_SAVESTATE_SUPPORT_LEVEL),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
strlcpy(tmp + _len, savestate_support, sizeof(tmp) - _len);
}
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
if (core_path)
{
char tmp_desc[PATH_MAX_LENGTH];
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_PATH),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
#if TARGET_OS_IPHONE
shortened_path[0] = '\0';
fill_pathname_abbreviate_special(shortened_path,
core_path, sizeof(shortened_path));
strlcpy(tmp_desc, shortened_path, sizeof(tmp_desc));
#else
strlcpy(tmp_desc, core_path, sizeof(tmp_desc));
#endif
if (!settings->bools.menu_show_sublabels)
_len += strlcpy(tmp + _len, tmp_desc, sizeof(tmp) - _len);
if (menu_entries_append(list, tmp, tmp_desc,
MENU_ENUM_LABEL_CORE_INFO_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
if (core_info->firmware_count > 0)
{
char tmp_path[PATH_MAX_LENGTH];
char tmp_desc[PATH_MAX_LENGTH];
size_t tmp_desc_len;
core_info_ctx_firmware_t firmware_info;
uint8_t flags = content_get_flags();
bool update_missing_firmware = false;
bool systemfiles_in_content_dir = settings->bools.systemfiles_in_content_dir;
bool content_is_inited = flags & CONTENT_ST_FLAG_IS_INITED;
firmware_info.path = core_info->path;
/* If 'System Files are in Content Directory' is enabled and content is inited,
* adjust the path to check for firmware files */
if (systemfiles_in_content_dir && content_is_inited)
{
size_t __len = fill_pathname_basedir(tmp_path,
path_get(RARCH_PATH_CONTENT),
sizeof(tmp_path));
/* If content path is empty, fall back to global system dir path */
if (!*tmp_path)
firmware_info.directory.system = settings->paths.directory_system;
else
{
/* Removes trailing slash (unless root dir), doesn't really matter
* but it's more consistent with how the path is stored and
* displayed without 'System Files are in Content Directory' */
if ( string_count_occurrences_single_character(tmp_path, PATH_DEFAULT_SLASH_C()) > 1
&& tmp_path[__len - 1] == PATH_DEFAULT_SLASH_C())
tmp_path[__len - 1] = '\0';
firmware_info.directory.system = tmp_path;
}
}
else
firmware_info.directory.system = settings->paths.directory_system;
update_missing_firmware = core_info_list_update_missing_firmware(&firmware_info);
if (update_missing_firmware)
{
const char *missing_optional = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MISSING_OPTIONAL);
const char *missing_required = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MISSING_REQUIRED);
const char *present_optional = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PRESENT_OPTIONAL);
const char *present_required = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PRESENT_REQUIRED);
const char *rdb_entry_name =
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME);
size_t __len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE),
sizeof(tmp));
tmp[ __len] = ':';
tmp[++__len] = ' ';
tmp[++__len] = '\0';
/* Show the path that was checked */
{
int _snprintf_ret;
#if TARGET_OS_IPHONE
shortened_path[0] = '\0';
fill_pathname_abbreviate_special(shortened_path,
firmware_info.directory.system,
sizeof(shortened_path));
_snprintf_ret = snprintf(tmp_desc, sizeof(tmp_desc),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_PATH),
shortened_path);
#else
_snprintf_ret = snprintf(tmp_desc, sizeof(tmp_desc),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_PATH),
firmware_info.directory.system);
#endif
if (_snprintf_ret < 0)
tmp_desc_len = 0;
else if ((size_t)_snprintf_ret >= sizeof(tmp_desc))
tmp_desc_len = sizeof(tmp_desc) - 1;
else
tmp_desc_len = (size_t)_snprintf_ret;
if (!settings->bools.menu_show_sublabels)
{
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
__len = strlcpy_lit(tmp, "- ", sizeof(tmp));
strlcpy(tmp + __len, tmp_desc, sizeof(tmp) - __len);
tmp_desc[0] = '\0';
tmp_desc_len = 0;
}
/* If 'System Files are in Content Directory' is enabled, let's add a note about it. */
if (systemfiles_in_content_dir)
{
if (!settings->bools.menu_show_sublabels)
{
char tmp_note[PATH_MAX_LENGTH];
snprintf(tmp_note, sizeof(tmp_note), "- %s",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_IN_CONTENT_DIRECTORY));
if (menu_entries_append(list, tmp_note, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
else
{
tmp_desc_len += strlcpy_lit(tmp_desc + tmp_desc_len, "\n", sizeof(tmp_desc) - tmp_desc_len);
strlcpy(tmp_desc + tmp_desc_len,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE_IN_CONTENT_DIRECTORY),
sizeof(tmp_desc) - tmp_desc_len);
}
}
if (menu_entries_append(list, tmp, tmp_desc,
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
for (i = 0; i < core_info->firmware_count; i++)
{
if (!core_info->firmware[i].desc)
continue;
snprintf(tmp, sizeof(tmp), "%s %s",
core_info->firmware[i].missing
? (core_info->firmware[i].optional ? missing_optional : missing_required)
: (core_info->firmware[i].optional ? present_optional : present_required),
core_info->firmware[i].desc ? core_info->firmware[i].desc : rdb_entry_name
);
tmp_desc[0] = '\0';
/* Parse md5 checksum rows as sublabels */
if ( core_info->notes
&& settings->bools.menu_show_sublabels)
{
unsigned j;
unsigned pos = menu_core_info_md5_parse(core_info, i, &j);
if (pos)
{
core_info_list_hide[j] = true;
strlcpy(tmp_desc,
core_info->note_list->elems[j].data + pos,
sizeof(tmp_desc));
}
}
if (menu_entries_append(list, tmp, tmp_desc,
MENU_ENUM_LABEL_CORE_INFO_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, i, NULL))
count++;
/* Show relevant note row and skip showing it later */
if ( core_info->notes
&& !settings->bools.menu_show_sublabels)
{
unsigned j;
unsigned pos = menu_core_info_md5_parse(core_info, i, &j);
if (pos)
{
core_info_list_hide[j] = true;
__len = strlcpy_lit(tmp, "- ", sizeof(tmp));
strlcpy( tmp + __len,
core_info->note_list->elems[j].data + pos,
sizeof(tmp) - __len);
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
}
}
}
}
if (core_info->notes)
{
for (i = 0; i < core_info->note_list->size; i++)
{
if (core_info_list_hide[i])
continue;
strlcpy(tmp,
core_info->note_list->elems[i].data, sizeof(tmp));
if (menu_entries_append(list, tmp, "",
MENU_ENUM_LABEL_CORE_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
}
end:
if (!kiosk_mode_enable)
{
#if defined(HAVE_DYNAMIC)
/* Exclude core from contentless cores menu */
if ((contentless_display_type ==
MENU_CONTENTLESS_CORES_DISPLAY_CUSTOM)
&& core_info
&& (core_info->flags & CORE_INFO_FLAG_SUPPORTS_NO_GAME)
&& (core_path && *core_path))
{
/* Note: Have to set core_path as both the
* 'path' and 'label' parameters (otherwise
* cannot access it in menu_cbs_get_value.c
* or menu_cbs_left/right.c), which means
* entry name must be set as 'alt' text */
if (menu_entries_append(list,
core_path, core_path,
MENU_ENUM_LABEL_CORE_SET_STANDALONE_EXEMPT,
MENU_SETTING_ACTION_CORE_SET_STANDALONE_EXEMPT, 0, 0, NULL))
{
file_list_set_alt_at_offset(list, count,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_SET_STANDALONE_EXEMPT));
count++;
}
}
#endif
#if !TARGET_OS_IPHONE /* should this be allowed on jailbroken iOS devices? */
if (core_path && *core_path)
{
/* Check whether core is currently locked */
bool core_locked = core_info_get_core_lock(core_path, true);
#if defined(ANDROID)
/* Play Store builds do not support
* core locking */
if (!play_feature_delivery_enabled())
#endif
{
/* Lock core
* > Note: Have to set core_path as both the
* 'path' and 'label' parameters (otherwise
* cannot access it in menu_cbs_get_value.c
* or menu_cbs_left/right.c), which means
* entry name must be set as 'alt' text */
if (menu_entries_append(list,
core_path,
core_path,
MENU_ENUM_LABEL_CORE_LOCK,
MENU_SETTING_ACTION_CORE_LOCK, 0, 0, NULL))
{
file_list_set_alt_at_offset(
list, count, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LOCK));
count++;
}
}
/* Backup core */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_CREATE_BACKUP),
core_path,
MENU_ENUM_LABEL_CORE_CREATE_BACKUP,
MENU_SETTING_ACTION_CORE_CREATE_BACKUP, 0, 0, NULL))
count++;
{
core_backup_list_t *backup_list = core_backup_list_init(core_path, settings->paths.directory_core_assets);
if (backup_list && core_backup_list_size(backup_list))
{
/* Restore core from backup */
if (!core_locked)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_RESTORE_BACKUP_LIST),
core_path,
MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_LIST,
MENU_SETTING_ACTION_CORE_RESTORE_BACKUP, 0, 0, NULL))
count++;
/* Delete core backup */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_DELETE_BACKUP_LIST),
core_path,
MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST,
MENU_SETTING_ACTION_CORE_DELETE_BACKUP, 0, 0, NULL))
count++;
}
}
/* Delete core
* > Only add this option if online updater is
* enabled/activated, otherwise user could end
* up in a situation where a core cannot be
* restored */
#if defined(HAVE_NETWORKING) && defined(HAVE_ONLINE_UPDATER)
if (settings->bools.menu_show_core_updater && !core_locked)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_DELETE),
core_path,
MENU_ENUM_LABEL_CORE_DELETE,
MENU_SETTING_ACTION_CORE_DELETE, 0, 0, NULL))
count++;
#endif
/* Reset core options */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET),
core_info ? core_info->core_name : NULL,
MENU_ENUM_LABEL_CORE_OPTIONS_RESET,
MENU_SETTING_ACTION_CORE_OPTIONS_RESET, 0, 0, NULL))
count++;
}
#endif
}
return count;
}
/* Fetches a string representation of a backup
* list entry timestamp.
* Returns false in the event of an error */
static size_t core_backup_list_get_entry_timestamp_str(
const core_backup_list_entry_t *entry,
enum core_backup_date_separator_type date_separator,
char *s, size_t len)
{
const char *format_str = "%04u-%02u-%02u %02u:%02u:%02u";
/* Get time format string */
if (date_separator == CORE_BACKUP_DATE_SEPARATOR_SLASH)
format_str = "%04u/%02u/%02u %02u:%02u:%02u";
else if (date_separator == CORE_BACKUP_DATE_SEPARATOR_PERIOD)
format_str = "%04u.%02u.%02u %02u:%02u:%02u";
return snprintf(s, len,
format_str,
entry->date.year,
entry->date.month,
entry->date.day,
entry->date.hour,
entry->date.minute,
entry->date.second);
}
static unsigned menu_displaylist_parse_core_backup_list(
file_list_t *list, const char *core_path,
const char *dir_core_assets,
enum core_backup_date_separator_type date_separator,
bool restore)
{
enum msg_hash_enums enum_idx;
enum menu_settings_type settings_type;
unsigned count = 0;
core_backup_list_t *backup_list = NULL;
if (restore)
{
enum_idx = MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_ENTRY;
settings_type = MENU_SETTING_ITEM_CORE_RESTORE_BACKUP;
}
else
{
/* If we're not restoring, we're deleting */
enum_idx = MENU_ENUM_LABEL_CORE_DELETE_BACKUP_ENTRY;
settings_type = MENU_SETTING_ITEM_CORE_DELETE_BACKUP;
}
/* Get backup list */
backup_list = core_backup_list_init(core_path, dir_core_assets);
if (backup_list)
{
size_t i;
size_t menu_index = 0;
for (i = 0; i < core_backup_list_size(backup_list); i++)
{
const core_backup_list_entry_t *entry = NULL;
/* Ensure entry is valid */
if ( core_backup_list_get_index(backup_list, i, &entry)
&& entry
&& (entry->backup_path && *entry->backup_path))
{
char timestamp[128];
/* Get timestamp and crc strings */
size_t _len = core_backup_list_get_entry_timestamp_str(
entry, date_separator, timestamp, sizeof(timestamp));
/* Append 'auto backup' tag to timestamp, if required */
if (entry->backup_mode == CORE_BACKUP_MODE_AUTO)
{
_len += strlcpy_lit(timestamp + _len, " ", sizeof(timestamp) - _len);
strlcpy(timestamp + _len, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_BACKUP_MODE_AUTO),
sizeof(timestamp) - _len);
}
/* Add menu entry */
if (menu_entries_append(list,
timestamp,
entry->backup_path,
enum_idx,
settings_type, 0, 0, NULL))
{
char crc[16];
snprintf(crc, sizeof(crc), "%08lx", (unsigned long)entry->crc);
/* We need to set backup path, timestamp and crc
* > Only have 2 useable fields as standard
* ('path' and 'label'), so have to set the
* crc as 'alt' text */
file_list_set_alt_at_offset(list, menu_index, crc);
menu_index++;
count++;
}
}
}
core_backup_list_free(backup_list);
}
/* Fallback, in case no backups are found */
if (count == 0)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE_BACKUPS_AVAILABLE),
MENU_ENUM_LABEL_NO_CORE_BACKUPS_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_CORE_BACKUPS_AVAILABLE,
0, 0, 0, NULL))
count++;
return count;
}
static unsigned menu_displaylist_parse_core_manager_list(file_list_t *list,
bool kiosk_mode_enable)
{
unsigned count = 0;
core_info_list_t *core_info_list = NULL;
/* Get core list */
core_info_get_list(&core_info_list);
if (core_info_list)
{
size_t i;
size_t menu_index = 0;
menu_search_terms_t *search_terms= menu_entries_search_get_terms();
/* Sort cores alphabetically */
core_info_qsort(core_info_list, CORE_INFO_LIST_SORT_DISPLAY_NAME);
/* Loop through cores */
for (i = 0; i < core_info_list->count; i++)
{
core_info_t *core_info = core_info_get(core_info_list, i);
if (core_info)
{
/* If a search is active, skip non-matching
* entries */
if (search_terms)
{
bool entry_valid = true;
size_t j;
for (j = 0; j < search_terms->size; j++)
{
const char *search_term = search_terms->terms[j];
if ( (search_term && *search_term)
&& (core_info->display_name && *core_info->display_name)
&& !compat_strcasestr(core_info->display_name, search_term))
{
entry_valid = false;
break;
}
}
if (!entry_valid)
continue;
}
if (menu_entries_append(list,
core_info->path,
"",
MENU_ENUM_LABEL_CORE_MANAGER_ENTRY,
MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS,
0, 0, NULL))
{
file_list_set_alt_at_offset(list, menu_index,
core_info->display_name);
menu_index++;
count++;
}
}
}
}
#if !TARGET_OS_IPHONE
/* Add 'sideload core' entry */
if (!kiosk_mode_enable)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_LIST),
MENU_ENUM_LABEL_SIDELOAD_CORE_LIST_STR,
MENU_ENUM_LABEL_SIDELOAD_CORE_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
#if defined(HAVE_IMAGEVIEWER) || defined(HAVE_MENU) || defined(HAVE_FFMPEG) || defined(HAVE_MPV) || defined(HAVE_AUDIOMIXER)
{
/* MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM requires 'settings',
* so the scope only exists where one of the entries below
* is built in. */
settings_t *settings = config_get_ptr();
#if defined(HAVE_IMAGEVIEWER) || defined(HAVE_MENU)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_USE_BUILTIN_IMAGE_VIEWER, PARSE_ONLY_BOOL,
false) == 0)
count++;
#endif
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) || defined (HAVE_AUDIOMIXER)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_USE_BUILTIN_PLAYER, PARSE_ONLY_BOOL,
false) == 0)
count++;
#endif
}
#endif
return count;
}
#ifdef HAVE_MIST
static unsigned menu_displaylist_parse_core_manager_steam_list(file_list_t *list)
{
size_t i;
steam_core_dlc_list_t *dlc_list;
unsigned count = 0;
MistResult result = steam_get_core_dlcs(&dlc_list, false);
if (MIST_IS_ERROR(result))
{
/* TODO/FIXME: Send error notification */
RARCH_ERR("[Steam] Error enumerating core dlcs for core manager (%d-%d).\n", MIST_UNPACK_RESULT(result));
return 0;
}
for (i = 0; i < dlc_list->count; i++)
{
steam_core_dlc_t *dlc_info = steam_core_dlc_list_get(dlc_list, i);
if (menu_entries_append(list,
dlc_info->name,
"",
MENU_ENUM_LABEL_CORE_MANAGER_STEAM_ENTRY,
MENU_SETTING_ACTION_CORE_MANAGER_STEAM_OPTIONS,
0, 0, NULL))
count++;
}
return count;
}
static unsigned menu_displaylist_parse_core_information_steam(
file_list_t *info_list, const char *info_path)
{
steam_core_dlc_list_t *dlc_list;
unsigned count = 0;
steam_core_dlc_t *core_dlc = NULL;
bool installed = false;
MistResult result = steam_get_core_dlcs(&dlc_list, false);
if (MIST_IS_ERROR(result))
goto error;
/* Get the core dlc information */
if (!(core_dlc = steam_get_core_dlc_by_name(dlc_list, info_path)))
return 0;
/* Check if installed */
result = mist_steam_apps_is_dlc_installed(core_dlc->app_id, &installed);
if (MIST_IS_ERROR(result))
goto error;
if (installed)
{
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_STEAM_UNINSTALL),
core_dlc->name,
MENU_ENUM_LABEL_CORE_STEAM_UNINSTALL,
MENU_SETTING_ACTION_CORE_STEAM_UNINSTALL,
0, 0, NULL))
count++;
}
else
{
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_STEAM_INSTALL),
core_dlc->name,
MENU_ENUM_LABEL_CORE_STEAM_INSTALL,
MENU_SETTING_ACTION_CORE_STEAM_INSTALL,
0, 0, NULL))
count++;
}
return count;
error:
/* TODO: Send error notification */
RARCH_ERR("[Steam] Error getting core information (%d-%d).\n", MIST_UNPACK_RESULT(result));
return count;
}
#endif
static unsigned menu_displaylist_parse_core_option_dropdown_list(
file_list_t *info_list, const char *info_path)
{
int j;
char val_d[8];
unsigned count = 0;
unsigned option_index = 0;
unsigned checked = 0;
bool checked_found = false;
core_option_manager_t *coreopts = NULL;
struct core_option *option = NULL;
const char *val = NULL;
const char *lbl_enabled = NULL;
const char *lbl_disabled = NULL;
const char *val_on_str = NULL;
const char *val_off_str = NULL;
const char *opt = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
/* Fetch options */
retroarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts);
/* Path string has the format core_option_<opt_idx>
* > Extract option index */
if (!coreopts || !info_path || !*info_path)
return 0;
if (!(opt = strrchr(info_path, '_')))
return 0;
option_index = string_to_unsigned(opt+1);
/* The core option set can shrink at runtime, leaving a stale
* entry index in the menu path. Reject an out-of-range index
* before taking the address of coreopts->opts[option_index]. */
if (option_index >= coreopts->size)
return 0;
val_d[0] = '\0';
snprintf(val_d, sizeof(val_d), "%d", option_index);
/* Get option itself + current value */
option = (struct core_option*)&coreopts->opts[option_index];
val = core_option_manager_get_val(coreopts, option_index);
if (!val || !*val)
return 0;
lbl_enabled = msg_hash_to_str(MENU_ENUM_LABEL_ENABLED);
lbl_disabled = msg_hash_to_str(MENU_ENUM_LABEL_DISABLED);
val_on_str = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON);
val_off_str = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
/* Loop over all option values */
for (j = 0; j < (int)option->vals->size; j++)
{
const char *val_str = option->vals->elems[j].data;
const char *val_label_str = option->val_labels->elems[j].data;
if (val_label_str && *val_label_str)
{
if (string_is_equal(val_label_str, lbl_enabled))
val_label_str = val_on_str;
else if (string_is_equal(val_label_str, lbl_disabled))
val_label_str = val_off_str;
if (menu_entries_append(info_list,
val_label_str,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_SETTING_CORE_OPTIONS_ITEM, j, 0, NULL))
count++;
if (!checked_found && string_is_equal(val_str, val))
{
checked = j;
checked_found = true;
}
}
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)
info_list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
return count;
}
static unsigned menu_displaylist_parse_core_option_override_list(file_list_t *list,
bool show_core_options_flush)
{
unsigned count = 0;
runloop_state_t *runloop_st = runloop_state_get_ptr();
uint32_t flags = runloop_get_flags();
bool core_has_options = !retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)
&& (runloop_st->core_options);
bool game_options_active = (flags & RUNLOOP_FLAG_GAME_OPTIONS_ACTIVE) ? true : false;
bool folder_options_active = (flags & RUNLOOP_FLAG_FOLDER_OPTIONS_ACTIVE) ? true : false;
const char *a = path_get(RARCH_PATH_CONTENT);
/* Sanity check - cannot handle core option
* overrides if:
* - Core is 'dummy'
* - Core has no options
* - No content has been loaded */
if (!core_has_options || (!a || !*a))
goto end;
/* Show currently active core options file */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_OPTION_OVERRIDE_INFO),
MENU_ENUM_LABEL_CORE_OPTION_OVERRIDE_INFO_STR,
MENU_ENUM_LABEL_CORE_OPTION_OVERRIDE_INFO,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
/* Save core option overrides */
if (!game_options_active)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_CORE_OPTIONS_CREATE),
MENU_ENUM_LABEL_GAME_SPECIFIC_CORE_OPTIONS_CREATE_STR,
MENU_ENUM_LABEL_GAME_SPECIFIC_CORE_OPTIONS_CREATE,
MENU_SETTING_ACTION_GAME_SPECIFIC_CORE_OPTIONS_CREATE, 0, 0, NULL))
count++;
}
else
{
/* Remove core option overrides */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GAME_SPECIFIC_CORE_OPTIONS_REMOVE),
MENU_ENUM_LABEL_GAME_SPECIFIC_CORE_OPTIONS_REMOVE_STR,
MENU_ENUM_LABEL_GAME_SPECIFIC_CORE_OPTIONS_REMOVE,
MENU_SETTING_ACTION_GAME_SPECIFIC_CORE_OPTIONS_REMOVE, 0, 0, NULL))
count++;
}
if (folder_options_active)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FOLDER_SPECIFIC_CORE_OPTIONS_REMOVE),
MENU_ENUM_LABEL_FOLDER_SPECIFIC_CORE_OPTIONS_REMOVE_STR,
MENU_ENUM_LABEL_FOLDER_SPECIFIC_CORE_OPTIONS_REMOVE,
MENU_SETTING_ACTION_FOLDER_SPECIFIC_CORE_OPTIONS_REMOVE, 0, 0, NULL))
count++;
}
else
{
if (!game_options_active)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FOLDER_SPECIFIC_CORE_OPTIONS_CREATE),
MENU_ENUM_LABEL_FOLDER_SPECIFIC_CORE_OPTIONS_CREATE_STR,
MENU_ENUM_LABEL_FOLDER_SPECIFIC_CORE_OPTIONS_CREATE,
MENU_SETTING_ACTION_FOLDER_SPECIFIC_CORE_OPTIONS_CREATE, 0, 0, NULL))
count++;
}
end:
if (core_has_options)
{
/* Flush core options to disk */
if (show_core_options_flush)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_FLUSH),
MENU_ENUM_LABEL_CORE_OPTIONS_FLUSH_STR,
MENU_ENUM_LABEL_CORE_OPTIONS_FLUSH,
MENU_SETTING_ACTION_CORE_OPTIONS_FLUSH, 0, 0, NULL))
count++;
/* Reset core options */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET),
"",
MENU_ENUM_LABEL_CORE_OPTIONS_RESET,
MENU_SETTING_ACTION_CORE_OPTIONS_RESET, 0, 0, NULL))
count++;
}
return count;
}
static unsigned menu_displaylist_parse_remap_file_manager_list(file_list_t *list,
bool remap_save_on_exit)
{
unsigned count = 0;
uint32_t flags = runloop_get_flags();
const char *a = path_get(RARCH_PATH_CONTENT);
bool has_content = a && *a;
bool core_remap_active = (flags & RUNLOOP_FLAG_REMAPS_CORE_ACTIVE) ? true : false;
bool content_dir_remap_active = (flags & RUNLOOP_FLAG_REMAPS_CONTENT_DIR_ACTIVE) ? true : false;
bool game_remap_active = (flags & RUNLOOP_FLAG_REMAPS_GAME_ACTIVE) ? true : false;
/* Sanity check - cannot handle remap files
* unless a valid core is running */
if ( !(flags & RUNLOOP_FLAG_CORE_RUNNING)
|| retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
return 0;
/* Show currently 'active' remap file */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_INFO),
MENU_ENUM_LABEL_REMAP_FILE_INFO_STR,
MENU_ENUM_LABEL_REMAP_FILE_INFO,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
/* Load remap file */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD),
MENU_ENUM_LABEL_REMAP_FILE_LOAD_STR,
MENU_ENUM_LABEL_REMAP_FILE_LOAD,
MENU_SETTING_ACTION_REMAP_FILE_LOAD, 0, 0, NULL))
count++;
/* Save as */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_AS),
MENU_ENUM_LABEL_REMAP_FILE_SAVE_AS_STR,
MENU_ENUM_LABEL_REMAP_FILE_SAVE_AS,
MENU_SETTING_ACTION_REMAP_FILE_SAVE_AS, 0, 0, NULL))
count++;
if (!game_remap_active)
{
/* Save remap files */
if (has_content)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME),
MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME_STR,
MENU_ENUM_LABEL_REMAP_FILE_SAVE_GAME,
MENU_SETTING_ACTION_REMAP_FILE_SAVE_GAME, 0, 0, NULL))
count++;
}
if (!content_dir_remap_active)
{
if (has_content &&
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CONTENT_DIR),
MENU_ENUM_LABEL_REMAP_FILE_SAVE_CONTENT_DIR_STR,
MENU_ENUM_LABEL_REMAP_FILE_SAVE_CONTENT_DIR,
MENU_SETTING_ACTION_REMAP_FILE_SAVE_CONTENT_DIR, 0, 0, NULL))
count++;
if (
!core_remap_active &&
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE),
MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE_STR,
MENU_ENUM_LABEL_REMAP_FILE_SAVE_CORE,
MENU_SETTING_ACTION_REMAP_FILE_SAVE_CORE, 0, 0, NULL))
count++;
}
}
/* Remove remap files */
if (has_content)
{
if (game_remap_active &&
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_GAME),
MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME_STR,
MENU_ENUM_LABEL_REMAP_FILE_REMOVE_GAME,
MENU_SETTING_ACTION_REMAP_FILE_REMOVE_GAME, 0, 0, NULL))
count++;
if (content_dir_remap_active &&
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CONTENT_DIR),
MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CONTENT_DIR_STR,
MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CONTENT_DIR,
MENU_SETTING_ACTION_REMAP_FILE_REMOVE_CONTENT_DIR, 0, 0, NULL))
count++;
}
if (core_remap_active &&
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_REMOVE_CORE),
MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE_STR,
MENU_ENUM_LABEL_REMAP_FILE_REMOVE_CORE,
MENU_SETTING_ACTION_REMAP_FILE_REMOVE_CORE, 0, 0, NULL))
count++;
/* Reset input remaps */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_RESET),
MENU_ENUM_LABEL_REMAP_FILE_RESET_STR,
MENU_ENUM_LABEL_REMAP_FILE_RESET,
MENU_SETTING_ACTION_REMAP_FILE_RESET, 0, 0, NULL))
count++;
/* Flush input remaps to disk */
if ( !remap_save_on_exit
&& (core_remap_active
|| content_dir_remap_active
|| game_remap_active)
&& menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_FLUSH),
MENU_ENUM_LABEL_REMAP_FILE_FLUSH_STR,
MENU_ENUM_LABEL_REMAP_FILE_FLUSH,
MENU_SETTING_ACTION_REMAP_FILE_FLUSH, 0, 0, NULL))
count++;
return count;
}
static unsigned menu_displaylist_parse_supported_cores(
menu_displaylist_info_t *info,
bool enable_load_with_current,
const char *core_path_current,
const char *content_path,
enum msg_hash_enums core_enum_label,
enum msg_hash_enums current_core_enum_label)
{
unsigned count = 0;
core_info_list_t *core_info_list = NULL;
bool core_available = false;
/* Get core list */
if ( core_info_get_list(&core_info_list)
&& core_info_list)
{
const char *detect_core_str = NULL;
const core_info_t *core_infos = NULL;
size_t core_infos_size = 0;
size_t core_idx = 0;
size_t entry_idx = 0;
const char *pending_core_path = NULL;
const char *pending_core_name = NULL;
bool core_is_pending = false;
/* Get list of supported cores */
core_info_list_get_supported_cores(core_info_list,
content_path, &core_infos, &core_infos_size);
detect_core_str = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_DETECT_CORE_LIST_OK_CURRENT_CORE);
for (core_idx = 0; core_idx < core_infos_size; core_idx++)
{
const core_info_t *core_info = (const core_info_t*)&core_infos[core_idx];
const char *core_path = core_info->path;
const char *core_name = core_info->display_name;
if ( (!core_path || !*core_path)
|| (!core_name || !*core_name))
continue;
/* If the content is supported by the currently
* loaded core, add a 'special' entry which
* (a) highlights this fact and (b) allows
* special handling of the the content (e.g.
* allow it to be launched without a core reload)
* > This functionality is disabled on static platforms
* when 'always_reload_core_on_run_content' is enabled */
if ( enable_load_with_current
&& string_is_equal(core_path, core_path_current))
{
/* This is a 'pending' entry. It will be
* prepended to the displaylist once all
* other cores have been added */
pending_core_path = core_path;
pending_core_name = core_name;
core_is_pending = true;
}
else if (menu_entries_append(info->list, core_path,
msg_hash_to_str(core_enum_label), core_enum_label,
FILE_TYPE_CORE, 0, 0, NULL))
{
file_list_set_alt_at_offset(info->list, entry_idx, core_name);
core_available = true;
entry_idx++;
count++;
}
}
/* If cores were found, sort the displaylist now */
if (core_available)
file_list_sort_on_alt(info->list);
/* If we have a 'pending' entry, prepended it
* to the displaylist */
if (core_is_pending)
{
char entry_alt_text[NAME_MAX_LENGTH];
size_t _len = strlcpy(entry_alt_text, detect_core_str,
sizeof(entry_alt_text));
_len += strlcpy_lit(entry_alt_text + _len, " (", sizeof(entry_alt_text) - _len);
_len += strlcpy(entry_alt_text + _len,
pending_core_name,
sizeof(entry_alt_text) - _len);
strlcpy_lit(entry_alt_text + _len, ")", sizeof(entry_alt_text) - _len);
menu_entries_prepend(info->list, pending_core_path,
msg_hash_to_str(current_core_enum_label),
current_core_enum_label, FILE_TYPE_CORE, 0, 0);
file_list_set_alt_at_offset(info->list, 0, entry_alt_text);
core_available = true;
count++;
}
}
/* Fallback */
if (!core_available)
{
/* We have to handle an annoying special case here.
* Some RetroArch ports (e.g. emscripten) are 'broken'
* by design - they do not handle cores correctly,
* resulting in empty core_info lists and thus no
* concept of supported content. These builds are
* typically static, such that the currently running
* core is the only one available. To enable the
* loading of *any* content on these troublesome
* platforms, we therefore have to:
* 1) Detect the presence of a running core
* 2) Blindly add a menu entry enabling the
* selection of this core
* 3) Hope that the user does not attempt to
* load unsupported content... */
/* Attempt to identify 'broken' platforms by fetching
* the core file extension - if there is none, then
* it is impossible for RetroArch to populate a
* core_info list. Platforms that cannot switch cores
* at runtime define LOAD_WITHOUT_CORE_INFO to skip
* this check, since refusing the running core would
* leave no options at all. */
#if !defined(LOAD_WITHOUT_CORE_INFO)
char exts[16];
if ( !frontend_driver_get_core_extension(exts, sizeof(exts))
|| !*exts)
#endif
{
struct retro_system_info *sysinfo = &runloop_state_get_ptr()->system.info;
const char *core_path = core_path_current;
const char *core_name = sysinfo ? sysinfo->library_name : NULL;
if (core_path && *core_path)
{
/* If we have a valid 'currently running' core
* path, add an entry for this core to the list */
if (menu_entries_append(info->list, core_path,
msg_hash_to_str(current_core_enum_label),
current_core_enum_label, FILE_TYPE_DIRECT_LOAD, 0, 0, NULL))
{
if (core_name && *core_name)
file_list_set_alt_at_offset(info->list, 0, core_name);
core_available = true;
count++;
}
}
else if (core_name && *core_name)
{
/* If we have a valid core name, but no core
* path, then RetroArch on this platform is
* likely to be unusable. But this legacy code
* path has existed for many years, and since
* we do not know who added it, or why, we
* shall continue to include it lest we break
* an unknown platform... */
if (menu_entries_append(info->list, core_name,
msg_hash_to_str(current_core_enum_label),
current_core_enum_label, FILE_TYPE_DIRECT_LOAD, 0, 0, NULL))
{
core_available = true;
count++;
}
}
}
if (!core_available)
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE),
MENU_ENUM_LABEL_NO_CORES_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_CORES_AVAILABLE,
0, 0, 0, NULL))
count++;
info->flags |= MD_FLAG_DOWNLOAD_CORE;
}
}
return count;
}
#if defined(HAVE_VULKAN) && defined(__APPLE__)
/* Implemented in gfx/common/vulkan_common.c. Forward-declared here to
* avoid pulling the Vulkan headers into the menu translation unit. */
const char *vulkan_get_moltenvk_version(void);
#endif
/* System Information > Display Information: the display in use as
* the display server sees it. Rebuilt on every entry, so back out and
* in to refresh. */
static unsigned menu_displaylist_parse_display_info(file_list_t *list)
{
char entry[NAME_MAX_LENGTH];
unsigned count = 0;
size_t _len;
unsigned dims = 0;
float hz;
video_output_info_t outputs[8];
int n_out, i;
/* Display Server */
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_INFO_SERVER),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len, video_display_server_get_ident(), sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
/* Outputs: name, size, placement */
n_out = video_display_server_list_outputs(outputs,
(int)(sizeof(outputs) / sizeof(outputs[0])));
for (i = 0; i < n_out; i++)
{
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_INFO_OUTPUT),
sizeof(entry));
_len += snprintf(entry + _len, sizeof(entry) - _len, " %d: %s %ux%u @ %d,%d%s",
i + 1, outputs[i].name, VIDEO_SCALE_W(outputs[i].dims), VIDEO_SCALE_H(outputs[i].dims),
outputs[i].x, outputs[i].y, outputs[i].primary ? " *" : "");
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
/* Resolution: the desktop mode of the display in use */
{
char mode[64];
mode[0] = '\0';
if (video_display_server_get_video_output_size(&dims, mode, sizeof(mode))
&& VIDEO_SCALE_W(dims) && VIDEO_SCALE_H(dims))
{
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_INFO_RESOLUTION),
sizeof(entry));
_len += snprintf(entry + _len, sizeof(entry) - _len, ": %ux%u",
VIDEO_SCALE_W(dims), VIDEO_SCALE_H(dims));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
}
/* Refresh Rate */
hz = video_display_server_get_refresh_rate();
if (hz > 0.0f)
{
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_INFO_REFRESH_RATE),
sizeof(entry));
snprintf(entry + _len, sizeof(entry) - _len, ": %.3f Hz", hz);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
/* Pacing: the same line as the statistics overlay, here because
* the overlay does not draw over the menu, and what paces the
* menu is exactly the question this answers. Read at build; the
* list rebuilds on entry, so back out and in again to refresh. */
{
char pbuf[64];
runloop_pace_string(pbuf, sizeof(pbuf));
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PACING),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len, pbuf, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
/* Whether the low-latency release the setting asks for is in
* effect, and why not when it is not: asked for and working
* are two different things. */
if (config_get_ptr()->uints.video_driver_pacing)
{
runloop_driver_pacing_string(pbuf, sizeof(pbuf));
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DRIVER_PACING),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len, pbuf, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
}
/* Display Width / Height (mm), DPI: the context's metrics */
{
gfx_ctx_metrics_t metrics;
float val = 0.0f;
metrics.value = &val;
metrics.type = DISPLAY_METRIC_MM_WIDTH;
if (video_context_driver_get_metrics(&metrics))
{
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH),
sizeof(entry));
snprintf(entry + _len, sizeof(entry) - _len, ": %.2f", val);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
metrics.type = DISPLAY_METRIC_MM_HEIGHT;
if (video_context_driver_get_metrics(&metrics))
{
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT),
sizeof(entry));
snprintf(entry + _len, sizeof(entry) - _len, ": %.2f", val);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
metrics.type = DISPLAY_METRIC_DPI;
if (video_context_driver_get_metrics(&metrics))
{
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI),
sizeof(entry));
snprintf(entry + _len, sizeof(entry) - _len, ": %.2f", val);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
}
/* Orientation */
if (video_display_server_can_set_screen_orientation())
{
enum msg_hash_enums name;
switch (video_display_server_get_screen_orientation())
{
case ORIENTATION_VERTICAL:
name = MENU_ENUM_LABEL_VALUE_VIDEO_ORIENTATION_VERTICAL;
break;
case ORIENTATION_FLIPPED:
name = MENU_ENUM_LABEL_VALUE_VIDEO_ORIENTATION_FLIPPED;
break;
case ORIENTATION_FLIPPED_ROTATED:
name = MENU_ENUM_LABEL_VALUE_VIDEO_ORIENTATION_FLIPPED_ROTATED;
break;
default:
name = MENU_ENUM_LABEL_VALUE_VIDEO_ORIENTATION_NORMAL;
break;
}
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_INFO_ORIENTATION),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len, msg_hash_to_str(name), sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
#ifdef HAVE_MODELINE
/* EDID submenu */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_INFORMATION),
MENU_ENUM_LABEL_DISPLAY_EDID_INFORMATION_STR,
MENU_ENUM_LABEL_DISPLAY_EDID_INFORMATION,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
return count;
}
#ifdef HAVE_MODELINE
/* One "Label: value" line */
static bool menu_displaylist_edid_line(file_list_t *list,
enum msg_hash_enums label, const char *value)
{
char entry[NAME_MAX_LENGTH];
size_t _len = strlcpy(entry, msg_hash_to_str(label), sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len, value, sizeof(entry) - _len);
return menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_EDID_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL);
}
/* One "Label n: value" line */
static bool menu_displaylist_edid_line_n(file_list_t *list,
enum msg_hash_enums label, unsigned n, const char *value)
{
char entry[NAME_MAX_LENGTH];
size_t _len = strlcpy(entry, msg_hash_to_str(label), sizeof(entry));
_len += snprintf(entry + _len, sizeof(entry) - _len, " %u: ", n);
strlcpy(entry + _len, value, sizeof(entry) - _len);
return menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_DISPLAY_EDID_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL);
}
/* Append ", item" or "item" to a comma list */
static size_t menu_displaylist_edid_cat(char *s, size_t _len, size_t len,
const char *item)
{
if (_len > 0)
_len += strlcpy_lit(s + _len, ", ", len - _len);
return _len + strlcpy(s + _len, item, len - _len);
}
/* System Information > Display Information > EDID: the block the
* display server read off the display in use, decoded field by field
* by the reader in gfx/modeline/modeline_edid.c, then the raw bytes. */
static unsigned menu_displaylist_parse_display_edid(file_list_t *list)
{
unsigned count = 0;
char value[512];
size_t _len;
int n, i;
uint8_t *raw;
video_edid_info_t *info;
raw = (uint8_t*)malloc(MODELINE_EDID_MAX_LEN + sizeof(video_edid_info_t));
if (!raw)
return 0;
info = (video_edid_info_t*)(raw + MODELINE_EDID_MAX_LEN);
n = video_display_server_get_edid(raw, MODELINE_EDID_MAX_LEN);
if (n < MODELINE_EDID_SIZE || !modeline_edid_parse(raw, (size_t)n, info))
{
/* Nothing to show, and two quite different reasons for it: the
* display server has no way to read one, or it has and the
* display in use carries none. Say what would. On Android the
* usual case is a phone or tablet panel, whose EDID the system
* keeps from apps; laptops and DDC do not come into it. */
#if defined(ANDROID)
enum msg_hash_enums why = MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_UNAVAILABLE_ANDROID;
#else
enum msg_hash_enums why = MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_UNAVAILABLE;
#endif
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_SOURCE,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE)))
count++;
if (menu_entries_append(list,
msg_hash_to_str(why), "",
MENU_ENUM_LABEL_DISPLAY_EDID_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
free(raw);
return count;
}
/* Read: "3 blocks, 384 bytes" */
snprintf(value, sizeof(value), "%u x %u = %u", info->n_blocks,
(unsigned)MODELINE_EDID_SIZE, (unsigned)info->len);
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_SOURCE, value))
count++;
if (info->truncated)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_TRUNCATED), "",
MENU_ENUM_LABEL_DISPLAY_EDID_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
/* Version */
snprintf(value, sizeof(value), "%u.%u", info->ver_major, info->ver_minor);
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_VERSION, value))
count++;
/* Identity */
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_MANUFACTURER,
info->manufacturer))
count++;
snprintf(value, sizeof(value), "0x%04X (%u)", info->product, info->product);
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_PRODUCT, value))
count++;
if (info->serial_text[0])
snprintf(value, sizeof(value), "%s (%lu)", info->serial_text,
(unsigned long)info->serial);
else
snprintf(value, sizeof(value), "%lu", (unsigned long)info->serial);
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_SERIAL, value))
count++;
if (info->year)
{
if (info->model_year)
snprintf(value, sizeof(value), "%u (model year)", info->year);
else if (info->week)
snprintf(value, sizeof(value), "%u, week %u", info->year, info->week);
else
snprintf(value, sizeof(value), "%u", info->year);
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_DATE, value))
count++;
}
if (info->name[0])
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_NAME,
info->name))
count++;
if (info->text[0])
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_TEXT,
info->text))
count++;
/* Video Input */
if (info->digital)
{
static const char *ifaces[] = {
"", "DVI", "HDMI-a", "HDMI-b", "MDDI", "DisplayPort"
};
_len = strlcpy_lit(value, "Digital", sizeof(value));
if (info->bit_depth)
_len += snprintf(value + _len, sizeof(value) - _len, ", %u bpc",
info->bit_depth);
if (info->interface > 0 && info->interface < 6)
_len += snprintf(value + _len, sizeof(value) - _len, ", %s",
ifaces[info->interface]);
if (info->dfp1x)
strlcpy_lit(value + _len, ", DFP 1.x", sizeof(value) - _len);
}
else
{
static const char *levels[] = {
"0.700/0.300 V", "0.714/0.286 V", "1.000/0.400 V", "0.700/0.000 V"
};
_len = snprintf(value, sizeof(value), "Analog, %s", levels[info->analog_level & 3]);
if (info->analog_sync & 0x10) _len += strlcpy_lit(value + _len, ", blank-to-black", sizeof(value) - _len);
if (info->analog_sync & 0x08) _len += strlcpy_lit(value + _len, ", separate sync", sizeof(value) - _len);
if (info->analog_sync & 0x04) _len += strlcpy_lit(value + _len, ", composite sync", sizeof(value) - _len);
if (info->analog_sync & 0x02) _len += strlcpy_lit(value + _len, ", sync on green", sizeof(value) - _len);
if (info->analog_sync & 0x01) strlcpy_lit(value + _len, ", serration", sizeof(value) - _len);
}
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_INPUT, value))
count++;
/* Screen Size */
if (info->width_cm && info->height_cm)
snprintf(value, sizeof(value), "%u x %u cm", info->width_cm, info->height_cm);
else if (info->width_cm || info->height_cm)
/* 1.4: one byte zero means the other is an aspect ratio code */
snprintf(value, sizeof(value), "%s %.2f:1", "aspect",
info->width_cm ? (info->width_cm + 99) / 100.0
: 100.0 / (info->height_cm + 99));
else
strlcpy(value, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE), sizeof(value));
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_SCREEN_SIZE, value))
count++;
/* Gamma */
if (info->gamma_x100)
{
snprintf(value, sizeof(value), "%.2f", info->gamma_x100 / 100.0);
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_GAMMA, value))
count++;
}
/* Features */
{
static const char *analog_types[] = {
"monochrome", "RGB color", "non-RGB color", "undefined"
};
static const char *digital_types[] = {
"RGB 4:4:4", "RGB 4:4:4 + YCrCb 4:4:4", "RGB 4:4:4 + YCrCb 4:2:2",
"RGB 4:4:4 + YCrCb 4:4:4 + 4:2:2"
};
unsigned f = info->features;
_len = 0;
value[0] = '\0';
if (f & 0x80) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "standby");
if (f & 0x40) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "suspend");
if (f & 0x20) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "active off");
_len = menu_displaylist_edid_cat(value, _len, sizeof(value),
info->digital ? digital_types[(f >> 3) & 3] : analog_types[(f >> 3) & 3]);
if (f & 0x04) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "sRGB");
if (f & 0x02) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "preferred timing");
if (f & 0x01) _len = menu_displaylist_edid_cat(value, _len, sizeof(value),
info->ver_minor >= 4 ? "continuous frequency" : "GTF");
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_FEATURES, value))
count++;
}
/* Chromaticity */
snprintf(value, sizeof(value),
"R %.3f %.3f, G %.3f %.3f, B %.3f %.3f, W %.3f %.3f",
info->red_x / 1000.0, info->red_y / 1000.0,
info->green_x / 1000.0, info->green_y / 1000.0,
info->blue_x / 1000.0, info->blue_y / 1000.0,
info->white_x / 1000.0, info->white_y / 1000.0);
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CHROMATICITY, value))
count++;
/* What those primaries amount to */
if (modeline_edid_gamut_str(info, value, sizeof(value)))
if (menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_GAMUT, value))
count++;
/* Range Limits */
if (info->has_range)
{
_len = snprintf(value, sizeof(value), "V %u-%u Hz, H %u-%u kHz",
info->vfreq_min, info->vfreq_max, info->hfreq_min, info->hfreq_max);
if (info->pclock_max)
_len += snprintf(value + _len, sizeof(value) - _len, ", max %u MHz",
info->pclock_max);
switch (info->range_type)
{
case 0x00: strlcpy_lit(value + _len, ", GTF", sizeof(value) - _len); break;
case 0x02: strlcpy_lit(value + _len, ", secondary GTF", sizeof(value) - _len); break;
case 0x04: strlcpy_lit(value + _len, ", CVT", sizeof(value) - _len); break;
default: break;
}
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_RANGE_LIMITS, value))
count++;
}
/* Established Timings, one line */
if (info->established)
{
_len = 0;
value[0] = '\0';
for (i = 0; i < 17; i++)
if (info->established & (1u << i))
_len = menu_displaylist_edid_cat(value, _len, sizeof(value),
modeline_edid_established_name((unsigned)i));
if (menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_ESTABLISHED_TIMINGS, value))
count++;
}
/* Standard Timings, one line */
if (info->n_std)
{
_len = 0;
value[0] = '\0';
for (i = 0; i < (int)info->n_std; i++)
{
char one[32];
snprintf(one, sizeof(one), "%ux%u @ %u Hz",
VIDEO_SCALE_W(info->std[i].dims),
VIDEO_SCALE_H(info->std[i].dims), info->std[i].refresh);
_len = menu_displaylist_edid_cat(value, _len, sizeof(value), one);
}
if (menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_STANDARD_TIMINGS, value))
count++;
}
/* Detailed Timings: summary and modeline, two lines each */
for (i = 0; i < (int)info->n_timings; i++)
{
const video_edid_timing_t *t = &info->timing[i];
_len = modeline_edid_timing_str(t, value, sizeof(value));
if (_len < sizeof(value) && t->hsize_mm && t->vsize_mm)
_len += snprintf(value + _len, sizeof(value) - _len, ", %u x %u mm",
t->hsize_mm, t->vsize_mm);
if (_len < sizeof(value) && t->preferred)
_len += snprintf(value + _len, sizeof(value) - _len, " (%s)",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_PREFERRED));
if (_len < sizeof(value) && t->src != MODELINE_EDID_SRC_BASE)
snprintf(value + _len, sizeof(value) - _len, " [%s]",
t->src == MODELINE_EDID_SRC_CTA ? "CTA-861" : "DisplayID");
if (menu_displaylist_edid_line_n(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_DETAILED_TIMING, (unsigned)i + 1, value))
count++;
modeline_edid_modeline_str(t, value, sizeof(value));
if (menu_entries_append(list, value, "",
MENU_ENUM_LABEL_DISPLAY_EDID_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
/* Checksum of the base block */
if (menu_displaylist_edid_line(list, MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CHECKSUM,
msg_hash_to_str(info->checksum_ok
? MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CHECKSUM_OK
: MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CHECKSUM_BAD)))
count++;
/* Extensions */
for (i = 0; i < (int)info->n_ext; i++)
{
const video_edid_ext_t *e = &info->ext[i];
int j;
if (e->tag == MODELINE_EDID_EXT_DISPLAYID)
snprintf(value, sizeof(value), "%s %u.%u, %s", modeline_edid_ext_name(e->tag),
e->revision >> 4, e->revision & 0x0f,
msg_hash_to_str(e->checksum_ok
? MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CHECKSUM_OK
: MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CHECKSUM_BAD));
else
snprintf(value, sizeof(value), "%s revision %u (0x%02X), %s",
modeline_edid_ext_name(e->tag), e->revision, e->tag,
msg_hash_to_str(e->checksum_ok
? MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CHECKSUM_OK
: MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CHECKSUM_BAD));
if (menu_displaylist_edid_line_n(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_EXTENSION, (unsigned)i + 1, value))
count++;
if (e->tag == MODELINE_EDID_EXT_CTA)
{
if (e->revision >= 2)
{
_len = 0;
value[0] = '\0';
if (e->underscan) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "underscan");
if (e->basic_audio) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "basic audio");
if (e->ycbcr444) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "YCbCr 4:4:4");
if (e->ycbcr422) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "YCbCr 4:2:2");
if (e->ycbcr420) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "YCbCr 4:2:0");
if (e->native_dtds)
{
char one[32];
snprintf(one, sizeof(one), "%u native", e->native_dtds);
_len = menu_displaylist_edid_cat(value, _len, sizeof(value), one);
}
if (_len && menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CTA_FLAGS, value))
count++;
}
if (e->n_vics)
{
_len = 0;
value[0] = '\0';
for (j = 0; j < (int)e->n_vics; j++)
{
char one[32];
size_t l = modeline_edid_vic_str(e->vic[j] & 0x7f, one, sizeof(one));
if ((e->vic[j] & 0x80) && (e->vic[j] & 0x7f) <= 64 && l < sizeof(one))
strlcpy_lit(one + l, "*", sizeof(one) - l);
_len = menu_displaylist_edid_cat(value, _len, sizeof(value), one);
if (_len >= sizeof(value) - 1)
break;
}
if (menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CTA_VIDEO, value))
count++;
}
if (e->n_audio)
{
snprintf(value, sizeof(value), "%u", e->n_audio);
if (menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CTA_AUDIO, value))
count++;
}
if (e->hdmi)
{
_len = snprintf(value, sizeof(value), "%u.%u.%u.%u",
e->hdmi_phys[0] >> 4, e->hdmi_phys[0] & 0x0f,
e->hdmi_phys[1] >> 4, e->hdmi_phys[1] & 0x0f);
if (e->hdmi_max_tmds)
_len += snprintf(value + _len, sizeof(value) - _len,
", max TMDS %u MHz", e->hdmi_max_tmds);
if (e->hdmi_forum)
snprintf(value + _len, sizeof(value) - _len,
", HDMI 2.x max TMDS %u MHz", e->hf_max_tmds);
if (menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CTA_HDMI, value))
count++;
}
if (e->hdr)
{
_len = 0;
value[0] = '\0';
if (e->hdr_eotf & 0x01) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "SDR");
if (e->hdr_eotf & 0x02) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "HDR");
if (e->hdr_eotf & 0x04) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "PQ");
if (e->hdr_eotf & 0x08) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "HLG");
if (e->hdr_max_lum)
{
/* CTA-861-G: 50 * 2^(code/32) cd/m2 */
char one[48];
snprintf(one, sizeof(one), "max %.0f cd/m2",
50.0 * pow(2.0, e->hdr_max_lum / 32.0));
_len = menu_displaylist_edid_cat(value, _len, sizeof(value), one);
}
if (e->hdr_max_fal)
{
char one[48];
snprintf(one, sizeof(one), "max frame average %.0f cd/m2",
50.0 * pow(2.0, e->hdr_max_fal / 32.0));
_len = menu_displaylist_edid_cat(value, _len, sizeof(value), one);
}
if (e->hdr_min_lum && e->hdr_max_lum)
{
char one[48];
double max_lum = 50.0 * pow(2.0, e->hdr_max_lum / 32.0);
snprintf(one, sizeof(one), "min %.4f cd/m2",
max_lum * pow(e->hdr_min_lum / 255.0, 2.0) / 100.0);
_len = menu_displaylist_edid_cat(value, _len, sizeof(value), one);
}
if (menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CTA_HDR, value))
count++;
}
if (e->colorimetry)
{
unsigned c = e->colorimetry_flags;
_len = 0;
value[0] = '\0';
if (c & 0x01) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "xvYCC601");
if (c & 0x02) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "xvYCC709");
if (c & 0x04) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "sYCC601");
if (c & 0x08) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "opYCC601");
if (c & 0x10) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "opRGB");
if (c & 0x20) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "BT.2020 cYCC");
if (c & 0x40) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "BT.2020 YCC");
if (c & 0x80) _len = menu_displaylist_edid_cat(value, _len, sizeof(value), "BT.2020 RGB");
if (_len && menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_CTA_COLORIMETRY, value))
count++;
}
}
else if (e->tag == MODELINE_EDID_EXT_DISPLAYID && e->n_sections)
{
_len = 0;
value[0] = '\0';
for (j = 0; j < (int)e->n_sections; j++)
_len = menu_displaylist_edid_cat(value, _len, sizeof(value),
modeline_edid_did_section_name(e->revision, e->section[j]));
if (menu_displaylist_edid_line(list,
MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_DID_SECTIONS, value))
count++;
}
}
/* Raw bytes, 16 per line, for pasting into edid-decode */
for (i = 0; i < n; i += 16)
{
int j;
_len = snprintf(value, sizeof(value), "%s %04X:",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_EDID_RAW), (unsigned)i);
for (j = 0; j < 16 && i + j < n; j++)
_len += snprintf(value + _len, sizeof(value) - _len, " %02X", raw[i + j]);
if (menu_entries_append(list, value, "",
MENU_ENUM_LABEL_DISPLAY_EDID_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
free(raw);
return count;
}
#endif
static void menu_displaylist_bt_addr(char *s, size_t len,
const uint8_t *addr)
{
snprintf(s, len, "%02X:%02X:%02X:%02X:%02X:%02X",
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
/* Each port with a device in it: its name, marked when no autoconfig
* profile matched it, and on RGUI the display and configuration names
* and VID/PID; for a controller that connects over Bluetooth to an
* address it keeps, that address, and a row to pair it with this
* computer. Every row carries its port in entry_idx. */
static unsigned menu_displaylist_parse_input_info(file_list_t *list)
{
char entry[NAME_MAX_LENGTH];
char host_str[18];
char host_name[64];
uint8_t host[6];
unsigned port;
unsigned count = 0;
unsigned keyboards = 0;
unsigned mice = 0;
const char *menu_driver = menu_driver_ident();
bool host_known = input_bluetooth_host_address(host,
host_name, sizeof(host_name));
if (host_known)
menu_displaylist_bt_addr(host_str, sizeof(host_str), host);
for (port = 0; port < MAX_USERS; port++)
{
const char *name = input_config_get_device_name(port);
size_t _len;
if (!name)
continue;
/* Port and Device Name */
_len = snprintf(entry, sizeof(entry), /* Note: format string below */
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT_DEVICE_NAME),
port + 1, name);
if (!input_config_get_device_autoconfigured(port) && _len < sizeof(entry))
snprintf(entry + _len, sizeof(entry) - _len, " (%s)",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT_DEVICE_NO_PROFILE));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
count++;
#ifdef HAVE_RGUI
if (!strcmp(menu_driver, "rgui"))
{
/* Device Display Name */
snprintf(entry, sizeof(entry), /* TODO/FIXME: localize */
"- Device Display Name: %s",
input_config_get_device_display_name(port)
? input_config_get_device_display_name(port)
: msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
count++;
/* Device Config Name */
snprintf(entry, sizeof(entry), /* TODO: localize */
"- Device Config Name: %s",
input_config_get_device_config_name(port)
? input_config_get_device_config_name(port)
: msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
count++;
/* Device VID/PID */
snprintf(entry, sizeof(entry), /* TODO: localize */
"- Device VID/PID: %d/%d",
input_config_get_device_vid(port),
input_config_get_device_pid(port));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
count++;
}
#endif
/* The Bluetooth address it connects to */
{
uint8_t pad_host[6];
if (input_driver_get_bt_host(port, pad_host))
{
char addr[18];
bool this_host = host_known && !memcmp(pad_host, host, 6);
menu_displaylist_bt_addr(addr, sizeof(addr), pad_host);
snprintf(entry, sizeof(entry), msg_hash_to_str(this_host
? MENU_ENUM_LABEL_VALUE_PORT_BT_HOST_THIS
: MENU_ENUM_LABEL_VALUE_PORT_BT_HOST), addr);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_CONTROLLER_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
count++;
if (host_known && !this_host && menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT_BT_PAIR), "",
MENU_ENUM_LABEL_INPUT_BT_PAIR,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
count++;
}
}
#ifdef HAVE_WINUSB_BIND
/* A DualShock 3: on Windows' own driver, which cannot start it,
* a row to move it to WinUSB; on WinUSB, read by the HID driver,
* one to give it back */
if (winusb_bind_is_ds3(input_config_get_device_vid(port),
input_config_get_device_pid(port)))
{
bool on_winusb = string_is_equal(
input_config_get_device_joypad_driver(port), "hid");
if (menu_entries_append(list, msg_hash_to_str(on_winusb
? MENU_ENUM_LABEL_VALUE_PORT_DS3_RESTORE
: MENU_ENUM_LABEL_VALUE_PORT_DS3_ENABLE), "",
on_winusb ? MENU_ENUM_LABEL_INPUT_DS3_RESTORE
: MENU_ENUM_LABEL_INPUT_DS3_ENABLE,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
count++;
}
#endif
}
/* This computer's Bluetooth */
if (host_known)
{
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BLUETOOTH_HOST_INFO),
host_name, host_str);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
/* The keyboards, where the input driver can tell them apart */
for (port = 0; port < MAX_INPUT_DEVICES; port++)
{
const char *name = input_config_get_keyboard_display_name(port);
if (!name)
continue;
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_KEYBOARD_DEVICE_NAME),
port + 1, name);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_KEYBOARD_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
{
count++;
keyboards++;
}
}
/* Where it cannot - most input drivers are handed keys by a window
* system that has merged every keyboard into one - there is still
* a keyboard, and a list with nothing in it says there is none. It
* is listed as what it is: all of them, through that driver. (The
* entry's index is past the last keyboard's; its sublabel goes by
* that.) */
if ( !keyboards
&& (input_driver_get_capabilities() & (1 << RETRO_DEVICE_KEYBOARD)))
{
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_KEYBOARD_SYSTEM_NAME),
input_driver_get_ident());
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_KEYBOARD_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, MAX_INPUT_DEVICES, NULL))
count++;
}
/* The mice. Each is numbered by its Mouse Index, the number a port
* is given it by. One mouse on the desk is often more than one of
* the input driver's mice: where the driver says which belong
* together they are one line, with all of their numbers. */
for (port = 0; port < MAX_INPUT_DEVICES; port++)
{
char numbers[64];
unsigned other;
size_t _len;
const char *name = input_config_get_mouse_display_name(port);
const char *device = input_config_get_mouse_device(port);
if (!name || input_config_get_mouse_hidden(port))
continue;
/* a part of a mouse that is listed already */
for (other = 0; other < port; other++)
if ( *device
&& input_config_get_mouse_display_name(other)
&& !input_config_get_mouse_hidden(other)
&& string_is_equal(device, input_config_get_mouse_device(other)))
break;
if (other < port)
continue;
_len = snprintf(numbers, sizeof(numbers), "%u", port + 1);
for (other = port + 1; other < MAX_INPUT_DEVICES; other++)
if ( *device
&& _len < sizeof(numbers)
&& input_config_get_mouse_display_name(other)
&& !input_config_get_mouse_hidden(other)
&& string_is_equal(device, input_config_get_mouse_device(other)))
_len += snprintf(numbers + _len, sizeof(numbers) - _len,
", %u", other + 1);
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MOUSE_DEVICE_NAME),
numbers, name);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_MOUSE_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, port, NULL))
{
count++;
mice++;
}
}
/* and the same for the mice */
if ( !mice
&& (input_driver_get_capabilities() & (1 << RETRO_DEVICE_MOUSE)))
{
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MOUSE_SYSTEM_NAME),
input_driver_get_ident());
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_MOUSE_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, MAX_INPUT_DEVICES, NULL))
count++;
}
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
/* The users' Network RetroPads: a controller, though no driver's */
for (port = 0; port < MAX_USERS; port++)
{
unsigned udp;
uint32_t a;
bool heard;
if (!input_remote_info(port, &udp, &a, &heard))
continue;
if (heard)
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_INFO_HEARD),
port + 1, udp, (unsigned)(a >> 24), (unsigned)((a >> 16) & 0xff),
(unsigned)((a >> 8) & 0xff), (unsigned)(a & 0xff));
else
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_INFO_WAITING),
port + 1, udp);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
#endif
return count;
}
static unsigned menu_displaylist_parse_system_info(file_list_t *list)
{
char entry[NAME_MAX_LENGTH];
unsigned count = 0;
/* RetroArch Version */
size_t _len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETROARCH_VERSION),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len, PACKAGE_VERSION, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
#ifdef HAVE_GIT_VERSION
/* Git Version */
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len, retroarch_git_version, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
#endif
#if defined(HAVE_VULKAN) && defined(__APPLE__)
/* MoltenVK Version */
{
const char *moltenvk_version = vulkan_get_moltenvk_version();
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_MOLTENVK_VERSION),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
if (!moltenvk_version || !*moltenvk_version)
strlcpy(entry + _len,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
sizeof(entry) - _len);
else
strlcpy(entry + _len, moltenvk_version, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
#endif
/* Build Date */
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
_len += strlcpy(entry + _len, __DATE__, sizeof(entry) - _len);
#ifdef DEBUG
_len += strlcpy_lit(entry + _len, " (DEBUG)", sizeof(entry) - _len);
#endif
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
/* Compiler */
retroarch_get_capabilities(RARCH_CAPABILITIES_COMPILER, entry, sizeof(entry));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
#ifdef ANDROID
/* Internal Storage Status */
{
bool perms = test_permissions(internal_storage_path);
strlcpy(entry,
perms
? msg_hash_to_str(MSG_READ_WRITE)
: msg_hash_to_str(MSG_READ_ONLY),
sizeof(entry));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
#endif
/* CPU Model */
{
/* TODO: this API is prone to leaking memory! */
const char *cpu_model = frontend_driver_get_cpu_model_name();
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_MODEL),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
if (!cpu_model || !*cpu_model)
strlcpy(entry + _len,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
sizeof(entry) - _len);
else
strlcpy(entry + _len, cpu_model, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
/* CPU Features */
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
retroarch_get_capabilities(RARCH_CAPABILITIES_CPU, entry + _len, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
/* CPU Architecture */
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_ARCHITECTURE),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
frontend_driver_get_cpu_architecture_str(entry + _len, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_CPU_ARCHITECTURE, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
/* CPU Cores */
{
/* Physical cores, with the thread count alongside where SMT
* doubles it - the raw thread count read as 32 cores on a
* 16-core part. */
unsigned threads = cpu_features_get_core_amount();
unsigned cores = cpu_features_get_core_amount_physical();
size_t _len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_CORES),
sizeof(entry));
if (threads > cores)
snprintf(entry + _len, sizeof(entry) - _len,
": %u (%u %s)", cores, threads,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_THREADS));
else
snprintf(entry + _len, sizeof(entry) - _len,
": %u", cores);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_CPU_CORES, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
#if TARGET_OS_IPHONE
{
const char *val_yes_str = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_YES);
const char *val_no_str = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO);
size_t _len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_JIT_AVAILABLE),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
if (jit_available())
strlcpy(entry + _len, val_yes_str, sizeof(entry) - _len);
else
strlcpy(entry + _len, val_no_str, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
#endif
#ifdef __APPLE__
{
CFBundleRef mainBundle = CFBundleGetMainBundle();
if (mainBundle)
{
CFStringRef bundleIdentifier = CFBundleGetIdentifier(mainBundle);
if (bundleIdentifier)
{
size_t _len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BUNDLE_IDENTIFIER),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
Boolean result = CFStringGetCString(bundleIdentifier, entry + _len, sizeof(entry) - _len, kCFStringEncodingUTF8);
if (result) {
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
}
}
}
#endif
{
const frontend_ctx_driver_t *frontend = frontend_get_ptr();
if (frontend)
{
/* Frontend Identifier */
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len, frontend->ident, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
/* Lakka Version */
if (frontend->get_lakka_version)
{
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LAKKA_VERSION),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
frontend->get_lakka_version(entry + _len, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
/* Frontend name */
if (frontend->get_name)
{
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
frontend->get_name(entry + _len, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
/* Frontend OS */
if (frontend->get_os)
{
int major = 0;
int minor = 0;
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
_len += frontend->get_os(entry + _len,
sizeof(entry) - _len, &major, &minor);
snprintf(entry + _len,
sizeof(entry) - _len,
" (v%d.%d)", major, minor);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
/* Memory */
{
uint64_t memory_total = mem_stats_total();
uint64_t memory_used = memory_total - mem_stats_free();
if (memory_used != 0 && memory_total != 0)
{
_len = strlcpy(entry,
msg_hash_to_str(MSG_MEMORY), sizeof(entry));
snprintf(entry + _len, sizeof(entry) - _len, ": %" PRIu64 "/%" PRIu64 " MB",
BYTES_TO_MB(memory_used), BYTES_TO_MB(memory_total));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
}
/* Power Source */
if (frontend->get_powerstate)
{
int seconds = 0;
int percent = 0;
enum frontend_powerstate state =
frontend->get_powerstate(&seconds, &percent);
/* Power Source */
size_t _len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
/* N/A */
if (state == FRONTEND_POWERSTATE_NONE)
strlcpy(entry + _len,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
sizeof(entry) - _len);
/* n% (No Source) */
else if (state == FRONTEND_POWERSTATE_NO_SOURCE)
snprintf(entry + _len, sizeof(entry) - _len, "%d%% (%s)", percent,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE));
/* n% (Charging) */
else if (state == FRONTEND_POWERSTATE_CHARGING)
snprintf(entry + _len, sizeof(entry) - _len, "%d%% (%s)", percent,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING));
/* n% (Charged) */
else if (state == FRONTEND_POWERSTATE_CHARGED)
snprintf(entry + _len, sizeof(entry) - _len, "%d%% (%s)", percent,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED));
/* n% (Discharging) */
else if (state == FRONTEND_POWERSTATE_ON_POWER_SOURCE)
snprintf(entry + _len, sizeof(entry) - _len, "%d%% (%s)", percent,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING));
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
}
}
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGL1) || \
defined(HAVE_OPENGLES) || defined(HAVE_OPENGL_CORE)
{
gfx_ctx_ident_t ident_info;
video_context_driver_get_ident(&ident_info);
/* Video Context Driver */
_len = strlcpy(entry,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER),
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
strlcpy(entry + _len,
(ident_info.ident && *ident_info.ident)
? ident_info.ident
: msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
#endif
/* Supports %s: yes/no */
{
static const struct menu_features_info
{
bool enabled;
const char *msg;
} info_list[] = {
#ifdef HAVE_DYLIB
{SUPPORTS_DYLIB, "Dynamic Library"},
#endif
{SUPPORTS_DYNAMIC, "Dynamic run-time loading of libretro library"},
#ifdef HAVE_LIBRETRODB
{SUPPORTS_LIBRETRODB, "LibretroDB"},
#endif
#ifdef HAVE_THREADS
{SUPPORTS_THREAD, "Threading"},
#endif
#ifdef HAVE_OVERLAY
{SUPPORTS_OVERLAY, "Overlay"},
#endif
#ifdef HAVE_COMMAND
{SUPPORTS_COMMAND, "Command interface"},
#endif
#ifdef HAVE_NETWORK_CMD
{SUPPORTS_NETWORK_COMMAND, "Network Command interface"},
#endif
#ifdef HAVE_NETWORKGAMEPAD
{SUPPORTS_NETWORK_GAMEPAD, "Network Gamepad"},
#endif
#ifdef HAVE_NETWORKING
{SUPPORTS_NETPLAY, "Netplay (Peer-to-Peer)"},
#endif
#ifdef HAVE_SSL
{SUPPORTS_SSL , "SSL"},
#endif
#ifdef HAVE_CG
{SUPPORTS_CG, "Cg"},
#endif
#ifdef HAVE_GLSL
{SUPPORTS_GLSL, "GLSL"},
#endif
#ifdef HAVE_HLSL
{SUPPORTS_HLSL, "HLSL"},
#endif
#ifdef HAVE_SLANG
{SUPPORTS_SLANG, "Slang"},
#endif
#ifdef HAVE_RPNG
{SUPPORTS_RPNG, "PNG (RPNG)"},
#endif
#ifdef HAVE_RJPEG
{SUPPORTS_RJPEG, "JPEG (RJPEG)"},
#endif
#ifdef HAVE_RBMP
{SUPPORTS_RBMP, "BMP (RBMP)"},
#endif
#ifdef HAVE_RTGA
{SUPPORTS_RTGA, "TGA (RTGA)"},
#endif
#ifdef HAVE_RWEBP
{SUPPORTS_RWEBP, "WebP (RWEBP)"},
#endif
#ifdef HAVE_RWEBM
{SUPPORTS_RWEBM, "WebM (RWEBM)"},
#endif
#ifdef HAVE_RVP9
{SUPPORTS_RVP9, "VP9 (RVP9)"},
#endif
#ifdef HAVE_RDDS
{SUPPORTS_RDDS, "DDS (RDDS)"},
#endif
#ifdef HAVE_SDL
{SUPPORTS_SDL, "SDL 1.2"},
#endif
#ifdef HAVE_SDL2
{SUPPORTS_SDL2, "SDL 2"},
#endif
#ifdef HAVE_SDL3
{SUPPORTS_SDL3, "SDL 3"},
#endif
#ifdef HAVE_X11
{SUPPORTS_X11, "X11"},
#endif
#ifdef HAVE_UDEV
{SUPPORTS_UDEV, "udev"},
#endif
#ifdef HAVE_WAYLAND
{SUPPORTS_WAYLAND, "Wayland"},
#endif
#ifdef HAVE_GDI
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
{SUPPORTS_GDI, "GDI"},
#endif
#endif
#ifdef HAVE_D3D8
{SUPPORTS_D3D8, "Direct3D 8"},
#endif
#ifdef HAVE_D3D9
{SUPPORTS_D3D9, "Direct3D 9"},
#endif
#ifdef HAVE_D3D10
{SUPPORTS_D3D10, "Direct3D 10"},
#endif
#ifdef HAVE_D3D11
{SUPPORTS_D3D11, "Direct3D 11"},
#endif
#ifdef HAVE_D3D12
{SUPPORTS_D3D12, "Direct3D 12"},
#endif
#ifdef HAVE_VULKAN
{SUPPORTS_VULKAN, "Vulkan"},
#endif
#ifdef HAVE_METAL
{SUPPORTS_METAL, "Metal"},
#endif
{SUPPORTS_OPENGL, "OpenGL"},
{SUPPORTS_OPENGLES, "OpenGL ES"},
#ifdef HAVE_OPENXR
{SUPPORTS_OPENXR, "OpenXR"},
#endif
#ifdef HAVE_XVIDEO
{SUPPORTS_XVIDEO, "XVideo"},
#endif
#ifdef HAVE_EGL
{SUPPORTS_EGL, "EGL"},
#endif
#ifdef HAVE_KMS
{SUPPORTS_KMS, "KMS"},
#endif
#ifdef HAVE_VG
{SUPPORTS_VG, "OpenVG"},
#endif
#ifdef HAVE_ALSA
{SUPPORTS_ALSA, "ALSA"},
#endif
#ifdef HAVE_COREAUDIO
{SUPPORTS_COREAUDIO, "CoreAudio"},
#endif
#ifdef HAVE_JACK
{SUPPORTS_JACK, "JACK"},
#endif
#ifdef HAVE_AL
{SUPPORTS_AL, "OpenAL"},
#endif
#ifdef HAVE_SL
{SUPPORTS_SL, "OpenSL"},
#endif
#ifdef HAVE_OSS
{SUPPORTS_OSS, "OSS"},
#endif
#ifdef HAVE_PIPEWIRE
{SUPPORTS_PIPEWIRE, "PipeWire"},
#endif
#ifdef HAVE_PULSE
{SUPPORTS_PULSE, "PulseAudio"},
#endif
#ifdef HAVE_ROAR
{SUPPORTS_ROAR, "RoarAudio"},
#endif
#ifdef HAVE_RSOUND
{SUPPORTS_RSOUND, "RSound"},
#endif
#ifdef HAVE_DSOUND
{SUPPORTS_DSOUND, "DirectSound"},
#endif
#ifdef HAVE_WASAPI
{SUPPORTS_WASAPI, "WASAPI"},
#endif
#ifdef HAVE_XAUDIO
{SUPPORTS_XAUDIO, "XAudio2"},
#endif
#ifdef HAVE_ZLIB
{SUPPORTS_ZLIB, "zlib"},
#endif
#ifdef HAVE_7ZIP
{SUPPORTS_7ZIP, "7zip"},
#endif
#ifdef HAVE_RZSTD
{SUPPORTS_ZSTD, "Zstandard"},
#endif
#ifdef HAVE_RRAR
{SUPPORTS_RAR, "RAR"},
#endif
#ifdef HAVE_FFMPEG
{SUPPORTS_FFMPEG, "FFmpeg"},
#endif
#ifdef HAVE_MPV
{SUPPORTS_MPV, "mpv"},
#endif
#ifdef HAVE_SDL_IMAGE
{SUPPORTS_SDL_IMAGE, "SDL Image"},
#endif
#ifdef HAVE_CORETEXT
{SUPPORTS_CORETEXT, "CoreText"},
#endif
#ifdef HAVE_FREETYPE
{SUPPORTS_FREETYPE, "FreeType"},
#endif
{SUPPORTS_STBFONT, "STB TrueType"},
#ifdef HAVE_V4L2
{SUPPORTS_V4L2, "Video4Linux2"},
#endif
#ifdef HAVE_LIBUSB
{SUPPORTS_LIBUSB, "libusb"},
#endif
#ifdef HAVE_COCOA
{SUPPORTS_COCOA, "Cocoa UI companion"},
#endif
#ifdef HAVE_QT
{SUPPORTS_QT, "Qt UI companion"},
#endif
#ifdef HAVE_QT6
{SUPPORTS_QT, "Qt6 UI companion"},
#endif
};
unsigned info_idx;
const char *val_yes_str = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_YES);
const char *val_no_str = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO);
for (info_idx = 0; info_idx < ARRAY_SIZE(info_list); info_idx++)
{
size_t _len = strlcpy(entry,
info_list[info_idx].msg,
sizeof(entry));
_len += strlcpy_lit(entry + _len, ": ", sizeof(entry) - _len);
_len += strlcpy(entry + _len,
(info_list[info_idx].enabled) ? val_yes_str : val_no_str, sizeof(entry) - _len);
if (menu_entries_append(list, entry, "",
MENU_ENUM_LABEL_SYSTEM_INFO_ENTRY, MENU_SETTINGS_CORE_INFO_NONE,
0, 0, NULL))
count++;
}
}
return count;
}
static int menu_displaylist_parse_playlist(
file_list_t *info_list,
const char *info_path, playlist_t *playlist,
settings_t *settings,
const char *path_playlist,
size_t path_playlist_size,
bool is_collection)
{
unsigned i;
char label_spacer[PL_LABEL_SPACER_MAXLEN];
size_t list_size = playlist_size(playlist);
bool show_inline_core_name = false;
struct menu_state *menu_st = menu_state_get_ptr();
const char *menu_driver = menu_driver_ident();
menu_search_terms_t *search_terms = menu_entries_search_get_terms();
unsigned pl_show_inline_core_name = settings->uints.playlist_show_inline_core_name;
bool pl_show_sublabels = settings->bools.playlist_show_sublabels;
void (*sanitization)(char*) = NULL;
unsigned count = 0;
if (list_size == 0)
return 0;
/* Check whether core name should be added to playlist entries */
if ( strcmp(menu_driver, "ozone")
&& !pl_show_sublabels
&& ((pl_show_inline_core_name == PLAYLIST_INLINE_CORE_DISPLAY_ALWAYS)
|| (!is_collection
&& !(pl_show_inline_core_name == PLAYLIST_INLINE_CORE_DISPLAY_NEVER))))
{
show_inline_core_name = true;
#ifdef HAVE_RGUI
/* Get spacer for menu entry labels (<content><spacer><core>)
* > Note: Only required when showing inline core names */
if (!strcmp(menu_driver, "rgui"))
strlcpy(label_spacer, PL_LABEL_SPACER_RGUI, sizeof(label_spacer));
else
#endif
strlcpy(label_spacer, PL_LABEL_SPACER_DEFAULT, sizeof(label_spacer));
}
{
/* Inform menu driver of current system name
* > Note: history, favorites and images_history
* require special treatment here, since info_path
* is nonsensical in these cases (and we *do* need
* to call set_thumbnail_system() in these cases,
* since all three playlist types have thumbnail
* support)
* EDIT: For correct operation of the quick menu
* 'download thumbnails' option, we must also extend
* this to music_history and video_history */
if (
!strcmp(path_playlist, "history")
|| !strcmp(path_playlist, "favorites")
|| string_ends_with_size(path_playlist, "_history",
path_playlist_size, STRLEN_CONST("_history")))
gfx_thumbnail_set_system(menu_st->thumbnail_path_data,
path_playlist, playlist_get_cached());
else if (info_path && *info_path)
{
char lpl_basename[NAME_MAX_LENGTH];
fill_pathname(lpl_basename, path_basename(info_path), "",
sizeof(lpl_basename));
gfx_thumbnail_set_system(menu_st->thumbnail_path_data,
lpl_basename, playlist_get_cached());
}
}
/* Preallocate the file list */
file_list_reserve(info_list, list_size);
switch (playlist_get_label_display_mode(playlist))
{
case LABEL_DISPLAY_MODE_REMOVE_PARENTHESES :
sanitization = &label_remove_parens;
break;
case LABEL_DISPLAY_MODE_REMOVE_BRACKETS :
sanitization = &label_remove_brackets;
break;
case LABEL_DISPLAY_MODE_REMOVE_PARENTHESES_AND_BRACKETS :
sanitization = &label_remove_parens_and_brackets;
break;
case LABEL_DISPLAY_MODE_KEEP_DISC_INDEX :
sanitization = &label_keep_disc;
break;
case LABEL_DISPLAY_MODE_KEEP_REGION :
sanitization = &label_keep_region;
break;
case LABEL_DISPLAY_MODE_KEEP_REGION_AND_DISC_INDEX :
sanitization = &label_keep_region_and_disc;
break;
default :
break;
}
for (i = 0; i < list_size; i++)
{
char menu_entry_lbl[NAME_MAX_LENGTH];
const struct playlist_entry *entry = NULL;
const char *entry_path = NULL;
bool entry_valid = true;
/* Read playlist entry */
playlist_get_index(playlist, i, &entry);
if (entry->path && *entry->path)
{
size_t _len;
/* Standard playlist entry
* > Base menu entry label is always playlist label
* > If playlist label is NULL, fallback to playlist entry file name
* > If required, add currently associated core (if any), otherwise
* no further action is necessary */
if (!entry->label || !*entry->label)
_len = fill_pathname(menu_entry_lbl,
path_basename(entry->path), "",
sizeof(menu_entry_lbl));
else
_len = strlcpy(menu_entry_lbl,
entry->label,
sizeof(menu_entry_lbl));
if (sanitization)
(*sanitization)(menu_entry_lbl);
if (show_inline_core_name)
{
/* Both core name and core path must be valid */
if ( entry->core_name
&& strcmp(entry->core_name, FILE_PATH_DETECT)
&& entry->core_path
&& strcmp(entry->core_path, FILE_PATH_DETECT))
{
_len += strlcpy(
menu_entry_lbl + _len,
label_spacer,
sizeof(menu_entry_lbl) - _len);
strlcpy(menu_entry_lbl + _len,
entry->core_name,
sizeof(menu_entry_lbl) - _len);
}
}
entry_path = entry->path;
}
else
{
/* Playlist entry without content...
* This is useless/broken, but have to include
* it otherwise synchronisation between the menu
* and the underlying playlist will be lost...
* > Use label if available, otherwise core name
* > If both are missing, add an empty menu entry */
if (entry->label && *entry->label)
strlcpy(menu_entry_lbl, entry->label, sizeof(menu_entry_lbl));
else if (entry->core_name && *entry->core_name)
strlcpy(menu_entry_lbl, entry->core_name, sizeof(menu_entry_lbl));
entry_path = path_playlist;
}
/* Check whether entry matches search terms,
* if required */
if (search_terms)
{
size_t j;
for (j = 0; j < search_terms->size; j++)
{
const char *search_term = search_terms->terms[j];
if ( (search_term && *search_term)
&& !compat_strcasestr(menu_entry_lbl, search_term))
{
entry_valid = false;
break;
}
}
}
/* Add menu entry */
if (entry_valid && menu_entries_append(info_list,
menu_entry_lbl, entry_path,
MENU_ENUM_LABEL_PLAYLIST_ENTRY, FILE_TYPE_RPL_ENTRY, 0, i, NULL))
count++;
}
return count;
}
#ifdef HAVE_LIBRETRODB
static int create_string_list_rdb_entry_string(
enum msg_hash_enums enum_idx,
const char *desc,
const char *label,
const char *actual_string,
const char *path,
file_list_t *list)
{
char tmp[128];
char out_lbl[NAME_MAX_LENGTH];
size_t _len = 0;
strlcpy_append(out_lbl, sizeof(out_lbl), &_len, label);
strlcpy_append(out_lbl, sizeof(out_lbl), &_len, "|");
strlcpy_append(out_lbl, sizeof(out_lbl), &_len, actual_string);
strlcpy_append(out_lbl, sizeof(out_lbl), &_len, "|");
strlcpy_append(out_lbl, sizeof(out_lbl), &_len, path);
_len = 0;
strlcpy_append(tmp, sizeof(tmp), &_len, desc);
strlcpy_append(tmp, sizeof(tmp), &_len, ": ");
strlcpy_append(tmp, sizeof(tmp), &_len, actual_string);
menu_entries_append(list, tmp, out_lbl,
enum_idx,
0, 0, 0, NULL);
return 0;
}
static int create_string_list_rdb_entry_int(
enum msg_hash_enums enum_idx,
const char *desc, const char *label,
int actual_int, const char *path, file_list_t *list)
{
size_t _len;
char tmp[128];
char out_lbl[NAME_MAX_LENGTH*2];
_len = strlcpy(out_lbl, label, sizeof(out_lbl));
out_lbl[_len++] = '|';
_len += snprintf(out_lbl + _len, sizeof(out_lbl) - _len, "%d", actual_int);
out_lbl[_len++] = '|';
strlcpy(out_lbl + _len, path, sizeof(out_lbl) - _len);
_len = strlcpy(tmp, desc, sizeof(tmp));
tmp[_len++] = ':';
tmp[_len++] = ' ';
_len += snprintf(tmp + _len, sizeof(tmp) - _len, "%d", actual_int);
menu_entries_append(list, tmp, out_lbl,
enum_idx,
0, 0, 0, NULL);
return 0;
}
/* Translatable name for a 1-based release month, or MSG_UNKNOWN when
* the database holds something outside 1-12 (the caller then shows
* the raw number, as before). */
static enum msg_hash_enums month_uint_to_menu_label_value(unsigned month)
{
static const enum msg_hash_enums months[12] = {
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_JANUARY,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_FEBRUARY,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_MARCH,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_APRIL,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_MAY,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_JUNE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_JULY,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_AUGUST,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_SEPTEMBER,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_OCTOBER,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_NOVEMBER,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH_DECEMBER
};
if (month < 1 || month > 12)
return MSG_UNKNOWN;
return months[month - 1];
}
static int menu_displaylist_parse_database_entry(menu_handle_t *menu,
menu_displaylist_info_t *info,
bool show_advanced_settings,
bool playlist_use_old_format,
bool playlist_compression,
bool playlist_fuzzy_archive_match,
bool playlist_portable_paths,
const char *dir_playlist,
const char *directory_menu_content
)
{
size_t _len;
unsigned i, j, k;
char query[256];
char path_base[NAME_MAX_LENGTH];
playlist_config_t playlist_config;
playlist_t *playlist = NULL;
bool playlist_is_cached = false;
database_info_list_t *db_info = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
playlist_config.capacity = COLLECTION_SIZE;
playlist_config.old_format = playlist_use_old_format;
playlist_config.compress = playlist_compression;
playlist_config.fuzzy_archive_match = playlist_fuzzy_archive_match;
playlist_config_set_base_content_directory(&playlist_config,
playlist_portable_paths
? directory_menu_content
: NULL);
database_info_build_query_enum(query, sizeof(query),
DATABASE_QUERY_ENTRY, info->path_b);
/* The scan walks the entire .rdb; it runs on the task queue and
* the result arrives via the one-slot cache. While pending, show
* a placeholder - the task callback refreshes this list. */
if (!(db_info = menu_dbinfo_cache_get(info->path, query)))
{
/* A cached NULL means the scan already ran and failed -
* behave like the old synchronous failure path instead of
* re-pushing the scan on every rebuild. */
if (menu_dbinfo_cache_has(info->path, query))
return -1;
if (!menu_dbinfo_load_in_progress(NULL))
task_push_dbinfo_load(info->path, query);
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_EXPLORE_INITIALISING_LIST),
MENU_ENUM_LABEL_EXPLORE_INITIALISING_LIST_STR,
MENU_ENUM_LABEL_EXPLORE_INITIALISING_LIST,
FILE_TYPE_NONE, 0, 0, NULL);
return 0;
}
_len = fill_pathname(path_base, path_basename(info->path), "",
sizeof(path_base));
gfx_thumbnail_set_system(menu_st->thumbnail_path_data,
path_base, playlist_get_cached());
strlcpy_lit(path_base + _len, ".lpl", sizeof(path_base) - _len);
fill_pathname_join_special(menu->db_playlist_file,
dir_playlist, path_base,
sizeof(menu->db_playlist_file));
playlist_config_set_path(&playlist_config, menu->db_playlist_file);
/* Read-only CRC matching against the database playlist: reuse
* the menu's cached playlist when it is the same file - the
* common case, since this list is reached from that playlist -
* and only parse from disk otherwise. */
{
playlist_t *cached = playlist_get_cached();
if ( cached
&& string_is_equal(playlist_get_conf_path(cached),
menu->db_playlist_file))
{
playlist = cached;
playlist_is_cached = true;
}
else
playlist = playlist_init(&playlist_config);
}
for (i = 0; i < db_info->count; i++)
{
char tmp[NAME_MAX_LENGTH];
char crc_str[20];
database_info_t *db_info_entry = &db_info->list[i];
size_t tmp_len;
snprintf(crc_str, sizeof(crc_str), "%08lX", (unsigned long)db_info_entry->crc32);
if (playlist)
{
size_t pl_size = playlist_size(playlist);
for (j = 0; j < pl_size; j++)
{
const struct playlist_entry *entry = NULL;
bool match_found = false;
playlist_get_index(playlist, j, &entry);
if (entry->crc32)
{
char entry_crc32_buf[256];
size_t crc_len = strlcpy(entry_crc32_buf,
entry->crc32, sizeof(entry_crc32_buf));
if (crc_len < sizeof(entry_crc32_buf))
{
const char *elem0 = entry_crc32_buf;
char *hash_type = NULL;
char *delim = strchr(entry_crc32_buf, '|');
if (delim)
{
*delim = '\0';
hash_type = delim + 1;
delim = strchr(hash_type, '|');
if (delim)
*delim = '\0';
}
if (hash_type)
{
switch (msg_hash_to_file_type(hash_type))
{
case FILE_TYPE_CRC:
match_found = string_is_equal(crc_str, elem0);
break;
case FILE_TYPE_SHA1:
match_found = string_is_equal(
db_info_entry->sha1, elem0);
break;
case FILE_TYPE_MD5:
match_found = string_is_equal(
db_info_entry->md5, elem0);
break;
default:
break;
}
}
}
}
if (!match_found)
continue;
menu->scratchpad.unsigned_var = j;
break;
}
}
if (db_info_entry->name)
{
tmp_len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME),
sizeof(tmp));
tmp_len += strlcpy_lit(tmp + tmp_len, ": ", sizeof(tmp) - tmp_len);
strlcpy(tmp + tmp_len, db_info_entry->name, sizeof(tmp) - tmp_len);
menu_entries_append(info->list, tmp,
MENU_ENUM_LABEL_RDB_ENTRY_NAME_STR,
MENU_ENUM_LABEL_RDB_ENTRY_NAME,
0, 0, 0, NULL);
}
if (db_info_entry->description)
{
tmp_len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION),
sizeof(tmp));
tmp_len += strlcpy_lit(tmp + tmp_len, ": ", sizeof(tmp) - tmp_len);
strlcpy(tmp + tmp_len, db_info_entry->description,
sizeof(tmp) - tmp_len);
menu_entries_append(info->list, tmp,
MENU_ENUM_LABEL_RDB_ENTRY_DESCRIPTION_STR,
MENU_ENUM_LABEL_RDB_ENTRY_DESCRIPTION,
0, 0, 0, NULL);
}
#define RDB_ENTRY_STR(field, enum_label, enum_val_label) \
if (db_info_entry->field) \
{ \
if (create_string_list_rdb_entry_string( \
enum_label, \
msg_hash_to_str(enum_val_label), \
msg_hash_to_str(enum_label), \
db_info_entry->field, info->path, info->list) == -1) \
goto error; \
}
#define RDB_ENTRY_INT(field, enum_label, enum_val_label) \
if (db_info_entry->field) \
{ \
if (create_string_list_rdb_entry_int( \
enum_label, \
msg_hash_to_str(enum_val_label), \
msg_hash_to_str(enum_label), \
db_info_entry->field, info->path, info->list) == -1) \
goto error; \
}
#define RDB_ENTRY_BOOL(field, enum_label, enum_val_label) \
if (db_info_entry->field == 1) \
{ \
if (create_string_list_rdb_entry_string( \
enum_label, \
msg_hash_to_str(enum_val_label), \
msg_hash_to_str(enum_label), \
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TRUE), \
info->path, info->list) == -1) \
goto error; \
}
RDB_ENTRY_STR(genre, MENU_ENUM_LABEL_RDB_ENTRY_GENRE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GENRE)
RDB_ENTRY_STR(publisher, MENU_ENUM_LABEL_RDB_ENTRY_PUBLISHER,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER)
RDB_ENTRY_STR(category, MENU_ENUM_LABEL_RDB_ENTRY_CATEGORY,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CATEGORY)
RDB_ENTRY_STR(language, MENU_ENUM_LABEL_RDB_ENTRY_LANGUAGE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_LANGUAGE)
RDB_ENTRY_STR(region, MENU_ENUM_LABEL_RDB_ENTRY_REGION,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_REGION)
RDB_ENTRY_STR(score, MENU_ENUM_LABEL_RDB_ENTRY_SCORE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SCORE)
RDB_ENTRY_STR(media, MENU_ENUM_LABEL_RDB_ENTRY_MEDIA,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MEDIA)
RDB_ENTRY_STR(controls, MENU_ENUM_LABEL_RDB_ENTRY_CONTROLS,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CONTROLS)
RDB_ENTRY_STR(artstyle, MENU_ENUM_LABEL_RDB_ENTRY_ARTSTYLE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ARTSTYLE)
RDB_ENTRY_STR(gameplay, MENU_ENUM_LABEL_RDB_ENTRY_GAMEPLAY,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_GAMEPLAY)
RDB_ENTRY_STR(narrative, MENU_ENUM_LABEL_RDB_ENTRY_NARRATIVE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NARRATIVE)
RDB_ENTRY_STR(pacing, MENU_ENUM_LABEL_RDB_ENTRY_PACING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PACING)
RDB_ENTRY_STR(perspective, MENU_ENUM_LABEL_RDB_ENTRY_PERSPECTIVE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PERSPECTIVE)
RDB_ENTRY_STR(setting, MENU_ENUM_LABEL_RDB_ENTRY_SETTING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SETTING)
RDB_ENTRY_STR(visual, MENU_ENUM_LABEL_RDB_ENTRY_VISUAL,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_VISUAL)
RDB_ENTRY_STR(vehicular, MENU_ENUM_LABEL_RDB_ENTRY_VEHICULAR,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_VEHICULAR)
if (db_info_entry->developer)
{
const char *val_rdb_entry_dev =
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER);
const char *rdb_entry_dev =
MENU_ENUM_LABEL_RDB_ENTRY_DEVELOPER_STR;
for (k = 0; k < db_info_entry->developer->size; k++)
{
if (db_info_entry->developer->elems[k].data)
{
if (create_string_list_rdb_entry_string(
MENU_ENUM_LABEL_RDB_ENTRY_DEVELOPER,
val_rdb_entry_dev, rdb_entry_dev,
db_info_entry->developer->elems[k].data,
info->path, info->list) == -1)
goto error;
}
}
}
RDB_ENTRY_STR(origin, MENU_ENUM_LABEL_RDB_ENTRY_ORIGIN,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN)
RDB_ENTRY_STR(franchise, MENU_ENUM_LABEL_RDB_ENTRY_FRANCHISE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE)
RDB_ENTRY_INT(max_users, MENU_ENUM_LABEL_RDB_ENTRY_MAX_USERS,
MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS)
RDB_ENTRY_INT(tgdb_rating, MENU_ENUM_LABEL_RDB_ENTRY_TGDB_RATING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_TGDB_RATING)
RDB_ENTRY_INT(famitsu_magazine_rating,
MENU_ENUM_LABEL_RDB_ENTRY_FAMITSU_MAGAZINE_RATING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FAMITSU_MAGAZINE_RATING)
RDB_ENTRY_STR(edge_magazine_review, MENU_ENUM_LABEL_RDB_ENTRY_EDGE_MAGAZINE_REVIEW,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_REVIEW)
RDB_ENTRY_INT(edge_magazine_rating, MENU_ENUM_LABEL_RDB_ENTRY_EDGE_MAGAZINE_RATING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_RATING)
RDB_ENTRY_INT(edge_magazine_issue, MENU_ENUM_LABEL_RDB_ENTRY_EDGE_MAGAZINE_ISSUE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_EDGE_MAGAZINE_ISSUE)
if (db_info_entry->releasemonth)
{
enum msg_hash_enums month_enum =
month_uint_to_menu_label_value(db_info_entry->releasemonth);
if (month_enum == MSG_UNKNOWN)
{
RDB_ENTRY_INT(releasemonth, MENU_ENUM_LABEL_RDB_ENTRY_RELEASE_MONTH,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH)
}
else if (create_string_list_rdb_entry_string(
MENU_ENUM_LABEL_RDB_ENTRY_RELEASE_MONTH,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH),
msg_hash_to_str(MENU_ENUM_LABEL_RDB_ENTRY_RELEASE_MONTH),
msg_hash_to_str(month_enum), info->path, info->list) == -1)
goto error;
}
RDB_ENTRY_INT(releaseyear, MENU_ENUM_LABEL_RDB_ENTRY_RELEASE_YEAR,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR)
RDB_ENTRY_STR(bbfc_rating, MENU_ENUM_LABEL_RDB_ENTRY_BBFC_RATING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_BBFC_RATING)
RDB_ENTRY_STR(esrb_rating, MENU_ENUM_LABEL_RDB_ENTRY_ESRB_RATING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ESRB_RATING)
RDB_ENTRY_STR(elspa_rating, MENU_ENUM_LABEL_RDB_ENTRY_ELSPA_RATING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ELSPA_RATING)
RDB_ENTRY_STR(pegi_rating, MENU_ENUM_LABEL_RDB_ENTRY_PEGI_RATING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PEGI_RATING)
RDB_ENTRY_STR(enhancement_hw, MENU_ENUM_LABEL_RDB_ENTRY_ENHANCEMENT_HW,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ENHANCEMENT_HW)
RDB_ENTRY_STR(cero_rating, MENU_ENUM_LABEL_RDB_ENTRY_CERO_RATING,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CERO_RATING)
RDB_ENTRY_STR(serial, MENU_ENUM_LABEL_RDB_ENTRY_SERIAL,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SERIAL)
RDB_ENTRY_BOOL(analog_supported, MENU_ENUM_LABEL_RDB_ENTRY_ANALOG,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ANALOG)
RDB_ENTRY_BOOL(rumble_supported, MENU_ENUM_LABEL_RDB_ENTRY_RUMBLE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RUMBLE)
RDB_ENTRY_BOOL(coop_supported, MENU_ENUM_LABEL_RDB_ENTRY_COOP,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_COOP)
RDB_ENTRY_BOOL(achievements, MENU_ENUM_LABEL_RDB_ENTRY_ACHIEVEMENTS,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ACHIEVEMENTS)
RDB_ENTRY_BOOL(console_exclusive, MENU_ENUM_LABEL_RDB_ENTRY_CONSOLE_EXCLUSIVE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CONSOLE_EXCLUSIVE)
RDB_ENTRY_BOOL(platform_exclusive, MENU_ENUM_LABEL_RDB_ENTRY_PLATFORM_EXCLUSIVE,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PLATFORM_EXCLUSIVE)
if (!show_advanced_settings)
continue;
if (db_info_entry->crc32)
{
if (create_string_list_rdb_entry_string(
MENU_ENUM_LABEL_RDB_ENTRY_CRC32,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32),
MENU_ENUM_LABEL_RDB_ENTRY_CRC32_STR,
crc_str, info->path, info->list) == -1)
goto error;
}
RDB_ENTRY_STR(sha1, MENU_ENUM_LABEL_RDB_ENTRY_SHA1,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1)
RDB_ENTRY_STR(md5, MENU_ENUM_LABEL_RDB_ENTRY_MD5,
MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5)
}
#undef RDB_ENTRY_STR
#undef RDB_ENTRY_INT
#undef RDB_ENTRY_BOOL
if (db_info->count < 1)
info->flags |= MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
if (!playlist_is_cached)
playlist_free(playlist);
/* db_info is owned by the dbinfo cache - do not free */
return 0;
error:
if (!playlist_is_cached)
playlist_free(playlist);
return -1;
}
#endif
int menu_displaylist_parse_settings_enum(
file_list_t *info_list,
enum menu_displaylist_parse_type parse_type,
bool add_empty_entry,
rarch_setting_t *setting,
unsigned entry_type,
bool is_enum,
bool menu_show_advanced_settings
)
{
static enum setting_type precond_lut[] =
{
ST_END_GROUP, /* PARSE_NONE */
ST_NONE, /* PARSE_GROUP */
ST_ACTION, /* PARSE_ACTION */
ST_INT, /* PARSE_ONLY_INT */
ST_UINT, /* PARSE_ONLY_UINT */
ST_BOOL, /* PARSE_ONLY_BOOL */
ST_FLOAT, /* PARSE_ONLY_FLOAT */
ST_BIND, /* PARSE_ONLY_BIND */
ST_END_GROUP, /* PARSE_ONLY_GROUP */
ST_STRING, /* PARSE_ONLY_STRING */
ST_PATH, /* PARSE_ONLY_PATH */
ST_STRING_OPTIONS, /* PARSE_ONLY_STRING_OPTIONS */
ST_DIR, /* PARSE_ONLY_DIR */
ST_NONE, /* PARSE_SUB_GROUP */
ST_SIZE, /* PARSE_ONLY_SIZE */
};
uint32_t flags;
enum setting_type precond = precond_lut[parse_type];
size_t count = 0;
if (!setting)
return -1;
flags = setting->flags;
#ifdef HAVE_LAKKA
if (flags & (SD_FLAG_ADVANCED | SD_FLAG_LAKKA_ADVANCED))
#else
if (flags & (SD_FLAG_ADVANCED))
#endif
{
if (!menu_show_advanced_settings)
goto end;
}
for (;;)
{
bool time_to_exit = false;
const char *short_description = setting->short_description;
const char *name = setting->name;
enum setting_type type = setting->type;
rarch_setting_t **list = &setting;
int type_flags = 0;
switch (parse_type)
{
case PARSE_NONE:
switch (type)
{
case ST_GROUP:
case ST_END_GROUP:
case ST_SUB_GROUP:
case ST_END_SUB_GROUP:
goto loop;
default:
break;
}
break;
case PARSE_GROUP:
case PARSE_ONLY_GROUP:
if (type == ST_GROUP)
break;
goto loop;
case PARSE_SUB_GROUP:
break;
case PARSE_ACTION:
case PARSE_ONLY_INT:
case PARSE_ONLY_UINT:
case PARSE_ONLY_SIZE:
case PARSE_ONLY_BIND:
case PARSE_ONLY_BOOL:
case PARSE_ONLY_FLOAT:
case PARSE_ONLY_STRING:
case PARSE_ONLY_PATH:
case PARSE_ONLY_DIR:
case PARSE_ONLY_STRING_OPTIONS:
if (type == precond)
break;
goto loop;
}
switch (type)
{
case ST_STRING_OPTIONS:
type_flags = MENU_SETTING_STRING_OPTIONS;
break;
case ST_ACTION:
type_flags = MENU_SETTING_ACTION;
break;
case ST_PATH:
type_flags = FILE_TYPE_PATH;
break;
case ST_GROUP:
type_flags = MENU_SETTING_GROUP;
break;
case ST_SUB_GROUP:
type_flags = MENU_SETTING_SUBGROUP;
break;
default:
break;
}
if (is_enum)
menu_entries_append(info_list,
short_description, name,
(enum msg_hash_enums)entry_type,
type_flags, 0, 0, NULL);
else
{
if (
(entry_type >= MENU_SETTINGS_INPUT_BEGIN)
&& (entry_type < MENU_SETTINGS_INPUT_END)
)
entry_type = (unsigned)(MENU_SETTINGS_INPUT_BEGIN + count);
if (entry_type == 0)
entry_type = type_flags;
menu_entries_append(info_list, short_description,
name, MSG_UNKNOWN, entry_type, 0, 0, menu_setting_find(name));
}
count++;
loop:
switch (parse_type)
{
case PARSE_NONE:
case PARSE_GROUP:
case PARSE_ONLY_GROUP:
case PARSE_SUB_GROUP:
if (setting->type == precond)
time_to_exit = true;
break;
case PARSE_ONLY_BIND:
case PARSE_ONLY_FLOAT:
case PARSE_ONLY_BOOL:
case PARSE_ONLY_INT:
case PARSE_ONLY_UINT:
case PARSE_ONLY_SIZE:
case PARSE_ONLY_PATH:
case PARSE_ONLY_DIR:
case PARSE_ONLY_STRING:
case PARSE_ONLY_STRING_OPTIONS:
case PARSE_ACTION:
time_to_exit = true;
break;
}
if (time_to_exit)
break;
(*list = *list + 1);
}
end:
if (count == 0)
{
if (add_empty_entry)
menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND),
MENU_ENUM_LABEL_NO_SETTINGS_FOUND_STR,
MENU_ENUM_LABEL_NO_SETTINGS_FOUND,
0, 0, 0, NULL);
return -1;
}
return 0;
}
static void menu_displaylist_set_new_playlist(
menu_handle_t *menu, settings_t *settings,
const char *path, bool sort_enabled)
{
playlist_config_t playlist_config;
const char *playlist_file_name = path_basename_nocompression(path);
int content_favorites_size = settings->ints.content_favorites_size;
unsigned content_history_size = settings->uints.content_history_size;
bool playlist_sort_alphabetical = settings->bools.playlist_sort_alphabetical;
playlist_config_set_path(&playlist_config, path);
playlist_config.capacity = COLLECTION_SIZE;
playlist_config.old_format = settings->bools.playlist_use_old_format;
playlist_config.compress = settings->bools.playlist_compression;
playlist_config.fuzzy_archive_match = settings->bools.playlist_fuzzy_archive_match;
playlist_config_set_base_content_directory(&playlist_config,
settings->bools.playlist_portable_paths
? settings->paths.directory_menu_content : NULL);
menu->db_playlist_file[0] = '\0';
/* The cache is not dropped here any more: playlist_init_cached
* decides whether the cached playlist can stand in for the one being
* asked for, and freeing it first would make that decision always
* come out "no" - which is exactly what made every rebuild of this
* list re-read and re-parse the same file. */
/* Get proper playlist capacity */
if (playlist_file_name && *playlist_file_name)
{
if (string_ends_with_size(playlist_file_name, "_history.lpl",
strlen(playlist_file_name), STRLEN_CONST("_history.lpl")))
playlist_config.capacity = content_history_size;
else if (!strcmp(playlist_file_name, FILE_PATH_CONTENT_FAVORITES)
&& (content_favorites_size >= 0))
playlist_config.capacity = (unsigned)content_favorites_size;
}
/* Budgeted first touch: one pass under the shared per-frame I/O
* window. Small and medium playlists finish inside it and this
* behaves exactly as the blocking call did; a large one yields,
* and the refresh below re-issues the request, which resumes the
* same parse where it stopped. The list is left empty for that
* frame rather than stalling the UI for the whole parse. */
{
nbio_budget_t b;
int pl_r;
task_nbio_slice_open(&b);
pl_r = playlist_init_cached_deferred(&playlist_config,
menu_displaylist_playlist_within_budget, &b);
task_nbio_slice_close(&b);
if (pl_r == 0)
{
/* Still parsing: come back next frame. */
menu_displaylist_dirwalk_refresh(0);
return;
}
if (pl_r < 0)
return;
}
{
playlist_t *playlist = playlist_get_cached();
enum playlist_sort_mode current_sort_mode = playlist_get_sort_mode(playlist);
/* Sort playlist, if required */
if ( sort_enabled
&& ((playlist_sort_alphabetical && (current_sort_mode == PLAYLIST_SORT_MODE_DEFAULT))
|| (current_sort_mode == PLAYLIST_SORT_MODE_ALPHABETICAL)))
playlist_qsort(playlist);
strlcpy(menu->db_playlist_file, path, sizeof(menu->db_playlist_file));
}
}
static int menu_displaylist_parse_horizontal_list(
menu_handle_t *menu, struct menu_state *menu_st,
settings_t *settings,
menu_displaylist_info_t *info)
{
struct item_file *item = NULL;
const menu_ctx_driver_t *driver_ctx = menu_st->driver_ctx;
size_t selection = driver_ctx->list_get_selection ? driver_ctx->list_get_selection(menu_st->userdata) : 0;
size_t _len = driver_ctx->list_get_size ? driver_ctx->list_get_size(menu_st->userdata, MENU_LIST_TABS) : 0;
if (!driver_ctx->list_get_entry)
return -1;
if (!(item = (struct item_file*)driver_ctx->list_get_entry(menu_st->userdata, MENU_LIST_HORIZONTAL,
(unsigned)(selection - (_len +1)))))
return -1;
/* When opening a saved view the explore menu will handle the list */
if (item->type == MENU_EXPLORE_TAB)
menu_displaylist_ctl(DISPLAYLIST_EXPLORE, info, settings);
else
{
playlist_t *playlist = NULL;
if (item->path && *item->path)
{
char lpl_basename[NAME_MAX_LENGTH];
char path_playlist[PATH_MAX_LENGTH];
const char *dir_playlist = settings->paths.directory_playlist;
fill_pathname_join_special(path_playlist, dir_playlist, item->path,
sizeof(path_playlist));
/* Horizontal lists are always 'collections'
* > Enable sorting (if allowed by user config) */
menu_displaylist_set_new_playlist(menu, settings, path_playlist, true);
/* Thumbnail system must be set *after* playlist
* is loaded/cached */
fill_pathname(lpl_basename, path_basename(item->path), "",
sizeof(lpl_basename));
gfx_thumbnail_set_system(menu_st->thumbnail_path_data,
lpl_basename, playlist_get_cached());
}
if ((playlist = playlist_get_cached()))
{
const char *_msg = MENU_ENUM_LABEL_COLLECTION_STR;
if (menu_displaylist_parse_playlist(info->list, info->path,
playlist, settings, _msg, strlen(_msg), true) == 0)
info->flags |= MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
}
}
return 0;
}
static int menu_displaylist_parse_load_content_settings(
file_list_t *list, settings_t *settings,
bool horizontal)
{
unsigned count = 0;
if (!retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
{
#ifdef HAVE_LAKKA
bool show_advanced_settings = settings->bools.menu_show_advanced_settings;
#endif
bool quickmenu_show_resume_content = settings->bools.quick_menu_show_resume_content;
bool quickmenu_show_restart_content = settings->bools.quick_menu_show_restart_content;
bool savestates_enabled = core_info_current_supports_savestate();
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
if (quickmenu_show_resume_content)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RESUME_CONTENT),
MENU_ENUM_LABEL_RESUME_CONTENT_STR,
MENU_ENUM_LABEL_RESUME_CONTENT,
MENU_SETTING_ACTION_RUN, 0, 0, NULL))
count++;
if (quickmenu_show_restart_content)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RESTART_CONTENT),
MENU_ENUM_LABEL_RESTART_CONTENT_STR,
MENU_ENUM_LABEL_RESTART_CONTENT,
MENU_SETTING_ACTION_RUN, 0, 0, NULL))
count++;
/* Note: Entry type depends on whether quick menu
* was accessed via a playlist ('horizontal content')
* or the main menu
* > This allows us to identify a close content event
* triggered via 'Main Menu > Quick Menu', which
* subsequently requires the menu stack to be flushed
* in order to prevent the display of an empty
* 'No items' menu */
if (settings->bools.quick_menu_show_close_content)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT),
MENU_ENUM_LABEL_CLOSE_CONTENT_STR,
MENU_ENUM_LABEL_CLOSE_CONTENT,
horizontal ? MENU_SETTING_ACTION_CLOSE_HORIZONTAL :
MENU_SETTING_ACTION_CLOSE,
0, 0, NULL))
count++;
if ( savestates_enabled
&& settings->bools.quick_menu_show_savestate_submenu)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVESTATE_LIST),
MENU_ENUM_LABEL_SAVESTATE_LIST_STR,
MENU_ENUM_LABEL_SAVESTATE_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
else if (savestates_enabled)
{
if (settings->bools.quick_menu_show_save_load_state)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_STATE_SLOT, PARSE_ONLY_INT, true) == 0)
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_STATE),
MENU_ENUM_LABEL_SAVE_STATE_STR,
MENU_ENUM_LABEL_SAVE_STATE,
MENU_SETTING_ACTION_SAVESTATE, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_STATE),
MENU_ENUM_LABEL_LOAD_STATE_STR,
MENU_ENUM_LABEL_LOAD_STATE,
MENU_SETTING_ACTION_LOADSTATE, 0, 0, NULL))
count++;
if (settings->bools.quick_menu_show_undo_save_load_state)
{
#ifdef HAVE_CHEEVOS
if (!rcheevos_hardcore_active())
#endif
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE),
MENU_ENUM_LABEL_UNDO_LOAD_STATE_STR,
MENU_ENUM_LABEL_UNDO_LOAD_STATE,
MENU_SETTING_ACTION_LOADSTATE, 0, 0, NULL))
count++;
}
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE),
MENU_ENUM_LABEL_UNDO_SAVE_STATE_STR,
MENU_ENUM_LABEL_UNDO_SAVE_STATE,
MENU_SETTING_ACTION_LOADSTATE, 0, 0, NULL))
count++;
}
}
}
if (!settings->bools.kiosk_mode_enable)
{
if (settings->bools.quick_menu_show_options)
{
/* Empty 'path' string signifies top level
* core options menu */
if (menu_entries_append(list,
"",
MENU_ENUM_LABEL_CORE_OPTIONS_STR,
MENU_ENUM_LABEL_CORE_OPTIONS,
MENU_SETTING_ACTION_CORE_OPTIONS, 0, 0, NULL))
count++;
}
if (settings->bools.quick_menu_show_controls)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS),
MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS_STR,
MENU_ENUM_LABEL_CORE_INPUT_REMAPPING_OPTIONS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
if ((!retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
&& disk_control_enabled(&sys_info->disk_control))
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISK_OPTIONS),
MENU_ENUM_LABEL_DISK_OPTIONS_STR,
MENU_ENUM_LABEL_DISK_OPTIONS,
MENU_SETTING_ACTION_CORE_DISK_OPTIONS, 0, 0, NULL))
count++;
#ifdef HAVE_SCREENSHOTS
if (settings->bools.quick_menu_show_take_screenshot)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT),
MENU_ENUM_LABEL_TAKE_SCREENSHOT_STR,
MENU_ENUM_LABEL_TAKE_SCREENSHOT,
MENU_SETTING_ACTION_SCREENSHOT, 0, 0, NULL))
count++;
}
#endif
if (string_is_not_equal(settings->arrays.record_driver, "null"))
{
recording_state_t *recording_st = recording_state_get_ptr();
if (!recording_st->enable)
{
if (!settings->bools.kiosk_mode_enable)
{
if (settings->bools.quick_menu_show_start_recording)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QUICK_MENU_START_RECORDING),
MENU_ENUM_LABEL_QUICK_MENU_START_RECORDING_STR,
MENU_ENUM_LABEL_QUICK_MENU_START_RECORDING, MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
if ( settings->bools.quick_menu_show_start_streaming
&& !strcmp(settings->arrays.record_driver,
"ffmpeg"))
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QUICK_MENU_START_STREAMING),
MENU_ENUM_LABEL_QUICK_MENU_START_STREAMING_STR,
MENU_ENUM_LABEL_QUICK_MENU_START_STREAMING, MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
}
else
{
if (recording_st->streaming_enable)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QUICK_MENU_STOP_STREAMING),
MENU_ENUM_LABEL_QUICK_MENU_STOP_STREAMING_STR,
MENU_ENUM_LABEL_QUICK_MENU_STOP_STREAMING, MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
else
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QUICK_MENU_STOP_RECORDING),
MENU_ENUM_LABEL_QUICK_MENU_STOP_RECORDING_STR,
MENU_ENUM_LABEL_QUICK_MENU_STOP_RECORDING, MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
}
#ifdef HAVE_BSV_MOVIE
if ( savestates_enabled
&& !settings->bools.quick_menu_show_savestate_submenu
&& settings->bools.quick_menu_show_replay)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_REPLAY_SLOT, PARSE_ONLY_INT, true) == 0)
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RECORD_REPLAY),
MENU_ENUM_LABEL_RECORD_REPLAY_STR,
MENU_ENUM_LABEL_RECORD_REPLAY,
MENU_SETTING_ACTION_RECORDREPLAY, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAY_REPLAY),
MENU_ENUM_LABEL_PLAY_REPLAY_STR,
MENU_ENUM_LABEL_PLAY_REPLAY,
MENU_SETTING_ACTION_PLAYREPLAY, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HALT_REPLAY),
MENU_ENUM_LABEL_HALT_REPLAY_STR,
MENU_ENUM_LABEL_HALT_REPLAY,
MENU_SETTING_ACTION_HALTREPLAY, 0, 0, NULL))
count++;
}
#endif
if (
settings->bools.quick_menu_show_add_to_favorites
&& settings->bools.menu_content_show_favorites
)
{
bool add_to_favorites_enabled = true;
/* Skip 'Add to Favourites' if we are currently
* viewing an entry of the favourites playlist */
if (horizontal)
{
playlist_t *playlist = playlist_get_cached();
const char *playlist_path = playlist_get_conf_path(playlist);
const char *playlist_file = NULL;
if (playlist_path && *playlist_path)
playlist_file = path_basename_nocompression(playlist_path);
if ( playlist_file
&& !strcmp(playlist_file, FILE_PATH_CONTENT_FAVORITES))
add_to_favorites_enabled = false;
}
if ( add_to_favorites_enabled
&& menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES),
MENU_ENUM_LABEL_ADD_TO_FAVORITES_STR,
MENU_ENUM_LABEL_ADD_TO_FAVORITES, FILE_TYPE_PLAYLIST_ENTRY, 0, 0, NULL))
count++;
}
if (settings->bools.quick_menu_show_add_to_playlist)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_PLAYLIST),
MENU_ENUM_LABEL_ADD_TO_PLAYLIST_QUICKMENU_STR,
MENU_ENUM_LABEL_ADD_TO_PLAYLIST_QUICKMENU,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
if (!settings->bools.kiosk_mode_enable)
{
if (settings->bools.menu_show_overlays)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ONSCREEN_OVERLAY_SETTINGS),
MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS_STR,
MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
if (settings->bools.menu_show_latency)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LATENCY_SETTINGS),
MENU_ENUM_LABEL_LATENCY_SETTINGS_STR,
MENU_ENUM_LABEL_LATENCY_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#ifdef HAVE_REWIND
if ( settings->bools.menu_show_rewind
&& core_info_current_supports_rewind())
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS),
MENU_ENUM_LABEL_REWIND_SETTINGS_STR,
MENU_ENUM_LABEL_REWIND_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#endif
if ( (settings->bools.quick_menu_show_save_core_overrides
|| settings->bools.quick_menu_show_save_content_dir_overrides
|| settings->bools.quick_menu_show_save_game_overrides))
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_QUICK_MENU_OVERRIDE_OPTIONS),
MENU_ENUM_LABEL_QUICK_MENU_OVERRIDE_OPTIONS_STR,
MENU_ENUM_LABEL_QUICK_MENU_OVERRIDE_OPTIONS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
#ifdef HAVE_CHEEVOS
if (settings->bools.cheevos_enable)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ACHIEVEMENT_LIST),
MENU_ENUM_LABEL_ACHIEVEMENT_LIST_STR,
MENU_ENUM_LABEL_ACHIEVEMENT_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#endif
#ifdef HAVE_CHEATS
if (settings->bools.quick_menu_show_cheats)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS),
MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS_STR,
MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#endif
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
gfx_ctx_flags_t flags;
flags.flags = 0;
video_context_driver_get_flags(&flags);
if (
BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG)
|| BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL)
|| BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG)
|| BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_HLSL))
{
if (settings->bools.quick_menu_show_shaders && !settings->bools.kiosk_mode_enable)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS),
MENU_ENUM_LABEL_SHADER_OPTIONS_STR,
MENU_ENUM_LABEL_SHADER_OPTIONS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
}
#endif
if (settings->bools.quick_menu_show_information)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INFORMATION),
MENU_ENUM_LABEL_INFORMATION_STR,
MENU_ENUM_LABEL_INFORMATION,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#if HAVE_GAME_AI
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_GAME_AI_MENU_OPTION,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (settings->bools.quick_menu_show_game_ai)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_GAME_AI_OPTIONS),
MENU_ENUM_LABEL_CORE_GAME_AI_OPTIONS_STR,
MENU_ENUM_LABEL_CORE_CHEAT_OPTIONS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#endif
}
return count;
}
static int menu_displaylist_parse_horizontal_content_actions(
menu_handle_t *menu, settings_t *settings, file_list_t *list)
{
bool content_loaded = false;
playlist_t *playlist = playlist_get_cached();
const char *fullpath = path_get(RARCH_PATH_CONTENT);
struct menu_state *menu_st = menu_state_get_ptr();
unsigned idx = menu->rpl_entry_selection_ptr;
const struct playlist_entry *entry = NULL;
if (playlist)
playlist_get_index(playlist, idx, &entry);
content_loaded = !retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)
&& string_is_equal(menu->deferred_path, fullpath);
if (content_loaded)
{
if (menu_displaylist_parse_load_content_settings(list,
settings, true) == 0)
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ITEMS),
MENU_ENUM_LABEL_NO_ITEMS_STR,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_NO_ITEM, 0, 0, NULL);
}
else
{
const char *playlist_path = NULL;
const char *playlist_file = NULL;
#ifdef HAVE_AUDIOMIXER
const char *ext = NULL;
if (entry && (entry->path && *entry->path))
ext = path_get_extension(entry->path);
if ( (ext && *ext)
&& audio_driver_mixer_extension_supported(ext))
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER),
MENU_ENUM_LABEL_ADD_TO_MIXER_STR,
MENU_ENUM_LABEL_ADD_TO_MIXER,
FILE_TYPE_PLAYLIST_ENTRY, 0, idx, NULL);
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_PLAY),
MENU_ENUM_LABEL_ADD_TO_MIXER_AND_PLAY_STR,
MENU_ENUM_LABEL_ADD_TO_MIXER_AND_PLAY,
FILE_TYPE_PLAYLIST_ENTRY, 0, idx, NULL);
}
#endif
playlist_path = playlist_get_conf_path(playlist);
if (playlist_path && *playlist_path)
playlist_file = path_basename_nocompression(playlist_path);
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN),
MENU_ENUM_LABEL_RUN_STR,
MENU_ENUM_LABEL_RUN,
FILE_TYPE_PLAYLIST_ENTRY, 0, idx, NULL);
if (settings->bools.quick_menu_show_save_load_state)
{
bool savestates_enabled = core_info_current_supports_savestate();
playlist_t *playlist = playlist_get_cached();
/* Trust core info for showing state load menu per playlist entry, because
* 'core_info_current_supports_savestate()' requires a core to be loaded,
* otherwise it defaults to true */
if (playlist)
{
struct menu_state *menu_st = menu_state_get_ptr();
const struct playlist_entry *entry = NULL;
if (menu_st && menu_st->driver_data)
playlist_get_index(playlist, menu_st->driver_data->rpl_entry_selection_ptr, &entry);
if (entry && *entry->path)
{
core_info_t *core_info = NULL;
if (core_info_find(entry->core_path, &core_info))
{
if (core_info->savestate_support_level < CORE_INFO_SAVESTATE_BASIC)
savestates_enabled = false;
}
}
}
if (savestates_enabled)
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_STATE),
MENU_ENUM_LABEL_STATE_SLOT_RUN_STR,
MENU_ENUM_LABEL_STATE_SLOT_RUN,
MENU_SETTING_ACTION, 0, idx, NULL);
}
if (!settings->bools.kiosk_mode_enable)
{
bool remove_entry_enabled = false;
if (settings->bools.playlist_entry_rename)
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RENAME_ENTRY),
MENU_ENUM_LABEL_RENAME_ENTRY_STR,
MENU_ENUM_LABEL_RENAME_ENTRY,
FILE_TYPE_PLAYLIST_ENTRY, 0, idx, NULL);
switch (settings->uints.playlist_entry_remove_enable)
{
case PLAYLIST_ENTRY_REMOVE_ENABLE_ALL:
remove_entry_enabled = true;
break;
case PLAYLIST_ENTRY_REMOVE_ENABLE_HIST_FAV:
{
if (*menu_st->thumbnail_path_data->system)
remove_entry_enabled =
!strcmp(menu_st->thumbnail_path_data->system, "history")
|| !strcmp(menu_st->thumbnail_path_data->system, "favorites")
|| string_ends_with_size(menu_st->thumbnail_path_data->system, "_history",
menu_st->thumbnail_path_data->system_len, STRLEN_CONST("_history"));
/* An annoyance: if the user navigates to the
* information menu, then to the database entry,
* the thumbnail system will be changed.
* This breaks the above 'remove_entry_enabled'
* check for the history and favorites playlists.
* We therefore have to check the playlist file
* name as well... */
if ( !remove_entry_enabled
&& settings->bools.quick_menu_show_information
&& (playlist_file && *playlist_file))
remove_entry_enabled =
string_is_equal(playlist_file, FILE_PATH_CONTENT_HISTORY)
|| string_is_equal(playlist_file, FILE_PATH_CONTENT_FAVORITES);
}
break;
}
/* Remove 'Remove' from Explore lists for now since it does not work correctly */
if (remove_entry_enabled)
{
menu_list_t *menu_list = menu_st->entries.list;
file_list_t *menu_stack = MENU_LIST_GET(menu_list, 0);
struct item_file *stack_top = menu_stack->list;
size_t depth = menu_stack->size;
unsigned current_type = (depth > 0 ? stack_top[depth - 1].type : 0);
if (current_type)
remove_entry_enabled = false;
}
if (remove_entry_enabled)
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DELETE_ENTRY),
MENU_ENUM_LABEL_DELETE_ENTRY_STR,
MENU_ENUM_LABEL_DELETE_ENTRY,
MENU_SETTING_ACTION_DELETE_ENTRY, 0, 0, NULL);
}
/* Skip 'Add to Favourites' if we are currently
* viewing an entry of the favourites playlist */
if (
settings->bools.quick_menu_show_add_to_favorites
&& settings->bools.menu_content_show_favorites
&& !((playlist_file && *playlist_file)
&& string_is_equal(playlist_file, FILE_PATH_CONTENT_FAVORITES))
)
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_FAVORITES_PLAYLIST),
MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST_STR,
MENU_ENUM_LABEL_ADD_TO_FAVORITES_PLAYLIST,
FILE_TYPE_PLAYLIST_ENTRY, 0, 0, NULL);
}
if (settings->bools.quick_menu_show_add_to_playlist)
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_PLAYLIST),
MENU_ENUM_LABEL_ADD_TO_PLAYLIST_STR,
MENU_ENUM_LABEL_ADD_TO_PLAYLIST,
MENU_SETTING_ACTION, 0, 0, NULL);
}
if (!settings->bools.kiosk_mode_enable)
{
if (settings->bools.quick_menu_show_set_core_association)
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SET_CORE_ASSOCIATION),
MENU_ENUM_LABEL_SET_CORE_ASSOCIATION_STR,
MENU_ENUM_LABEL_SET_CORE_ASSOCIATION, FILE_TYPE_PLAYLIST_ENTRY, 0, 0, NULL);
}
if (settings->bools.quick_menu_show_reset_core_association)
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RESET_CORE_ASSOCIATION),
MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION_STR,
MENU_ENUM_LABEL_RESET_CORE_ASSOCIATION, FILE_TYPE_PLAYLIST_ENTRY, 0, 0, NULL);
}
#ifdef HAVE_NETWORKING
if (settings->bools.quick_menu_show_download_thumbnails)
{
bool download_enabled = true;
if (download_enabled)
{
/* Only show 'Download Thumbnails' on supported playlists */
if (*menu_st->thumbnail_path_data->system)
download_enabled = !string_ends_with_size(
menu_st->thumbnail_path_data->system,
"_history",
menu_st->thumbnail_path_data->system_len,
STRLEN_CONST("_history"));
else
download_enabled = false;
}
if (settings->bools.network_on_demand_thumbnails)
download_enabled = false;
if (download_enabled)
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_PL_ENTRY_THUMBNAILS),
MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS_STR,
MENU_ENUM_LABEL_DOWNLOAD_PL_ENTRY_THUMBNAILS, FILE_TYPE_PLAYLIST_ENTRY, 0, 0, NULL);
}
#endif
}
if (settings->bools.quick_menu_show_information)
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INFORMATION),
MENU_ENUM_LABEL_INFORMATION_STR,
MENU_ENUM_LABEL_INFORMATION, MENU_SETTING_ACTION, 0, 0, NULL);
}
return 0;
}
static unsigned menu_displaylist_parse_information_list(file_list_t *info_list)
{
unsigned count = 0;
core_info_t *core_info = NULL;
struct retro_system_info *sysinfo = &runloop_state_get_ptr()->system.info;
core_info_get_current_core(&core_info);
if ( sysinfo
&& ((sysinfo->library_name && *sysinfo->library_name)
&& !string_is_equal(sysinfo->library_name,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE))
)
&& core_info
&& (core_info->flags & CORE_INFO_FLAG_HAS_INFO)
)
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_INFORMATION),
MENU_ENUM_LABEL_CORE_INFORMATION_STR,
MENU_ENUM_LABEL_CORE_INFORMATION,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#ifdef HAVE_CDROM
{
struct string_list *drive_list = cdrom_get_available_drives();
if (drive_list)
{
if (drive_list->size)
{
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFORMATION),
MENU_ENUM_LABEL_DISC_INFORMATION_STR,
MENU_ENUM_LABEL_DISC_INFORMATION,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
string_list_free(drive_list);
}
}
#endif
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION),
MENU_ENUM_LABEL_SYSTEM_INFORMATION_STR,
MENU_ENUM_LABEL_SYSTEM_INFORMATION,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISPLAY_INFORMATION),
MENU_ENUM_LABEL_DISPLAY_INFORMATION_STR,
MENU_ENUM_LABEL_DISPLAY_INFORMATION,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_INFORMATION),
MENU_ENUM_LABEL_INPUT_INFORMATION_STR,
MENU_ENUM_LABEL_INPUT_INFORMATION,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#if defined(HAVE_NETWORKING) && defined(HAVE_IFINFO)
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_INFORMATION),
MENU_ENUM_LABEL_NETWORK_INFORMATION_STR,
MENU_ENUM_LABEL_NETWORK_INFORMATION,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
#ifdef HAVE_LIBRETRODB
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER),
MENU_ENUM_LABEL_DATABASE_MANAGER_LIST_STR,
MENU_ENUM_LABEL_DATABASE_MANAGER_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
if (retroarch_ctl(RARCH_CTL_IS_PERFCNT_ENABLE, NULL))
{
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS),
MENU_ENUM_LABEL_FRONTEND_COUNTERS_STR,
MENU_ENUM_LABEL_FRONTEND_COUNTERS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_COUNTERS),
MENU_ENUM_LABEL_CORE_COUNTERS_STR,
MENU_ENUM_LABEL_CORE_COUNTERS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
/* Move password-hidden enablers under Information if visible */
{
const char *menu_ident = menu_driver_ident();
settings_t *settings = config_get_ptr();
if ( !settings->bools.menu_content_show_settings
&& !settings->bools.kiosk_mode_enable
&& !(string_is_equal(menu_ident, "glui")
&& settings->bools.menu_materialui_show_nav_bar)
&& *settings->paths.menu_content_show_settings_password)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info_list,
MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS,
PARSE_ACTION,
false) == 0)
count++;
if ( settings->bools.kiosk_mode_enable
&& *settings->paths.kiosk_mode_password)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info_list,
MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE,
PARSE_ACTION,
false) == 0)
count++;
}
return count;
}
static bool menu_history_in_main_menu(const char *menu_ident,
settings_t *settings)
{
return (!strcmp(menu_ident, "rgui"))
|| (!strcmp(menu_ident, "glui") && !settings->bools.menu_materialui_show_nav_bar)
|| (!strcmp(menu_ident, "ozone") && !settings->bools.ozone_show_sidebar)
|| (!strcmp(menu_ident, "xmb") && !settings->bools.menu_xmb_show_horizontal_list);
}
static unsigned menu_displaylist_parse_playlists(
file_list_t *info_list,
unsigned type_default,
const char *path,
settings_t *settings,
bool horizontal)
{
size_t i, list_size;
struct string_list str_list = {0};
struct string_list *walk_list = NULL;
enum menu_dirwalk_status walk_status = MENU_DIRWALK_FAILED;
unsigned count = 0;
unsigned content_count = 0;
bool show_hidden_files = settings->bools.show_hidden_files;
if (!path || !*path)
{
int ret = frontend_driver_parse_drive_list(info_list, true);
/* TODO/FIXME - we need to know the actual count number here */
if (ret == 0)
count++;
else
if (menu_entries_append(info_list, "/", "",
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR,
FILE_TYPE_DIRECTORY, 0, 0, NULL))
count++;
return count;
}
if (!horizontal)
{
const char *menu_ident = menu_driver_ident();
bool show_add_content = (settings->uints.menu_content_show_add_entry ==
MENU_ADD_CONTENT_ENTRY_DISPLAY_PLAYLISTS_TAB);
bool show_netplay = (settings->uints.menu_content_show_netplay ==
MENU_ADD_CONTENT_ENTRY_DISPLAY_PLAYLISTS_TAB);
bool show_history = !menu_history_in_main_menu(menu_ident, settings);
if (show_history)
{
if (settings->bools.menu_content_show_favorites_first)
{
if (settings->bools.menu_content_show_favorites)
if (menu_entries_append(info_list,
playlist_get_conf_path(g_defaults.content_favorites),
MENU_ENUM_LABEL_GOTO_FAVORITES_STR,
MENU_ENUM_LABEL_GOTO_FAVORITES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (settings->bools.menu_content_show_history && g_defaults.content_history)
if (menu_entries_append(info_list,
playlist_get_conf_path(g_defaults.content_history),
MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY_STR,
MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
else
{
if (settings->bools.menu_content_show_history && g_defaults.content_history)
if (menu_entries_append(info_list,
playlist_get_conf_path(g_defaults.content_history),
MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY_STR,
MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (settings->bools.menu_content_show_favorites)
if (menu_entries_append(info_list,
playlist_get_conf_path(g_defaults.content_favorites),
MENU_ENUM_LABEL_GOTO_FAVORITES_STR,
MENU_ENUM_LABEL_GOTO_FAVORITES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
#if defined(HAVE_IMAGEVIEWER) || defined(HAVE_MENU)
if (settings->bools.menu_content_show_images && g_defaults.image_history)
if (menu_entries_append(info_list,
playlist_get_conf_path(g_defaults.image_history),
MENU_ENUM_LABEL_GOTO_IMAGES_STR,
MENU_ENUM_LABEL_GOTO_IMAGES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
if (settings->bools.menu_content_show_music && g_defaults.music_history)
if (menu_entries_append(info_list,
playlist_get_conf_path(g_defaults.music_history),
MENU_ENUM_LABEL_GOTO_MUSIC_STR,
MENU_ENUM_LABEL_GOTO_MUSIC,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) || defined(HAVE_WEBMPLAYER)
if (settings->bools.menu_content_show_video && g_defaults.video_history)
if (menu_entries_append(info_list,
playlist_get_conf_path(g_defaults.video_history),
MENU_ENUM_LABEL_GOTO_VIDEO_STR,
MENU_ENUM_LABEL_GOTO_VIDEO,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
if (show_netplay)
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY),
MENU_ENUM_LABEL_NETPLAY_STR,
MENU_ENUM_LABEL_NETPLAY,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (show_add_content)
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST),
MENU_ENUM_LABEL_ADD_CONTENT_LIST_STR,
MENU_ENUM_LABEL_ADD_CONTENT_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#if defined(HAVE_DYNAMIC)
if (settings->uints.menu_content_show_contentless_cores !=
MENU_CONTENTLESS_CORES_DISPLAY_NONE)
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_CONTENTLESS_CORES),
MENU_ENUM_LABEL_GOTO_CONTENTLESS_CORES_STR,
MENU_ENUM_LABEL_GOTO_CONTENTLESS_CORES,
MENU_CONTENTLESS_CORES_TAB, 0, 0, NULL))
count++;
#endif
#if defined(HAVE_LIBRETRODB)
if (settings->bools.menu_content_show_explore)
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_GOTO_EXPLORE),
MENU_ENUM_LABEL_GOTO_EXPLORE_STR,
MENU_ENUM_LABEL_GOTO_EXPLORE,
MENU_EXPLORE_TAB, 0, 0, NULL))
count++;
#endif
}
if (horizontal)
{
if ( (retroarch_get_flags() & RARCH_FLAGS_USER_DIRS_HELD)
|| !dir_list_initialize(&str_list, path, NULL, true,
show_hidden_files, true, false))
return count;
dir_list_sort_ignore_ext(&str_list, true);
}
else
{
menu_dirwalk_set_refresh_cb(menu_displaylist_dirwalk_refresh);
walk_status = menu_dirwalk_request(path, NULL, true,
show_hidden_files, true, MENU_DIRWALK_SORT_IGNORE_EXT,
MENU_DIRWALK_TAG_PLAYLISTS, &walk_list);
if (walk_status == MENU_DIRWALK_PENDING)
{
/* The playlist-directory walk continues in the background;
* the refresh callback rebuilds this list on completion. */
if (menu_entries_append(info_list,
msg_hash_to_str(MSG_LOADING), "",
MSG_UNKNOWN, MENU_SETTING_NO_ITEM, 0, 0, NULL))
count++;
return count;
}
if (walk_status != MENU_DIRWALK_DONE || !walk_list)
return count; /* same early-out as a failed walk before */
/* Move the completed listing (sorted by the module) into the
* local list the loop below reads. */
str_list = *walk_list;
free(walk_list);
}
content_count = count;
list_size = str_list.size;
#if defined(HAVE_LIBRETRODB)
if (settings->bools.menu_content_show_explore)
{
char lbl[NAME_MAX_LENGTH];
size_t _len = strlcpy(lbl, msg_hash_to_str(MENU_ENUM_LABEL_EXPLORE_VIEW),
sizeof(lbl));
/* List any custom explore views above playlists */
for (i = 0; i < list_size; i++)
{
const char *path = str_list.elems[i].data;
const char *fname = path_basename(path);
const char *fext = path_get_extension(fname);
if (!string_is_equal_noncase(fext, "lvw"))
continue;
snprintf(lbl + _len, sizeof(lbl) - _len, ": %.*s",
(int)(fext - 1 - fname), fname);
if (menu_entries_append(info_list, lbl, path,
MENU_ENUM_LABEL_GOTO_EXPLORE,
MENU_EXPLORE_TAB, 0, (count - content_count), NULL))
{
menu_file_list_cbs_t *cbs = ((menu_file_list_cbs_t*)info_list->list[info_list->size-1].actiondata);
cbs->action_sublabel = NULL;
count++;
}
}
}
#endif
for (i = 0; i < list_size; i++)
{
const char *path = str_list.elems[i].data;
const char *playlist_file = NULL;
enum msg_file_type file_type = FILE_TYPE_NONE;
switch (str_list.elems[i].attr.i)
{
case RARCH_DIRECTORY:
file_type = FILE_TYPE_DIRECTORY;
break;
case RARCH_PLAIN_FILE:
default:
file_type = (enum msg_file_type)type_default;
break;
}
if (file_type == FILE_TYPE_DIRECTORY)
continue;
if (!path || !*path)
continue;
playlist_file = path_basename_nocompression(path);
if (!playlist_file || !*playlist_file)
continue;
/* Ignore non-playlist files */
if (!string_is_equal_noncase(path_get_extension(playlist_file),
"lpl"))
continue;
/* Ignore history/favourites */
if (
string_ends_with_size(path, "_history.lpl",
strlen(path), STRLEN_CONST("_history.lpl"))
|| string_is_equal(playlist_file,
FILE_PATH_CONTENT_FAVORITES))
continue;
file_type = FILE_TYPE_PLAYLIST_COLLECTION;
if (horizontal)
path = playlist_file;
if (menu_entries_append(info_list, path, "",
MENU_ENUM_LABEL_PLAYLIST_COLLECTION_ENTRY,
file_type, 0, (count - content_count), NULL))
count++;
}
dir_list_deinitialize(&str_list);
return count;
}
static unsigned menu_displaylist_parse_cores(menu_handle_t *menu,
bool show_hidden_files, menu_displaylist_info_t *info)
{
size_t i, list_size;
char out_dir[DIR_MAX_LENGTH];
struct string_list *str_list = NULL;
unsigned count = 0;
const char *path = info->path;
bool ok = false;
bool walk_pending = false;
bool list_presorted = false;
if (!path || !*path)
{
if (frontend_driver_parse_drive_list(info->list, true) != 0)
menu_entries_append(info->list, "/", "",
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR, FILE_TYPE_DIRECTORY, 0, 0, NULL);
count++;
return count;
}
#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
/* UWP joins the optional core packages into the same listing:
* keep the one-shot construction (a handful of package
* directories) and the local sort below. */
str_list = string_list_new();
ok = dir_list_append(str_list, path, info->exts,
true, show_hidden_files, false, false);
#else
{
enum menu_dirwalk_status walk_status;
menu_dirwalk_set_refresh_cb(menu_displaylist_dirwalk_refresh);
walk_status = menu_dirwalk_request(path, info->exts,
true, show_hidden_files, false,
MENU_DIRWALK_SORT_DIR_FIRST,
MENU_DIRWALK_TAG_CORES, &str_list);
walk_pending = (walk_status == MENU_DIRWALK_PENDING);
list_presorted = (walk_status == MENU_DIRWALK_DONE);
ok = list_presorted;
}
#endif
#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
/* UWP: browse the optional packages for additional cores */
struct string_list *core_packages = string_list_new();
uwp_fill_installed_core_packages(core_packages);
for (i = 0; i < core_packages->size; i++)
dir_list_append(str_list, core_packages->elems[i].data, info->exts,
true, show_hidden_files, true, false);
string_list_free(core_packages);
#else
/* A failed walk hands back no listing; the not-found entry
* below covers it, as it did for a failed dir_list_append. */
if (!ok && str_list)
{
string_list_free(str_list);
str_list = NULL;
}
#endif
fill_pathname_parent_dir(out_dir, path, sizeof(out_dir));
if (!*out_dir)
menu_entries_prepend(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY),
path,
MENU_ENUM_LABEL_PARENT_DIRECTORY,
FILE_TYPE_PARENT_DIRECTORY, 0, 0);
if (walk_pending)
{
menu_entries_append(info->list,
msg_hash_to_str(MSG_LOADING), "",
MSG_UNKNOWN, MENU_SETTING_NO_ITEM, 0, 0, NULL);
count++;
return count;
}
if (!str_list)
{
const char *str = msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND);
menu_entries_append(info->list, str, "",
MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND, 0, 0, 0, NULL);
count++;
return count;
}
if (string_is_equal(info->label, MENU_ENUM_LABEL_CORE_LIST_STR))
info->flags |= MD_FLAG_DOWNLOAD_CORE;
if (!list_presorted)
dir_list_sort(str_list, true);
list_size = str_list->size;
if (list_size == 0)
{
string_list_free(str_list);
return 0;
}
for (i = 0; i < list_size; i++)
{
char label[64];
#ifndef HAVE_DYNAMIC
bool is_dir = false;
#endif
const char *path = NULL;
enum msg_hash_enums enum_idx = MSG_UNKNOWN;
enum msg_file_type file_type = FILE_TYPE_NONE;
/* TODO/FIXME - empty label */
label[0] = '\0';
switch (str_list->elems[i].attr.i)
{
case RARCH_DIRECTORY:
file_type = FILE_TYPE_DIRECTORY;
enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY;
#ifndef HAVE_DYNAMIC
is_dir = true;
#endif
break;
case RARCH_COMPRESSED_ARCHIVE:
case RARCH_COMPRESSED_FILE_IN_ARCHIVE:
/* Compressed cores are unsupported */
continue;
case RARCH_PLAIN_FILE:
default:
file_type = FILE_TYPE_CORE;
enum_idx = MENU_ENUM_LABEL_FILE_BROWSER_CORE;
break;
}
/* Need to preserve slash first time. */
path = str_list->elems[i].data;
if (path && *path)
path = path_basename_nocompression(path);
#ifndef HAVE_DYNAMIC
if (frontend_driver_has_fork())
{
char salamander_name[NAME_MAX_LENGTH];
salamander_name[0] = '\0';
if (frontend_driver_get_salamander_basename(
salamander_name, sizeof(salamander_name)))
{
if (string_is_equal_noncase(path, salamander_name))
continue;
}
if (is_dir)
continue;
}
#endif
#if TARGET_OS_IPHONE
/* For various reasons on iOS/tvOS, MoltenVK shows up
* in the cores directory; exclude it here */
if (string_starts_with(path, "MoltenVK"))
continue;
#endif
count++;
menu_entries_append(info->list, path, label,
enum_idx,
file_type, 0, 0, NULL);
}
string_list_free(str_list);
if (count == 0)
return 0;
{
core_info_list_t *list = NULL;
const char *dir = NULL;
core_info_get_list(&list);
menu_entries_get_last_stack(&dir, NULL, NULL, NULL, NULL);
list_size = info->list->size;
for (i = 0; i < list_size; i++)
{
const char *path = info->list->list[i].path;
unsigned type = info->list->list[i].type;
if (type == FILE_TYPE_CORE)
{
char core_path[PATH_MAX_LENGTH];
char display_name[NAME_MAX_LENGTH];
fill_pathname_join_special(core_path, dir, path, sizeof(core_path));
if (core_info_list_get_display_name(list,
core_path, display_name, sizeof(display_name)) > 0)
file_list_set_alt_at_offset(info->list, i, display_name);
}
}
info->flags |= MD_FLAG_NEED_SORT;
}
return count;
}
static unsigned menu_displaylist_parse_add_to_playlist_list(file_list_t *list,
enum menu_displaylist_ctl_state type, const char *dir_playlist, bool show_hidden_files)
{
char playlist_display_name[NAME_MAX_LENGTH];
unsigned count = 0;
struct string_list *str_list = NULL;
enum menu_dirwalk_status walk_status;
/* The playlist-directory listing DIR_LIST_COLLECTIONS produced:
* "lpl" extension, no directories, no compressed files. */
menu_dirwalk_set_refresh_cb(menu_displaylist_dirwalk_refresh);
walk_status = menu_dirwalk_request(dir_playlist, "lpl", false,
show_hidden_files, false, MENU_DIRWALK_SORT_DIR_FIRST,
MENU_DIRWALK_TAG_ADD_TO_PLAYLIST, &str_list);
if (walk_status == MENU_DIRWALK_PENDING)
{
if (menu_entries_append(list,
msg_hash_to_str(MSG_LOADING), "",
MSG_UNKNOWN, MENU_SETTING_NO_ITEM, 0, 0, NULL))
count++;
return count;
}
if (str_list && str_list->size)
{
unsigned i;
for (i = 0; i < str_list->size; i++)
{
const char *path = str_list->elems[i].data;
const char *playlist_file = NULL;
if (str_list->elems[i].attr.i == FILE_TYPE_DIRECTORY)
continue;
if (!path || !*path)
continue;
playlist_file = path_basename_nocompression(path);
if (!playlist_file || !*playlist_file)
continue;
/* Ignore non-playlist files */
if (!string_is_equal_noncase(path_get_extension(playlist_file),
"lpl"))
continue;
/* Ignore history/favourites
* > content_history + favorites are handled separately
* > music/video/image_history are ignored */
if ( string_ends_with_size(path, "_history.lpl", strlen(path), STRLEN_CONST("_history.lpl"))
|| !strcmp(playlist_file, FILE_PATH_CONTENT_FAVORITES))
continue;
fill_pathname(playlist_display_name, playlist_file, "",
sizeof(playlist_display_name));
menu_entries_append(list, playlist_display_name, path,
(type == DISPLAYLIST_ADD_TO_PLAYLIST_LIST ?
MENU_ENUM_LABEL_ADD_ENTRY_TO_PLAYLIST :
MENU_ENUM_LABEL_ADD_ENTRY_TO_PLAYLIST_QUICKMENU),
MENU_SETTING_ACTION, 0, 0, NULL);
count++;
}
}
/* Not necessary to check for NULL here */
string_list_free(str_list);
return count;
}
static unsigned menu_displaylist_parse_playlist_manager_list(
file_list_t *list, settings_t *settings)
{
unsigned count = 0;
const char *dir_playlist = settings->paths.directory_playlist;
bool show_hidden_files = settings->bools.show_hidden_files;
bool history_list_enable = settings->bools.history_list_enable;
struct string_list *str_list = NULL;
enum menu_dirwalk_status walk_status;
menu_dirwalk_set_refresh_cb(menu_displaylist_dirwalk_refresh);
walk_status = menu_dirwalk_request(dir_playlist, "lpl", false,
show_hidden_files, false, MENU_DIRWALK_SORT_DIR_FIRST,
MENU_DIRWALK_TAG_PLAYLIST_MANAGER, &str_list);
if (walk_status == MENU_DIRWALK_PENDING)
{
if (menu_entries_append(list,
msg_hash_to_str(MSG_LOADING), "",
MSG_UNKNOWN, MENU_SETTING_NO_ITEM, 0, 0, NULL))
count++;
return count;
}
if (str_list && str_list->size)
{
unsigned i;
for (i = 0; i < str_list->size; i++)
{
const char *path = str_list->elems[i].data;
const char *playlist_file = NULL;
if (str_list->elems[i].attr.i == FILE_TYPE_DIRECTORY)
continue;
if (!path || !*path)
continue;
playlist_file = path_basename_nocompression(path);
if (!playlist_file || !*playlist_file)
continue;
/* Ignore non-playlist files */
if (!string_is_equal_noncase(path_get_extension(playlist_file),
"lpl"))
continue;
/* Ignore history/favourites
* > content_history + favorites are handled separately
* > music/video/image_history are ignored */
if (
string_ends_with_size(path, "_history.lpl",
strlen(path), STRLEN_CONST("_history.lpl"))
|| !strcmp(playlist_file,
FILE_PATH_CONTENT_FAVORITES))
continue;
menu_entries_append(list, path, "",
MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL);
count++;
}
}
/* Not necessary to check for NULL here */
string_list_free(str_list);
/* Add content history */
if (history_list_enable)
if (g_defaults.content_history)
if (playlist_size(g_defaults.content_history) > 0)
if (menu_entries_append(list,
playlist_get_conf_path(g_defaults.content_history),
"",
MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
/* Add favourites */
if (g_defaults.content_favorites)
if (playlist_size(g_defaults.content_favorites) > 0)
if (menu_entries_append(list,
playlist_get_conf_path(g_defaults.content_favorites),
"",
MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#if defined(HAVE_IMAGEVIEWER) || defined(HAVE_MENU)
/* Add image history */
if (playlist_size(g_defaults.image_history) > 0)
if (menu_entries_append(list,
playlist_get_conf_path(g_defaults.image_history),
"",
MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
/* Add music history */
if (playlist_size(g_defaults.music_history) > 0)
if (menu_entries_append(list,
playlist_get_conf_path(g_defaults.music_history),
"",
MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) || defined(HAVE_WEBMPLAYER)
/* Add video history */
if (playlist_size(g_defaults.video_history) > 0)
if (menu_entries_append(list,
playlist_get_conf_path(g_defaults.video_history),
"",
MENU_ENUM_LABEL_PLAYLIST_MANAGER_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
return count;
}
static bool menu_displaylist_parse_playlist_manager_settings(
menu_handle_t *menu, settings_t *settings, file_list_t *list,
const char *playlist_path)
{
bool is_content_history = false;
bool is_media_history = false;
enum msg_hash_enums right_thumbnail_label_value;
enum msg_hash_enums left_thumbnail_label_value;
const char *playlist_file = NULL;
playlist_t *playlist = NULL;
const char *menu_driver = menu_driver_ident();
if (!playlist_path || !*playlist_path)
return false;
playlist_file = path_basename_nocompression(playlist_path);
if (!playlist_file || !*playlist_file)
return false;
/* Note: We are caching the current playlist
* here so we can get its path and/or modify
* its metadata when performing management
* tasks. We *don't* care about entry order
* at this stage, so we can save a few clock
* cycles by disabling sorting */
menu_displaylist_set_new_playlist(menu, settings, playlist_path, false);
if (!(playlist = playlist_get_cached()))
return false;
/* Check whether this is a content history playlist */
is_content_history = string_ends_with_size(
playlist_path, "_history.lpl", strlen(playlist_path),
STRLEN_CONST("_history.lpl"));
is_media_history =
string_ends_with_size(
playlist_path, "_image_history.lpl", strlen(playlist_path),
STRLEN_CONST("_image_history.lpl"))
|| string_ends_with_size(
playlist_path, "_music_history.lpl", strlen(playlist_path),
STRLEN_CONST("_music_history.lpl"))
|| string_ends_with_size(
playlist_path, "_video_history.lpl", strlen(playlist_path),
STRLEN_CONST("_video_history.lpl"));
/* Label display mode */
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE,
MENU_SETTING_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE, 0, 0, NULL);
/* Thumbnail modes */
right_thumbnail_label_value = MENU_ENUM_LABEL_VALUE_THUMBNAILS;
left_thumbnail_label_value = MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS;
/* > Get label values */
#ifdef HAVE_RGUI
if (!strcmp(menu_driver, "rgui"))
{
right_thumbnail_label_value = MENU_ENUM_LABEL_VALUE_THUMBNAILS_RGUI;
left_thumbnail_label_value = MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_RGUI;
}
#endif
#ifdef HAVE_OZONE
if (!strcmp(menu_driver, "ozone"))
{
right_thumbnail_label_value = MENU_ENUM_LABEL_VALUE_THUMBNAILS;
left_thumbnail_label_value = MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_OZONE;
}
#endif
#ifdef HAVE_MATERIALUI
if (!strcmp(menu_driver, "glui"))
{
right_thumbnail_label_value = MENU_ENUM_LABEL_VALUE_THUMBNAILS_MATERIALUI;
left_thumbnail_label_value = MENU_ENUM_LABEL_VALUE_LEFT_THUMBNAILS_MATERIALUI;
}
#endif
if (!is_media_history)
{
/* > Right thumbnail mode */
menu_entries_append(list,
msg_hash_to_str(right_thumbnail_label_value),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_RIGHT_THUMBNAIL_MODE_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_RIGHT_THUMBNAIL_MODE,
MENU_SETTING_PLAYLIST_MANAGER_RIGHT_THUMBNAIL_MODE, 0, 0, NULL);
/* > Left thumbnail mode */
menu_entries_append(list,
msg_hash_to_str(left_thumbnail_label_value),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_LEFT_THUMBNAIL_MODE_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_LEFT_THUMBNAIL_MODE,
MENU_SETTING_PLAYLIST_MANAGER_LEFT_THUMBNAIL_MODE, 0, 0, NULL);
}
/* Sorting mode
* > Not relevant for history playlists */
if (!is_content_history)
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_SORT_MODE),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_SORT_MODE_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_SORT_MODE,
MENU_SETTING_PLAYLIST_MANAGER_SORT_MODE, 0, 0, NULL);
/* Default core association
* > This is only shown for collection playlists
* (i.e. it is not relevant for history/favourites) */
if ( !is_content_history
&& !string_is_equal(playlist_file, FILE_PATH_CONTENT_FAVORITES))
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_DEFAULT_CORE),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_DEFAULT_CORE,
MENU_SETTING_PLAYLIST_MANAGER_DEFAULT_CORE, 0, 0, NULL);
/* Reset core associations */
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_RESET_CORES),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_RESET_CORES,
MENU_SETTING_ACTION_PLAYLIST_MANAGER_RESET_CORES, 0, 0, NULL);
}
/* Refresh playlist */
if (playlist_scan_refresh_enabled(playlist))
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_REFRESH_PLAYLIST),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_REFRESH_PLAYLIST,
MENU_SETTING_ACTION_PLAYLIST_MANAGER_REFRESH_PLAYLIST, 0, 0, NULL);
/* Clean playlist */
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_CLEAN_PLAYLIST),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_CLEAN_PLAYLIST,
MENU_SETTING_ACTION_PLAYLIST_MANAGER_CLEAN_PLAYLIST, 0, 0, NULL);
/* Delete playlist */
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DELETE_PLAYLIST),
MENU_ENUM_LABEL_DELETE_PLAYLIST_STR,
MENU_ENUM_LABEL_DELETE_PLAYLIST,
MENU_SETTING_ACTION_DELETE_PLAYLIST, 0, 0, NULL);
return true;
}
#ifdef HAVE_NETWORKING
static unsigned menu_displaylist_parse_pl_thumbnail_download_list(
file_list_t *list,
const char *dir_playlist,
bool show_hidden_files)
{
unsigned count = 0;
struct string_list *str_list = NULL;
enum menu_dirwalk_status walk_status;
menu_dirwalk_set_refresh_cb(menu_displaylist_dirwalk_refresh);
walk_status = menu_dirwalk_request(dir_playlist, "lpl", false,
show_hidden_files, false, MENU_DIRWALK_SORT_DIR_FIRST,
MENU_DIRWALK_TAG_PL_THUMBNAILS, &str_list);
if (walk_status == MENU_DIRWALK_PENDING)
{
if (menu_entries_append(list,
msg_hash_to_str(MSG_LOADING), "",
MSG_UNKNOWN, MENU_SETTING_NO_ITEM, 0, 0, NULL))
count++;
return count;
}
if (str_list && str_list->size)
{
unsigned i;
for (i = 0; i < str_list->size; i++)
{
char path_base[NAME_MAX_LENGTH];
const char *path;
if (str_list->elems[i].attr.i == FILE_TYPE_DIRECTORY)
continue;
path = path_basename(str_list->elems[i].data);
if ( (!path || !*path)
|| !string_is_equal_noncase(path_get_extension(path),
"lpl"))
continue;
fill_pathname(path_base, path, "", sizeof(path_base));
menu_entries_append(list, path_base, path,
MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_ENTRY,
FILE_TYPE_DOWNLOAD_PL_THUMBNAIL_CONTENT,
0, 0, NULL);
count++;
}
}
/* Not necessary to check for NULL here */
string_list_free(str_list);
return count;
}
#endif
static unsigned menu_displaylist_parse_content_information(
menu_handle_t *menu, settings_t *settings, file_list_t *info_list)
{
char tmp[PATH_MAX_LENGTH];
char core_name[NAME_MAX_LENGTH];
char content_label[NAME_MAX_LENGTH];
playlist_t *playlist = playlist_get_cached();
unsigned idx = menu->rpl_entry_selection_ptr;
const struct playlist_entry *entry = NULL;
const char *loaded_content_path = path_get(RARCH_PATH_CONTENT);
const char *loaded_core_path = path_get(RARCH_PATH_CORE);
const char *content_path = NULL;
const char *core_path = NULL;
const char *db_name = NULL;
bool playlist_origin = true;
bool playlist_valid = false;
const char *origin_label = NULL;
struct menu_state *menu_st = menu_state_get_ptr();
file_list_t *list = NULL;
unsigned count = 0;
bool content_loaded = !retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL)
&& (loaded_content_path && *loaded_content_path)
&& string_is_equal(menu->deferred_path, loaded_content_path);
bool core_supports_no_game = false;
core_name[0] = '\0';
content_label[0] = '\0';
/* Check the origin menu from which the information
* entry was selected
* > Can only assume a valid playlist if the origin
* was an actual playlist - i.e. cached playlist is
* dubious if information was selected from
* 'Main Menu > Quick Menu' or 'Contentless Cores >
* Quick Menu' */
if (menu_st->entries.list)
list = MENU_LIST_GET(menu_st->entries.list, 0);
if (list && (list->size > 2))
{
origin_label = list->list[list->size - 3].label;
if ( string_is_equal(origin_label, MENU_ENUM_LABEL_MAIN_MENU_STR)
|| string_is_equal(origin_label, MENU_ENUM_LABEL_CONTENTLESS_CORES_TAB_STR)
|| string_is_equal(origin_label, MENU_ENUM_LABEL_DEFERRED_CONTENTLESS_CORES_LIST_STR))
playlist_origin = false;
}
/* If origin menu was a playlist, may rely on
* return value from playlist_get_cached() */
if (playlist_origin)
playlist_valid = !!playlist;
else
{
/* If origin menu was not a playlist, then
* check currently loaded content against
* last cached playlist */
if ( content_loaded
&& (loaded_core_path && *loaded_core_path))
playlist_valid = playlist_index_is_valid(
playlist, idx, loaded_content_path, loaded_core_path);
}
if (playlist_valid)
{
/* If playlist is valid, all information is readily available */
playlist_get_index(playlist, idx, &entry);
if (entry)
{
content_path = entry->path;
core_path = entry->core_path;
db_name = entry->db_name;
if (entry->label && *entry->label)
strlcpy(content_label, entry->label, sizeof(content_label));
else if (content_path && *content_path) /* Create content label from the path */
fill_pathname(content_label, path_basename(content_path), "",
sizeof(content_label));
/* Only display core name if both core name and
* core path are valid */
if ( (entry->core_name && *entry->core_name)
&& (core_path && *core_path)
&& !string_is_equal(core_path, FILE_PATH_DETECT))
strlcpy(core_name, entry->core_name, sizeof(core_name));
/* Use playlist default core if set */
else if (string_is_equal(entry->core_path, FILE_PATH_DETECT)
&& string_is_equal(entry->core_name, FILE_PATH_DETECT))
{
const char* default_core_name = playlist_get_default_core_name(playlist);
const char* default_core_path = playlist_get_default_core_path(playlist);
if ( (default_core_name && *default_core_name)
&& (default_core_path && *default_core_path)
&& !string_is_equal(default_core_name, FILE_PATH_DETECT)
&& !string_is_equal(default_core_path, FILE_PATH_DETECT))
{
strlcpy(core_name, default_core_name, sizeof(core_name));
core_path = default_core_path;
}
}
}
}
else
{
core_info_t *core_info = NULL;
/* No playlist - just extract what we can... */
content_path = loaded_content_path;
core_path = loaded_core_path;
/* Create content label from the path */
fill_pathname(content_label, path_basename(content_path), "",
sizeof(content_label));
if (core_info_find(core_path, &core_info))
{
core_supports_no_game = (core_info->flags
& CORE_INFO_FLAG_SUPPORTS_NO_GAME);
if (core_info->display_name && *core_info->display_name)
strlcpy(core_name, core_info->display_name, sizeof(core_name));
}
}
/* Core name */
if ( *core_name
&& !string_is_equal(core_name, FILE_PATH_DETECT))
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CORE_NAME),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
strlcpy(tmp + _len, core_name, sizeof(tmp) - _len);
if (menu_entries_append(info_list, tmp,
MENU_ENUM_LABEL_CONTENT_INFO_CORE_NAME_STR,
MENU_ENUM_LABEL_CORE_INFORMATION, /* Shortcut to core info */
0, 0, 0, NULL))
count++;
}
#ifdef HAVE_LIBRETRODB
/* Database entry */
if ( *content_label
&& (db_name && *db_name))
{
char *last;
char db_path[PATH_MAX_LENGTH];
fill_pathname_join_special(db_path,
settings->paths.path_content_database,
db_name,
sizeof(db_path));
last = path_get_extension_mutable(db_path);
if (last && *last)
{
last[0] = '.';
last[1] = 'r';
last[2] = 'd';
last[3] = 'b';
last[4] = '\0';
}
if (path_is_valid(db_path))
if (menu_entries_append(info_list,
content_label,
db_path,
MENU_ENUM_LABEL_RDB_ENTRY_DETAIL,
FILE_TYPE_RDB_ENTRY, 0, 0, NULL))
count++;
}
#endif
/* Database */
if (db_name && *db_name)
{
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_DATABASE),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
fill_pathname(tmp + _len, db_name, "", sizeof(tmp) - _len);
if (menu_entries_append(info_list, tmp,
MENU_ENUM_LABEL_CONTENT_INFO_DATABASE_STR,
MENU_ENUM_LABEL_CONTENT_INFO_DATABASE,
0, 0, 0, NULL))
count++;
}
/* If content path is empty and core supports
* contentless operation, skip label/path entries */
if ( !(core_supports_no_game
&& (!content_path || !*content_path)))
{
/* Content label */
size_t _len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_LABEL),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
strlcpy(tmp + _len, *content_label
? content_label
: msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
sizeof(tmp) - _len);
if (menu_entries_append(info_list, tmp,
MENU_ENUM_LABEL_CONTENT_INFO_LABEL_STR,
MENU_ENUM_LABEL_CONTENT_INFO_LABEL,
0, 0, 0, NULL))
count++;
/* Content path */
_len = strlcpy(tmp,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_PATH),
sizeof(tmp));
_len += strlcpy_lit(tmp + _len, ": ", sizeof(tmp) - _len);
strlcpy(tmp + _len, (content_path && *content_path)
? content_path
: msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
sizeof(tmp) - _len);
if (menu_entries_append(info_list, tmp,
MENU_ENUM_LABEL_CONTENT_INFO_PATH_STR,
MENU_ENUM_LABEL_CONTENT_INFO_PATH,
0, 0, 0, NULL))
count++;
}
/* Runtime */
if ( ((settings->uints.playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_PER_CORE)
&& settings->bools.content_runtime_log)
|| ((settings->uints.playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_AGGREGATE)
&& !settings->bools.content_runtime_log_aggregate))
{
runtime_log_t *runtime_log = runtime_log_init(
content_path,
core_path,
settings->paths.directory_runtime_log,
settings->paths.directory_playlist,
(settings->uints.playlist_sublabel_runtime_type == PLAYLIST_RUNTIME_PER_CORE));
if (runtime_log)
{
if (runtime_log_has_runtime(runtime_log))
{
/* Runtime */
tmp[0] = '\0';
runtime_log_get_runtime_str(runtime_log, tmp, sizeof(tmp));
if (*tmp)
if (menu_entries_append(info_list, tmp,
MENU_ENUM_LABEL_CONTENT_INFO_RUNTIME_STR,
MENU_ENUM_LABEL_CONTENT_INFO_RUNTIME,
0, 0, 0, NULL))
count++;
/* Last Played */
tmp[0] = '\0';
runtime_log_get_last_played_str(runtime_log, tmp, sizeof(tmp),
(enum playlist_sublabel_last_played_style_type)settings->uints.playlist_sublabel_last_played_style,
(enum playlist_sublabel_last_played_date_separator_type)settings->uints.menu_timedate_date_separator);
if (*tmp)
if (menu_entries_append(info_list, tmp,
MENU_ENUM_LABEL_CONTENT_INFO_LAST_PLAYED_STR,
MENU_ENUM_LABEL_CONTENT_INFO_LAST_PLAYED,
0, 0, 0, NULL))
count++;
/* Play Count */
tmp[0] = '\0';
snprintf(tmp, sizeof(tmp), "%s %u",
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_SUBLABEL_PLAY_COUNT),
runtime_log->play_count);
if (*tmp)
if (menu_entries_append(info_list, tmp,
MENU_ENUM_LABEL_CONTENT_INFO_PLAY_COUNT_STR,
MENU_ENUM_LABEL_CONTENT_INFO_PLAY_COUNT,
0, 0, 0, NULL))
count++;
}
free(runtime_log);
}
}
#ifdef HAVE_CHEEVOS
/* RetroAchievements Hash */
if ( settings->bools.cheevos_enable
&& settings->arrays.cheevos_token[0]
&& (loaded_content_path && *loaded_content_path))
{
const char *cheevos_hash_str =
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CHEEVOS_HASH);
size_t _len = strlcpy(tmp, cheevos_hash_str, sizeof(tmp) - 4);
tmp[ _len] = ':';
tmp[++_len] = ' ';
tmp[++_len] = '\0';
strlcpy(tmp + _len, rcheevos_get_hash(), sizeof(tmp) - _len);
if (menu_entries_append(info_list, tmp, cheevos_hash_str,
MENU_ENUM_LABEL_VALUE_CONTENT_INFO_CHEEVOS_HASH,
0, 0, 0, NULL))
count++;
}
#endif
return count;
}
static unsigned menu_displaylist_parse_disk_options(file_list_t *list)
{
unsigned count = 0;
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
bool disk_ejected = false;
/* Sanity Check */
if (!sys_info)
return 0;
if (!disk_control_enabled(&sys_info->disk_control))
return 0;
/* Check whether disk is currently ejected */
disk_ejected = disk_control_get_eject_state(&sys_info->disk_control);
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISK_INDEX),
MENU_ENUM_LABEL_DISK_INDEX_STR,
MENU_ENUM_LABEL_DISK_INDEX,
MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_INDEX, 0, 0, NULL))
count++;
if (disk_ejected)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISK_TRAY_INSERT),
MENU_ENUM_LABEL_DISK_TRAY_INSERT_STR,
MENU_ENUM_LABEL_DISK_TRAY_INSERT,
MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_CYCLE_TRAY_STATUS, 0, 0, NULL))
count++;
}
else
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISK_TRAY_EJECT),
MENU_ENUM_LABEL_DISK_TRAY_EJECT_STR,
MENU_ENUM_LABEL_DISK_TRAY_EJECT,
MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_CYCLE_TRAY_STATUS, 0, 0, NULL))
count++;
}
/* If core does not support appending images,
* can stop here */
if (!disk_control_append_enabled(&sys_info->disk_control))
return count;
/* Always show a 'DISK_IMAGE_APPEND' entry
* > If tray is currently shut, this will:
* - Open tray
* - Append disk image
* - Close tray
* > If tray is currently open, this will
* only append a disk image */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND),
MENU_ENUM_LABEL_DISK_IMAGE_APPEND_STR,
MENU_ENUM_LABEL_DISK_IMAGE_APPEND,
MENU_SETTINGS_CORE_DISK_OPTIONS_DISK_IMAGE_APPEND, 0, 0, NULL))
count++;
return count;
}
static int menu_displaylist_parse_audio_device_list(file_list_t *info_list,
const char *info_path)
{
struct menu_state *menu_st = menu_state_get_ptr();
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info_path);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
size_t menu_index = 0;
unsigned count = 0;
int i = -1;
int audio_device_index = -1;
struct string_list *ptr = NULL;
if (!setting)
return 0;
/* Enumerate now rather than showing whatever init cached: devices
* come and go, and the cached list is empty when init failed. */
audio_driver_refresh_devices_list();
if (!audio_driver_get_devices_list((void**)&ptr))
return 0;
/* Get index in the string list */
if (ptr)
audio_device_index = string_list_find_elem(ptr, setting->value.target.string) - 1;
/* Add "Default" even if driver fails and device list is empty */
if (i == -1)
{
bool add = false;
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE),
"",
MENU_ENUM_LABEL_AUDIO_DEVICE_LIST,
MENU_SETTING_DROPDOWN_ITEM_AUDIO_DEVICE,
0, i, NULL))
add = true;
if (add)
{
/* Add checkmark if input is currently
* mapped to this entry */
if (audio_device_index == i)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
for (i = 0; ptr && i < (int)ptr->size; i++)
{
bool add = false;
/* Add menu entry */
if (menu_entries_append(info_list,
ptr->elems[i].data,
ptr->elems[i].data,
MENU_ENUM_LABEL_AUDIO_DEVICE_LIST,
MENU_SETTING_DROPDOWN_ITEM_AUDIO_DEVICE,
0, i, NULL))
add = true;
if (add)
{
/* Add checkmark if input is currently
* mapped to this entry */
if (audio_device_index == i)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
return count;
}
static int menu_displaylist_parse_midi_device_list(file_list_t *info_list,
const char *info_path)
{
struct menu_state *menu_st = menu_state_get_ptr();
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info_path);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
size_t menu_index = 0;
unsigned count = 0;
int i = -1;
int midi_device_index = -1;
struct string_list *ptr = NULL;
if (!setting)
return 0;
if (enum_idx == MENU_ENUM_LABEL_MIDI_INPUT)
ptr = midi_driver_get_avail_inputs();
else
ptr = midi_driver_get_avail_outputs();
if (!ptr)
return 0;
/* Get index in the string list */
midi_device_index = string_list_find_elem(ptr, setting->value.target.string) - 1;
for (i = 0; i < (int)ptr->size; i++)
{
bool add = false;
/* Add menu entry */
if (menu_entries_append(info_list,
ptr->elems[i].data,
ptr->elems[i].data,
MENU_ENUM_LABEL_AUDIO_DEVICE_LIST,
MENU_SETTING_DROPDOWN_ITEM_AUDIO_DEVICE, /* Share common audio for reinit */
0, i, NULL))
add = true;
if (add)
{
/* Add checkmark if input is currently
* mapped to this entry */
if (midi_device_index == i)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
return count;
}
#ifdef HAVE_MICROPHONE
static int menu_displaylist_parse_microphone_device_list(
file_list_t *info_list, const char *info_path)
{
struct menu_state *menu_st = menu_state_get_ptr();
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info_path);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
size_t menu_index = 0;
unsigned count = 0;
int i = -1;
int mic_device_index = -1;
struct string_list *ptr = NULL;
if (!setting)
return 0;
/* Rebuilt on each open, from the configured driver, as the audio
* device list is. */
microphone_driver_refresh_devices_list();
if (!microphone_driver_get_devices_list((void**)&ptr))
return 0;
if (!ptr)
return 0;
/* Get index in the string list */
mic_device_index = string_list_find_elem(ptr, setting->value.target.string) - 1;
/* Add "Default" */
if (i == -1)
{
bool add = false;
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DONT_CARE),
"",
MENU_ENUM_LABEL_MICROPHONE_DEVICE_LIST,
MENU_SETTING_DROPDOWN_ITEM_MICROPHONE_DEVICE,
0, i, NULL))
add = true;
if (add)
{
/* Add checkmark if input is currently
* mapped to this entry */
if (mic_device_index == i)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
for (i = 0; i < (int)ptr->size; i++)
{
bool add = false;
/* Add menu entry */
if (menu_entries_append(info_list,
ptr->elems[i].data,
ptr->elems[i].data,
MENU_ENUM_LABEL_MICROPHONE_DEVICE_LIST,
MENU_SETTING_DROPDOWN_ITEM_MICROPHONE_DEVICE,
0, i, NULL))
add = true;
if (add)
{
/* Add checkmark if input is currently
* mapped to this entry */
if (mic_device_index == i)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
return count;
}
#endif
static int menu_displaylist_parse_input_retropad_bind_list(
file_list_t *info_list, const char *info_path,
settings_t *settings)
{
char name[64];
char id[4];
size_t menu_index = 0;
unsigned count = 0;
unsigned i = 0;
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info_path);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
struct menu_state *menu_st = menu_state_get_ptr();
bool turbo_bind = enum_idx == MENU_ENUM_LABEL_INPUT_TURBO_BIND;
if (!sys_info || !setting)
return 0;
if (turbo_bind && menu_entries_append(info_list,
RARCH_NO_BIND,
"-1",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_INPUT_RETROPAD_BIND,
0, -1, NULL))
{
count++;
menu_index++;
}
for (i = 0; i < RARCH_ANALOG_BIND_LIST_END; i++)
{
int retro_id = input_config_bind_order[i];
snprintf(id, sizeof(id), "%d", retro_id);
strlcpy(name, msg_hash_to_str(input_config_bind_label(retro_id)), sizeof(name));
if (!turbo_bind && i >= RARCH_FIRST_CUSTOM_BIND)
continue;
/* Add menu entry */
if (menu_entries_append(info_list,
name,
id,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_INPUT_RETROPAD_BIND,
0, i, NULL))
{
if ((int)retro_id == *setting->value.target.integer)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
return count;
}
static int menu_displaylist_parse_input_device_type_list(
file_list_t *info_list, const char *info_path)
{
char device_id[10];
const struct retro_controller_description *desc = NULL;
const char *name = NULL;
const char *val_none = NULL;
const char *val_retropad = NULL;
const char *val_retropad_an = NULL;
const char *val_unknown = NULL;
size_t menu_index = 0;
unsigned count = 0;
unsigned i = 0;
unsigned types = 0;
unsigned port = 0;
unsigned current_device = 0;
unsigned devices[128] = {0};
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info_path);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
struct menu_state *menu_st = menu_state_get_ptr();
device_id[0] = '\0';
if (!sys_info || !setting)
return 0;
port = setting->index_offset;
if (port >= MAX_USERS)
return 0;
types = libretro_device_get_size(devices, ARRAY_SIZE(devices), port);
current_device = input_config_get_device(port);
val_none = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE);
val_retropad = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RETROPAD);
val_retropad_an= msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RETROPAD_WITH_ANALOG);
val_unknown = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNKNOWN);
for (i = 0; i < types; i++)
{
snprintf(device_id, sizeof(device_id), "%d", devices[i]);
desc = NULL;
name = NULL;
if (sys_info && port < sys_info->ports.size)
desc = libretro_find_controller_description(
&sys_info->ports.data[port],
devices[i]);
if (desc)
name = desc->desc;
if (!name)
{
/* Find generic name. */
switch (devices[i])
{
case RETRO_DEVICE_NONE:
name = val_none;
break;
case RETRO_DEVICE_JOYPAD:
name = val_retropad;
break;
case RETRO_DEVICE_ANALOG:
name = val_retropad_an;
break;
default:
name = val_unknown;
break;
}
}
/* Add menu entry */
if (menu_entries_append(info_list,
name,
device_id,
MENU_ENUM_LABEL_INPUT_BIND_DEVICE_TYPE,
MENU_SETTING_DROPDOWN_ITEM_INPUT_DEVICE_TYPE,
0, i, NULL))
{
/* Add checkmark if input is currently
* mapped to this entry */
if (current_device == devices[i])
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
return count;
}
static int menu_displaylist_parse_input_select_reserved_device_list(
file_list_t *info_list, const char *info_path,
settings_t *settings)
{
char device_lbl[NAME_MAX_LENGTH];
const char *val_disabled = NULL;
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info_path);
struct menu_state *menu_st = menu_state_get_ptr();
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
size_t menu_index = 0;
unsigned count = 0;
int i = 0;
char reserved_device_name[sizeof(settings->arrays.input_reserved_devices[0])];
bool device_added = false;
device_lbl[0] = '\0';
if (!settings || !setting)
return 0;
val_disabled = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
if (!*settings->arrays.input_reserved_devices[enum_idx - MENU_ENUM_LABEL_INPUT_DEVICE_RESERVED_DEVICE_NAME])
strlcpy(reserved_device_name, val_disabled, sizeof(reserved_device_name));
else
strlcpy(reserved_device_name, settings->arrays.input_reserved_devices[
enum_idx - MENU_ENUM_LABEL_INPUT_DEVICE_RESERVED_DEVICE_NAME],
sizeof(reserved_device_name));
/* List elements: none/disabled, all existing reservations, all existing devices */
for (i = MAX_INPUT_DEVICES + MAX_USERS; i >= 0; --i)
{
device_lbl[0] = '\0';
if (i == MAX_INPUT_DEVICES + MAX_USERS)
strlcpy(device_lbl, val_disabled, sizeof(device_lbl));
else if (i < MAX_INPUT_DEVICES)
{
const char *device_name = input_config_get_device_display_name(i)
? input_config_get_device_display_name(i)
: input_config_get_device_name(i);
if (device_name && *device_name)
{
unsigned idx = input_config_get_device_name_index(i);
size_t _len = strlcpy(device_lbl, device_name,
sizeof(device_lbl));
/* If idx is non-zero, it's part of a set*/
if (idx > 0)
snprintf(device_lbl + _len,
sizeof(device_lbl) - _len, " (#%u)", idx);
}
}
else
{
if (*settings->arrays.input_reserved_devices[i-MAX_INPUT_DEVICES])
{
const char *str = settings->arrays.input_reserved_devices[i-MAX_INPUT_DEVICES];
if (((str[0] >= '0' && str[0] <= '9') || (str[0] >= 'a' && str[0] <= 'f') || (str[0] >= 'A' && str[0] <= 'F'))
&& ((str[1] >= '0' && str[1] <= '9') || (str[1] >= 'a' && str[1] <= 'f') || (str[1] >= 'A' && str[1] <= 'F'))
&& ((str[2] >= '0' && str[2] <= '9') || (str[2] >= 'a' && str[2] <= 'f') || (str[2] >= 'A' && str[2] <= 'F'))
&& ((str[3] >= '0' && str[3] <= '9') || (str[3] >= 'a' && str[3] <= 'f') || (str[3] >= 'A' && str[3] <= 'F'))
&& str[4] == ':'
&& ((str[5] >= '0' && str[5] <= '9') || (str[5] >= 'a' && str[5] <= 'f') || (str[5] >= 'A' && str[5] <= 'F'))
&& ((str[6] >= '0' && str[6] <= '9') || (str[6] >= 'a' && str[6] <= 'f') || (str[6] >= 'A' && str[6] <= 'F'))
&& ((str[7] >= '0' && str[7] <= '9') || (str[7] >= 'a' && str[7] <= 'f') || (str[7] >= 'A' && str[7] <= 'F'))
&& ((str[8] >= '0' && str[8] <= '9') || (str[8] >= 'a' && str[8] <= 'f') || (str[8] >= 'A' && str[8] <= 'F'))
&& str[9] == ' ')
strlcpy(device_lbl, &str[10], sizeof(reserved_device_name));
else
strlcpy(device_lbl, str, sizeof(reserved_device_name));
}
}
if (*device_lbl)
{
size_t previous_position;
if (file_list_search(info_list, device_lbl, &previous_position))
continue;
/* Add menu entry */
if (menu_entries_append(info_list,
device_lbl, device_lbl,
MSG_UNKNOWN,
MENU_SETTING_DROPDOWN_ITEM_INPUT_SELECT_RESERVED_DEVICE,
0, menu_index, NULL))
{
/* Add checkmark if input is currently
* mapped to this entry - with or without vid:pid prefix */
if ( string_is_equal(device_lbl, &reserved_device_name[10])
|| string_is_equal(device_lbl, reserved_device_name))
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
device_added = true;
}
count++;
menu_index++;
}
}
}
/* if nothing is configured, select None by default */
if (!device_added)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[0].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = 0;
}
return count;
}
#ifdef ANDROID
static int menu_displaylist_parse_input_select_physical_keyboard_list(
file_list_t *info_list, const char *info_path,
settings_t *settings)
{
char device_lbl[128];
const char *val_disabled = NULL;
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info_path);
struct menu_state *menu_st = menu_state_get_ptr();
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
size_t menu_index = 0;
unsigned count = 0;
int i = 0;
char keyboard[sizeof(settings->arrays.input_android_physical_keyboard)];
bool keyboard_added = false;
bool is_android_driver = string_is_equal(input_driver_get_ident(), "android");
device_lbl[0] = '\0';
if (!settings || !setting || !is_android_driver)
return 0;
val_disabled = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NONE);
if (!*settings->arrays.input_android_physical_keyboard)
strlcpy(keyboard, val_disabled, sizeof(keyboard));
else
{
const char *name = settings->arrays.input_android_physical_keyboard;
size_t len = strlen(name);
if (len > 10
&& ((name[0] >= '0' && name[0] <= '9') || (name[0] >= 'a' && name[0] <= 'f') || (name[0] >= 'A' && name[0] <= 'F'))
&& ((name[1] >= '0' && name[1] <= '9') || (name[1] >= 'a' && name[1] <= 'f') || (name[1] >= 'A' && name[1] <= 'F'))
&& ((name[2] >= '0' && name[2] <= '9') || (name[2] >= 'a' && name[2] <= 'f') || (name[2] >= 'A' && name[2] <= 'F'))
&& ((name[3] >= '0' && name[3] <= '9') || (name[3] >= 'a' && name[3] <= 'f') || (name[3] >= 'A' && name[3] <= 'F'))
&& name[4] == ':'
&& ((name[5] >= '0' && name[5] <= '9') || (name[5] >= 'a' && name[5] <= 'f') || (name[5] >= 'A' && name[5] <= 'F'))
&& ((name[6] >= '0' && name[6] <= '9') || (name[6] >= 'a' && name[6] <= 'f') || (name[6] >= 'A' && name[6] <= 'F'))
&& ((name[7] >= '0' && name[7] <= '9') || (name[7] >= 'a' && name[7] <= 'f') || (name[7] >= 'A' && name[7] <= 'F'))
&& ((name[8] >= '0' && name[8] <= '9') || (name[8] >= 'a' && name[8] <= 'f') || (name[8] >= 'A' && name[8] <= 'F'))
&& name[9] == ' ')
strlcpy(keyboard, &name[10], sizeof(keyboard));
else
strlcpy(keyboard, name, sizeof(keyboard));
}
for (i = MAX_INPUT_DEVICES; i >= -1; --i)
{
device_lbl[0] = '\0';
if (i < 0)
strlcpy(device_lbl, keyboard, sizeof(device_lbl));
else if (i == MAX_INPUT_DEVICES)
strlcpy(device_lbl, val_disabled, sizeof(device_lbl));
else if (i < MAX_INPUT_DEVICES)
{
/*
* Skip devices that do not look like keyboards
*/
if (!android_input_can_be_keyboard(input_driver_current_data(), i))
continue;
const char *device_name = input_config_get_device_display_name(i)
? input_config_get_device_display_name(i)
: input_config_get_device_name(i);
if (device_name && *device_name)
{
unsigned idx = input_config_get_device_name_index(i);
size_t _len = strlcpy(device_lbl, device_name,
sizeof(device_lbl));
/* If idx is non-zero, it's part of a set*/
if (idx > 0)
snprintf(device_lbl + _len,
sizeof(device_lbl) - _len, " (#%u)", idx);
}
}
if (*device_lbl)
{
size_t previous_position;
if (file_list_search(info_list, device_lbl, &previous_position))
continue;
/* Add menu entry */
if (menu_entries_append(info_list,
device_lbl,
device_lbl,
MSG_UNKNOWN,
MENU_SETTING_DROPDOWN_ITEM_INPUT_SELECT_PHYSICAL_KEYBOARD,
0, menu_index, NULL))
{
/* Add checkmark if input is currently
* mapped to this entry */
if (string_is_equal(device_lbl, keyboard))
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
keyboard_added = true;
}
count++;
menu_index++;
}
}
}
/* if nothing is configured, select None by default */
if (!keyboard_added)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[0].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = 0;
}
return count;
}
#endif
static int menu_displaylist_parse_input_description_list(
menu_displaylist_info_t *info, settings_t *settings)
{
size_t i, j;
char entry_lbl[21];
unsigned user_idx;
unsigned btn_idx;
unsigned current_remap_idx;
unsigned mapped_port;
unsigned count = 0;
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
size_t menu_index = 0;
struct menu_state *menu_st = menu_state_get_ptr();
entry_lbl[0] = '\0';
if (!settings)
return 0;
/* Determine user/button indices */
user_idx = (info->type - MENU_SETTINGS_INPUT_DESC_BEGIN) / RARCH_ANALOG_BIND_LIST_END;
btn_idx = (info->type - MENU_SETTINGS_INPUT_DESC_BEGIN) - RARCH_ANALOG_BIND_LIST_END * user_idx;
if ( (user_idx >= MAX_USERS)
|| (btn_idx >= RARCH_CUSTOM_BIND_LIST_END))
return 0;
mapped_port = settings->uints.input_remap_ports[user_idx];
if (mapped_port >= MAX_USERS)
return 0;
/* Get current mapping for selected button */
current_remap_idx = settings->uints.input_remap_ids[user_idx][btn_idx];
if ( current_remap_idx >= RARCH_CUSTOM_BIND_LIST_END
|| (!sys_info->input_desc_btn[mapped_port][current_remap_idx] || !*sys_info->input_desc_btn[mapped_port][current_remap_idx]))
current_remap_idx = RARCH_UNMAPPED;
/* An annoyance: Menu entries do not have
* enough parameters to pass on all the information
* required to interpret a remap selection without
* adding workarounds...
* We need to record the current user/button indices,
* and so have to convert 'info->type' to a string
* and pass it as the entry label... */
snprintf(entry_lbl, sizeof(entry_lbl), "%u", info->type);
/* Add 'unmapped' entry */
if (menu_entries_append(info->list,
RARCH_NO_BIND,
entry_lbl,
MENU_ENUM_LABEL_INPUT_DESCRIPTION,
MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION,
0, RARCH_UNMAPPED, NULL))
{
/* Add checkmark if input is currently unmapped */
if (current_remap_idx == RARCH_UNMAPPED)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
/* Loop over core input definitions */
for (j = 0; j < RARCH_CUSTOM_BIND_LIST_END; j++)
{
const char *input_desc_btn;
i = (j < RARCH_ANALOG_BIND_LIST_END) ? input_config_bind_order[j] : j;
input_desc_btn = sys_info->input_desc_btn[mapped_port][i];
/* Check whether an input is defined for
* this button */
if (input_desc_btn && *input_desc_btn)
{
char input_description[NAME_MAX_LENGTH];
/* > Up to RARCH_FIRST_CUSTOM_BIND, inputs
* are buttons - description can be used
* directly
* > Above RARCH_FIRST_CUSTOM_BIND, inputs
* are analog axes - have to add +/-
* indicators */
size_t _len = strlcpy(input_description, input_desc_btn,
sizeof(input_description));
if (i >= RARCH_FIRST_CUSTOM_BIND)
{
if ((i % 2) == 0)
input_description[ _len] = '+';
else
input_description[ _len] = '-';
input_description [++_len] = '\0';
}
if (!*input_description)
continue;
/* Add menu entry */
if (menu_entries_append(info->list,
input_description,
entry_lbl,
MENU_ENUM_LABEL_INPUT_DESCRIPTION,
MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION,
0, i, NULL))
{
/* Add checkmark if input is currently
* mapped to this entry */
if (current_remap_idx == i)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
}
return count;
}
#ifdef HAVE_NETWORKING
static unsigned menu_displaylist_parse_netplay_mitm_server_list(
file_list_t *info_list, const char *netplay_mitm_server)
{
size_t i;
unsigned count = 0;
struct menu_state *menu_st = menu_state_get_ptr();
for (i = 0; i < ARRAY_SIZE(netplay_mitm_server_list); i++)
{
const mitm_server_t *server = &netplay_mitm_server_list[i];
if (menu_entries_append(info_list,
msg_hash_to_str(server->description), server->name,
MENU_ENUM_LABEL_NETPLAY_MITM_SERVER_LOCATION,
MENU_SETTING_DROPDOWN_ITEM_NETPLAY_MITM_SERVER,
0, i, NULL))
{
if (string_is_equal(server->name, netplay_mitm_server))
{
menu_file_list_cbs_t *cbs =
(menu_file_list_cbs_t*)info_list->list[count].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = count;
}
count++;
}
}
return count;
}
#endif
static int menu_displaylist_parse_input_description_kbd_list(
file_list_t *info_list, unsigned info_type, settings_t *settings)
{
size_t i;
char entry_lbl[21];
unsigned current_key_id;
unsigned user_idx, btn_idx;
unsigned count = 0;
size_t menu_index = 0;
struct menu_state *menu_st = menu_state_get_ptr();
entry_lbl[0] = '\0';
if (!settings)
return 0;
/* Determine user/button indices */
user_idx = (info_type - MENU_SETTINGS_INPUT_DESC_KBD_BEGIN) / RARCH_ANALOG_BIND_LIST_END;
btn_idx = (info_type - MENU_SETTINGS_INPUT_DESC_KBD_BEGIN) - RARCH_ANALOG_BIND_LIST_END * user_idx;
if ( (user_idx >= MAX_USERS)
|| (btn_idx >= RARCH_CUSTOM_BIND_LIST_END))
return 0;
/* Get current mapping for selected button */
current_key_id = settings->uints.input_keymapper_ids[user_idx][btn_idx];
if (current_key_id >= (RARCH_MAX_KEYS + MENU_SETTINGS_INPUT_DESC_KBD_BEGIN))
current_key_id = RETROK_FIRST;
/* An annoyance: Menu entries do not have
* enough parameters to pass on all the information
* required to interpret a remap selection without
* adding workarounds...
* We need to record the current user/button indices,
* and so have to convert 'info_type' to a string
* and pass it as the entry label... */
snprintf(entry_lbl, sizeof(entry_lbl), "%u", info_type);
/* Loop over keyboard keys */
for (i = 0; i < RARCH_MAX_KEYS; i++)
{
char input_description[NAME_MAX_LENGTH];
unsigned key_id = key_descriptors[i].key;
const char *key_label = key_descriptors[i].desc;
if (!key_label || !*key_label)
continue;
if (key_id == RETROK_FIRST)
strlcpy(input_description, RARCH_NO_BIND, sizeof(input_description));
else
{
snprintf(input_description, sizeof(input_description), /* Format string below */
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_KEYBOARD_KEY), key_label);
}
/* Add menu entry */
if (menu_entries_append(info_list, input_description, entry_lbl,
MENU_ENUM_LABEL_INPUT_DESCRIPTION_KBD,
MENU_SETTING_DROPDOWN_ITEM_INPUT_DESCRIPTION_KBD,
0, key_id, NULL))
{
/* Add checkmark if input is currently
* mapped to this entry */
if (current_key_id == key_id)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info_list->list[menu_index].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = menu_index;
}
count++;
menu_index++;
}
}
return count;
}
static int menu_displaylist_parse_playlist_generic(
menu_handle_t *menu,
menu_displaylist_info_t *info,
settings_t *settings,
const char *playlist_name,
size_t playlist_name_size,
const char *playlist_path,
bool is_collection,
bool sort_enabled,
int *ret)
{
unsigned count = 0;
playlist_t *playlist = NULL;
menu_displaylist_set_new_playlist(menu, settings,
playlist_path, sort_enabled);
if ((playlist = playlist_get_cached()))
{
if ((count = menu_displaylist_parse_playlist(info->list, info->path,
playlist, settings, playlist_name, playlist_name_size, is_collection)) == 0)
info->flags |= MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
*ret = 0;
}
else
/* Unreadable, or still being read: either way the list must not
* be left empty. generic_menu_entry_action() takes its cbs
* from the selected entry and gates the rebuild on
* selection_buf_size, so with no entries back is never
* dispatched and nothing repopulates - a blank screen the user
* cannot leave. The placeholder keeps both alive. Only
* reachable when a read yields, which is Android/SAF speed,
* not local stdio. */
info->flags |= MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
return count;
}
#ifdef HAVE_BLUETOOTH
/* The devices the last scan found - their places in the list are the
* driver's numbers for them - or that none were; then a scan again. */
static unsigned bluetooth_list_fill(file_list_t *list)
{
unsigned i, count;
struct string_list *device_list = string_list_new();
const char *msg_connect_bluetooth =
msg_hash_to_str(MENU_ENUM_LABEL_CONNECT_BLUETOOTH);
if (!device_list)
return 0;
driver_bluetooth_get_devices(device_list);
for (i = 0; i < device_list->size; i++)
menu_entries_append(list,
device_list->elems[i].data, msg_connect_bluetooth,
MENU_ENUM_LABEL_CONNECT_BLUETOOTH,
MENU_BLUETOOTH, 0, 0, NULL);
/* never left empty: a list with nothing in it cannot be left */
if (device_list->size == 0)
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_BT_DEVICES_FOUND),
MENU_ENUM_LABEL_NO_BT_DEVICES_FOUND_STR,
MENU_ENUM_LABEL_NO_BT_DEVICES_FOUND,
0, 0, 0, NULL);
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BLUETOOTH_SCAN),
MENU_ENUM_LABEL_BLUETOOTH_SCAN_STR,
MENU_ENUM_LABEL_BLUETOOTH_SCAN,
0, 0, 0, NULL);
count = (unsigned)device_list->size + (device_list->size ? 1 : 2);
string_list_free(device_list);
return count;
}
static void bluetooth_scan_callback(retro_task_t *task,
void *task_data, void *user_data, const char *err)
{
const char *path = NULL;
const char *label = NULL;
unsigned menu_type = 0;
struct menu_state *menu_st = menu_state_get_ptr();
menu_list_t *menu_list = menu_st->entries.list;
file_list_t *selection_buf = menu_list ? MENU_LIST_GET_SELECTION(menu_list, 0) : NULL;
menu_entries_get_last_stack(&path, &label, &menu_type, NULL, NULL);
/* Don't push the results if we left the bluetooth menu */
if ( !selection_buf
|| !string_is_equal(label,
MENU_ENUM_LABEL_DEFERRED_BLUETOOTH_SETTINGS_LIST_STR))
return;
menu_entries_clear(selection_buf);
bluetooth_list_fill(selection_buf);
}
bool menu_displaylist_bluetooth_scan(void)
{
return task_push_bluetooth_scan(bluetooth_scan_callback);
}
#endif
#if defined(HAVE_NETWORKING) && defined(HAVE_WIFI)
static void wifi_scan_callback(retro_task_t *task,
void *task_data,
void *user_data, const char *err)
{
struct menu_state *menu_st = menu_state_get_ptr();
menu_st->flags |= MENU_ST_FLAG_PREVENT_POPULATE
| MENU_ST_FLAG_ENTRIES_NEED_REFRESH;
}
#endif
/**
* 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.
**/
static bool menu_displaylist_refresh(struct menu_state *menu_st, file_list_t *list)
{
size_t list_size = 0;
if (list->size)
menu_entries_build_scroll_indices(menu_st, list);
if (menu_st->entries.list)
list_size = MENU_LIST_GET_SELECTION(menu_st->entries.list, 0)->size;
if (list_size)
{
size_t selection = menu_st->selection_ptr;
if (selection >= list_size)
{
size_t idx = list_size - 1;
menu_st->selection_ptr = idx;
if (menu_st->driver_ctx->navigation_set)
menu_st->driver_ctx->navigation_set(menu_st->userdata, true);
}
}
else
{
bool pending_push = true;
menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
}
return true;
}
#ifdef HAVE_NETWORKING
/* Put the cursor back on the Content Downloader directory the user
* just backed out of. Called for both the stack push and the rebuild
* that follows the download, hence clearing the name on a match only:
* the push has nothing to match against yet. */
static void menu_displaylist_restore_core_content_dir(
struct menu_state *menu_st, file_list_t *list)
{
size_t i;
menu_handle_t *menu = menu_st->driver_data;
if (!list || !menu || !menu->core_content_dir[0])
return;
for (i = 0; i < list->size; i++)
{
if (!string_is_equal(list->list[i].path, menu->core_content_dir))
continue;
menu_st->selection_ptr = i;
if (menu_st->driver_ctx && menu_st->driver_ctx->navigation_set)
menu_st->driver_ctx->navigation_set(menu_st->userdata, true);
menu->core_content_dir[0] = '\0';
break;
}
}
#endif
bool menu_displaylist_process(menu_displaylist_info_t *info)
{
#ifdef HAVE_NETWORKING
settings_t *settings = config_get_ptr();
#endif
struct menu_state *menu_st = menu_state_get_ptr();
uint32_t info_flags = info->flags;
file_list_t *info_list = info->list;
if (info_flags & MD_FLAG_NEED_NAVIGATION_CLEAR)
{
bool pending_push = true;
menu_driver_ctl(MENU_NAVIGATION_CTL_CLEAR, &pending_push);
}
if (info_flags & MD_FLAG_NEED_ENTRIES_REFRESH)
menu_st->flags |= MENU_ST_FLAG_ENTRIES_NEED_REFRESH;
if (info_flags & MD_FLAG_NEED_SORT)
file_list_sort_on_alt(info_list);
#ifdef HAVE_NETWORKING
if ( settings->bools.menu_show_core_updater
&& !settings->bools.kiosk_mode_enable)
{
if (info_flags & MD_FLAG_DOWNLOAD_CORE)
{
#ifdef HAVE_UPDATE_CORES
menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE),
MENU_ENUM_LABEL_CORE_UPDATER_LIST_STR,
MENU_ENUM_LABEL_CORE_UPDATER_LIST,
MENU_SETTING_ACTION, 0, 0, NULL);
#endif
#if !TARGET_OS_IPHONE
menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SIDELOAD_CORE_LIST),
MENU_ENUM_LABEL_SIDELOAD_CORE_LIST_STR,
MENU_ENUM_LABEL_SIDELOAD_CORE_LIST,
MENU_SETTING_ACTION, 0, 0, NULL);
#endif
}
}
#endif
if (info_flags & MD_FLAG_PUSH_BUILTIN_CORES)
{
#if defined(HAVE_VIDEOPROCESSOR)
menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_START_VIDEO_PROCESSOR),
MENU_ENUM_LABEL_START_VIDEO_PROCESSOR_STR,
MENU_ENUM_LABEL_START_VIDEO_PROCESSOR,
MENU_SETTING_ACTION, 0, 0, NULL);
#endif
#if defined(HAVE_NETWORKING) && defined(HAVE_NETWORKGAMEPAD)
menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_START_NET_RETROPAD),
MENU_ENUM_LABEL_START_NET_RETROPAD_STR,
MENU_ENUM_LABEL_START_NET_RETROPAD,
MENU_SETTING_ACTION, 0, 0, NULL);
#endif
}
if (info_flags & MD_FLAG_NEED_REFRESH)
menu_displaylist_refresh(menu_st, info_list);
if (info_flags & MD_FLAG_NEED_CLEAR)
menu_st->selection_ptr = 0;
#ifdef HAVE_NETWORKING
/* When going back from the online updater core content,
* make sure we restore the active core content selection. */
if (string_is_equal(info->label, MENU_ENUM_LABEL_DEFERRED_CORE_CONTENT_DIRS_LIST_STR))
menu_displaylist_restore_core_content_dir(menu_st, info_list);
#endif
if (info_flags & MD_FLAG_NEED_PUSH)
{
if (info_flags & MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES)
{
/* Empty because a deferred read is still LOADING, not
* because the playlist has no entries - say so, with the
* entry the deferred dirwalk uses; the pump replaces it. */
if (playlist_init_cached_pending())
menu_entries_append(info_list,
msg_hash_to_str(MSG_LOADING), "",
MSG_UNKNOWN, MENU_SETTING_NO_ITEM, 0, 0, NULL);
else
menu_entries_append(info_list,
msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE),
MENU_ENUM_LABEL_NO_PLAYLIST_ENTRIES_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_PLAYLIST_ENTRIES_AVAILABLE,
MENU_INFO_MESSAGE, 0, 0, NULL);
}
if (menu_st->driver_ctx && menu_st->driver_ctx->populate_entries)
menu_st->driver_ctx->populate_entries(
menu_st->userdata, info->path,
info->label, info->type);
}
return true;
}
void menu_displaylist_info_free(menu_displaylist_info_t *info)
{
if (!info)
return;
if (info->exts)
free(info->exts);
if (info->path_b)
free(info->path_b);
if (info->path_c)
free(info->path_c);
if (info->label)
free(info->label);
if (info->path)
free(info->path);
info->exts = NULL;
info->path_b = NULL;
info->path_c = NULL;
info->label = NULL;
info->path = NULL;
}
void menu_displaylist_info_init(menu_displaylist_info_t *info)
{
if (!info)
return;
info->enum_idx = MSG_UNKNOWN;
info->type = 0;
info->type_default = 0;
info->flags = 0;
info->directory_ptr = 0;
info->label = NULL;
info->path = NULL;
info->path_b = NULL;
info->path_c = NULL;
info->exts = NULL;
info->list = NULL;
info->setting = NULL;
}
typedef struct menu_displaylist_build_info
{
enum msg_hash_enums enum_idx;
enum menu_displaylist_parse_type parse_type;
} menu_displaylist_build_info_t;
typedef struct menu_displaylist_build_info_selective
{
enum msg_hash_enums enum_idx;
enum menu_displaylist_parse_type parse_type;
bool checked;
} menu_displaylist_build_info_selective_t;
static unsigned populate_playlist_thumbnail_mode_dropdown_list(
file_list_t *list, enum playlist_thumbnail_id thumbnail_id)
{
unsigned count = 0;
struct menu_state *menu_st = menu_state_get_ptr();
playlist_t *playlist = playlist_get_cached();
if (list && playlist)
{
size_t i;
/* Get currently selected thumbnail mode */
enum playlist_thumbnail_mode current_thumbnail_mode =
playlist_get_thumbnail_mode(playlist, thumbnail_id);
/* Get appropriate menu_settings_type (right/left) */
enum menu_settings_type settings_type =
(thumbnail_id == PLAYLIST_THUMBNAIL_RIGHT)
? MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_RIGHT_THUMBNAIL_MODE
: MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_LEFT_THUMBNAIL_MODE;
/* Loop over all thumbnail modes */
for (i = 0; i <= (unsigned)PLAYLIST_THUMBNAIL_MODE_LOGOS; i++)
{
enum msg_hash_enums label_value;
enum playlist_thumbnail_mode thumbnail_mode =
(enum playlist_thumbnail_mode)i;
/* Get appropriate entry label */
switch (thumbnail_mode)
{
case PLAYLIST_THUMBNAIL_MODE_OFF:
label_value = MENU_ENUM_LABEL_VALUE_OFF;
break;
case PLAYLIST_THUMBNAIL_MODE_SCREENSHOTS:
label_value = MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_SCREENSHOTS;
break;
case PLAYLIST_THUMBNAIL_MODE_TITLE_SCREENS:
label_value = MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_TITLE_SCREENS;
break;
case PLAYLIST_THUMBNAIL_MODE_BOXARTS:
label_value = MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_BOXARTS;
break;
case PLAYLIST_THUMBNAIL_MODE_LOGOS:
label_value = MENU_ENUM_LABEL_VALUE_THUMBNAIL_MODE_LOGOS;
break;
default:
/* PLAYLIST_THUMBNAIL_MODE_DEFAULT */
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_THUMBNAIL_MODE_DEFAULT;
break;
}
/* Add entry */
if (menu_entries_append(list,
msg_hash_to_str(label_value),
"",
MENU_ENUM_LABEL_NO_ITEMS,
settings_type,
0, 0, NULL))
count++;
/* Add checkmark if item is currently selected */
if (current_thumbnail_mode == thumbnail_mode)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
}
return count;
}
static unsigned menu_displaylist_parse_manual_content_scan_list(
file_list_t *info_list)
{
unsigned count = 0;
settings_t *settings = config_get_ptr();
/* Content directory */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_DIR),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DIR_STR,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DIR,
MENU_SETTING_MANUAL_CONTENT_SCAN_DIR, 0, 0, NULL))
count++;
/* Scan method - automatic or custom (more entries) */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_METHOD),
MENU_ENUM_LABEL_SCAN_METHOD_STR,
MENU_ENUM_LABEL_SCAN_METHOD,
MENU_SETTING_SCAN_METHOD, 0, 0, NULL))
count++;
if (manual_content_scan_get_scan_method_enum() == MANUAL_CONTENT_SCAN_METHOD_CUSTOM)
{
/* DB usage - matching strategy */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_USE_DB),
MENU_ENUM_LABEL_SCAN_USE_DB_STR,
MENU_ENUM_LABEL_SCAN_USE_DB,
MENU_SETTING_SCAN_USE_DB, 0, 0, NULL))
count++;
if (manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_DAT_LOOSE ||
manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_DAT_STRICT)
{
/* Arcade DAT file - only if DAT file is used*/
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_DAT_FILE, PARSE_ONLY_PATH,
false) == 0)
count++;
}
else if (manual_content_scan_get_scan_use_db_enum() != MANUAL_CONTENT_SCAN_USE_DB_NONE)
{
/* Database selection */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_DB_SELECT),
MENU_ENUM_LABEL_SCAN_DB_SELECT_STR,
MENU_ENUM_LABEL_SCAN_DB_SELECT,
MENU_SETTING_SCAN_DB_SELECT, 0, 0, NULL))
count++;
}
/* Target playlist (system name in old terminology) */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_SYSTEM_NAME),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME_STR,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME,
MENU_SETTING_MANUAL_CONTENT_SCAN_SYSTEM_NAME, 0, 0, NULL))
count++;
if (manual_content_scan_get_menu_system_name_type() == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM)
{
/* Custom target playlist */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM, PARSE_ONLY_STRING,
false) == 0)
count++;
}
if (manual_content_scan_get_menu_system_name_type() == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CUSTOM ||
manual_content_scan_get_menu_system_name_type() == MANUAL_CONTENT_SCAN_SYSTEM_NAME_CONTENT_DIR)
{
/* DB reference skipping only makes sense if there is a DB used */
if (manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_STRICT ||
manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_LOOSE)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_SCAN_OMIT_DB_REF, PARSE_ONLY_BOOL,
false) == 0)
count++;
}
}
/* Core name */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_CORE_NAME),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME_STR,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_CORE_NAME,
MENU_SETTING_MANUAL_CONTENT_SCAN_CORE_NAME, 0, 0, NULL))
count++;
/* File extensions */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_FILE_EXTS, PARSE_ONLY_STRING,
false) == 0)
count++;
/* Search recursively */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SEARCH_RECURSIVELY, PARSE_ONLY_BOOL,
false) == 0)
count++;
if (*(manual_content_scan_get_search_recursively_ptr()) == false)
{
/* Scan only one file */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_SCAN_SINGLE_FILE, PARSE_ONLY_BOOL,
false) == 0)
count++;
}
/* Search inside archive files */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_SEARCH_ARCHIVES, PARSE_ONLY_BOOL,
false) == 0)
count++;
/* Arcade DAT filter is merged with DB usage setting */
/* Hiding validate / overwrite in cases when target playlist can not be determined in advance */
if ((manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_STRICT ||
manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_LOOSE) &&
(manual_content_scan_get_scan_db_select_enum() == MANUAL_CONTENT_SCAN_SELECT_DB_AUTO ||
manual_content_scan_get_scan_db_select_enum() == MANUAL_CONTENT_SCAN_SELECT_DB_AUTO_FIRST_MATCH ) &&
manual_content_scan_get_menu_system_name_type() == MANUAL_CONTENT_SCAN_SYSTEM_NAME_AUTO)
{
;
}
else
{
/* Overwrite playlist */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_OVERWRITE, PARSE_ONLY_BOOL,
false) == 0)
count++;
/* Validate existing entries */
if (!(*manual_content_scan_get_overwrite_playlist_ptr())
&& MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_VALIDATE_ENTRIES, PARSE_ONLY_BOOL,
false) == 0)
count++;
}
}
/* Scan without core match and CRC duplicate check only makes sense if there is a DB used */
if (manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_STRICT ||
manual_content_scan_get_scan_use_db_enum() == MANUAL_CONTENT_SCAN_USE_DB_LOOSE)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_SCAN_WITHOUT_CORE_MATCH, PARSE_ONLY_BOOL,
false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info_list,
MENU_ENUM_LABEL_SCAN_SERIAL_AND_CRC, PARSE_ONLY_BOOL,
false) == 0)
count++;
}
/* Start scan */
if (menu_entries_append(info_list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_START),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_START_STR,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_START,
MENU_SETTING_ACTION_MANUAL_CONTENT_SCAN_START, 0, 0, NULL))
count++;
return count;
}
#ifdef HAVE_CDROM
static int menu_displaylist_parse_disc_info(file_list_t *info_list,
unsigned type)
{
unsigned i;
unsigned count = 0;
struct string_list *list = cdrom_get_available_drives();
const char *msg_drive_number = msg_hash_to_str(MSG_DRIVE_NUMBER);
for (i = 0; list && i < list->size; i++)
{
char drive[2];
char drive_string[NAME_MAX_LENGTH] = {0};
/* snprintf() reports the length it would have written, which a
* long enough translation of msg_drive_number can carry past the
* buffer, so take the length that landed. */
int _ret = snprintf(drive_string, sizeof(drive_string),
msg_drive_number, i + 1);
size_t _len = (_ret < 0 || (size_t)_ret >= sizeof(drive_string))
? sizeof(drive_string) - 1
: (size_t)_ret;
_len += strlcpy_lit(drive_string + _len, ": ",
sizeof(drive_string) - _len);
if (_len < sizeof(drive_string))
strlcpy( drive_string + _len,
list->elems[i].data,
sizeof(drive_string) - _len);
drive[0] = list->elems[i].attr.i;
drive[1] = '\0';
if (menu_entries_append(info_list,
drive_string, drive, MSG_UNKNOWN,
type, 0, i, NULL))
count++;
}
if (list)
string_list_free(list);
return count;
}
#endif
static unsigned menu_displaylist_populate_subsystem(
const struct retro_subsystem_info* subsystem,
file_list_t *list, bool menu_show_sublabels)
{
char star_char[16];
unsigned count = 0;
/* Note: Create this string here explicitly (rather than
* using a #define elsewhere) since we need to be aware of
* its length... */
#if defined(__APPLE__)
/* UTF-8 support is currently broken on Apple devices... */
static const char utf8_star_char[] = "*";
#else
/* <BLACK STAR>
* UCN equivalent: "\u2605" */
static const char utf8_star_char[] = "\xE2\x98\x85";
#endif
int i = 0;
#if defined(HAVE_RGUI)
const char *menu_driver = menu_driver_ident();
bool is_rgui = !strcmp(menu_driver, "rgui");
/* Select appropriate 'star' marker for subsystem menu entries
* (i.e. RGUI does not support unicode, so use a 'standard'
* character fallback) */
if (is_rgui)
{
star_char[0] = '*';
star_char[1] = '\0';
}
else
#endif
strlcpy(star_char, utf8_star_char, sizeof(star_char));
if (menu_displaylist_has_subsystems())
{
runloop_state_t *runloop_st = runloop_state_get_ptr();
for (i = 0; i < (int)runloop_st->subsystem_current_count; i++, subsystem++)
{
char s[PATH_MAX_LENGTH];
if (content_get_subsystem() == i)
{
if (content_get_subsystem_rom_id() < subsystem->num_roms)
{
/* Bound-checked piece-by-piece append. Pre-fix this
* was a naive `_len += strlcpy(s + _len, src,
* sizeof(s) - _len)` chain that overshoots and
* underflows on a long subsystem->desc -- core-
* controlled via RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO
* with no length limit imposed by RetroArch -- driving
* the next strlcpy into an OOB write on the stack
* buffer s[PATH_MAX_LENGTH]. See 78c52ab for the
* helper rationale and the database_info_build_
* query_enum precedent. */
size_t pos = 0;
int rv = 0;
{
char head[256];
snprintf(head, sizeof(head), /* Format string below */
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SUBSYSTEM_LOAD_ENTRY),
subsystem->desc);
rv |= strlcpy_append(s, sizeof(s), &pos, head);
}
rv |= strlcpy_append(s, sizeof(s), &pos, " ");
rv |= strlcpy_append(s, sizeof(s), &pos, star_char);
#ifdef HAVE_RGUI
/* If using RGUI with sublabels disabled, add the
* appropriate text to the menu entry itself... */
if (is_rgui && !menu_show_sublabels)
{
rv |= strlcpy_append(s, sizeof(s), &pos, " [");
{
char head[256];
snprintf(head, sizeof(head), /* Format string below */
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SUBSYSTEM_CONTENT_INFO),
subsystem->roms[content_get_subsystem_rom_id()].desc);
rv |= strlcpy_append(s, sizeof(s), &pos, head);
}
rv |= strlcpy_append(s, sizeof(s), &pos, "]");
}
#endif
(void)rv; /* truncation leaves s NUL-terminated at
* sizeof(s) - 1; the menu entry is just
* shorter than ideal, no further action. */
if (menu_entries_append(list,
s,
MENU_ENUM_LABEL_SUBSYSTEM_ADD_STR,
MENU_ENUM_LABEL_SUBSYSTEM_ADD,
MENU_SETTINGS_SUBSYSTEM_ADD + i, 0, 0, NULL))
count++;
}
else
{
/* Same chain pattern as the "Load" branch above; same
* unbounded subsystem->desc surface. */
size_t pos = 0;
int rv = 0;
{
char head[256];
snprintf(head, sizeof(head), /* Format string below */
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SUBSYSTEM_START_ENTRY),
subsystem->desc);
rv |= strlcpy_append(s, sizeof(s), &pos, head);
}
rv |= strlcpy_append(s, sizeof(s), &pos, " ");
rv |= strlcpy_append(s, sizeof(s), &pos, star_char);
#ifdef HAVE_RGUI
/* If using RGUI with sublabels disabled, add the
* appropriate text to the menu entry itself... */
if (is_rgui && !menu_show_sublabels)
{
size_t pos2 = 0;
int rv2 = 0;
unsigned j = 0;
char rom_buff[PATH_MAX_LENGTH];
rom_buff[0] = '\0';
for (j = 0; j < content_get_subsystem_rom_id(); j++)
{
rv2 |= strlcpy_append(rom_buff, sizeof(rom_buff),
&pos2,
path_basename(content_get_subsystem_rom(j)));
if (j != content_get_subsystem_rom_id() - 1)
rv2 |= strlcpy_append(rom_buff, sizeof(rom_buff),
&pos2, "|");
}
(void)rv2;
if (*rom_buff)
{
rv |= strlcpy_append(s, sizeof(s), &pos, " [");
rv |= strlcpy_append(s, sizeof(s), &pos, rom_buff);
rv |= strlcpy_append(s, sizeof(s), &pos, "]");
}
}
#endif
(void)rv;
if (menu_entries_append(list,
s,
MENU_ENUM_LABEL_SUBSYSTEM_LOAD_STR,
MENU_ENUM_LABEL_SUBSYSTEM_LOAD,
MENU_SETTINGS_SUBSYSTEM_LOAD, 0, 0, NULL))
count++;
}
}
else
{
/* Same chain pattern as the two branches above. */
size_t pos = 0;
int rv = 0;
{
char head[256];
snprintf(head, sizeof(head), /* Format string below */
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SUBSYSTEM_LOAD_ENTRY),
subsystem->desc);
rv |= strlcpy_append(s, sizeof(s), &pos, head);
}
#ifdef HAVE_RGUI
/* If using RGUI with sublabels disabled, add the
* appropriate text to the menu entry itself... */
if (is_rgui && !menu_show_sublabels)
{
/* This check is probably not required (it's not done
* in menu_cbs_sublabel.c action_bind_sublabel_subsystem_add(),
* anyway), but no harm in being safe... */
if (subsystem->num_roms > 0)
{
rv |= strlcpy_append(s, sizeof(s), &pos, " [");
{
char head[256];
snprintf(head, sizeof(head), /* Format string below */
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SUBSYSTEM_CONTENT_INFO),
subsystem->roms[0].desc);
rv |= strlcpy_append(s, sizeof(s), &pos, head);
}
rv |= strlcpy_append(s, sizeof(s), &pos, "]");
}
}
#endif
(void)rv;
if (menu_entries_append(list,
s,
MENU_ENUM_LABEL_SUBSYSTEM_ADD_STR,
MENU_ENUM_LABEL_SUBSYSTEM_ADD,
MENU_SETTINGS_SUBSYSTEM_ADD + i, 0, 0, NULL))
count++;
}
}
}
return count;
}
#ifdef HAVE_NETWORKING
static unsigned menu_displaylist_netplay_refresh_rooms(file_list_t *list)
{
int i, j;
char s[256];
const char *room_type;
const char *cnc_netplay_room = NULL;
const char *msg_int_nc = NULL;
const char *msg_int_relay = NULL;
const char *msg_int = NULL;
const char *msg_local = NULL;
const char *msg_room_pwd = NULL;
unsigned count = 0;
core_info_list_t *coreinfos = NULL;
settings_t *settings = config_get_ptr();
net_driver_state_t *net_st = networking_state_get_ptr();
bool show_only_connectable =
settings->bools.netplay_show_only_connectable;
bool show_only_installed_cores =
settings->bools.netplay_show_only_installed_cores;
bool show_passworded = settings->bools.netplay_show_passworded;
menu_entries_clear(list);
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_HOSTING_SETTINGS),
MENU_ENUM_LABEL_NETWORK_HOSTING_SETTINGS_STR,
MENU_ENUM_LABEL_NETWORK_HOSTING_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if ( netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL)
&& !netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL)
&& netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_CONNECTED, NULL))
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_DISCONNECT),
MENU_ENUM_LABEL_NETPLAY_DISCONNECT_STR,
MENU_ENUM_LABEL_NETPLAY_DISCONNECT,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_CLIENT),
MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT_STR,
MENU_ENUM_LABEL_NETPLAY_ENABLE_CLIENT,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS),
MENU_ENUM_LABEL_NETWORK_SETTINGS_STR,
MENU_ENUM_LABEL_NETWORK_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_LOBBY_FILTERS),
MENU_ENUM_LABEL_NETPLAY_LOBBY_FILTERS_STR,
MENU_ENUM_LABEL_NETPLAY_LOBBY_FILTERS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_ROOMS),
MENU_ENUM_LABEL_NETPLAY_REFRESH_ROOMS_STR,
MENU_ENUM_LABEL_NETPLAY_REFRESH_ROOMS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#ifdef HAVE_NETPLAYDISCOVERY
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_REFRESH_LAN),
MENU_ENUM_LABEL_NETPLAY_REFRESH_LAN_STR,
MENU_ENUM_LABEL_NETPLAY_REFRESH_LAN,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
core_info_get_list(&coreinfos);
msg_int_nc = msg_hash_to_str(MSG_INTERNET_NOT_CONNECTABLE);
msg_int_relay = msg_hash_to_str(MSG_INTERNET_RELAY);
msg_int = msg_hash_to_str(MSG_INTERNET);
msg_local = msg_hash_to_str(MSG_LOCAL);
msg_room_pwd = msg_hash_to_str(MSG_ROOM_PASSWORDED);
cnc_netplay_room = MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM_STR;
for (i = 0; i < net_st->room_count; i++)
{
size_t _len = 0;
struct netplay_room *room = &net_st->room_list[i];
/* Get rid of any room that is not running RetroArch. */
if (!room->is_retroarch)
continue;
/* Get rid of rooms running older (incompatible) versions. */
if (!netplay_compatible_version(room->retroarch_version))
continue;
/* Get rid of any room that is not connectable,
if the user opt-in. */
if (!room->connectable)
{
if (show_only_connectable)
continue;
room_type = msg_int_nc;
}
else if (room->lan)
room_type = msg_local;
else if (room->host_method == NETPLAY_HOST_METHOD_MITM)
room_type = msg_int_relay;
else
room_type = msg_int;
/* Get rid of any room running a core that we don't have installed,
if the user opt-in. */
if (show_only_installed_cores)
{
for (j = 0; j < (int)coreinfos->count; j++)
{
if (string_is_equal_case_insensitive(coreinfos->list[j].core_name,
room->corename))
break;
}
if (j >= (int)coreinfos->count)
continue;
}
/* Get rid of any room that is passworded,
if the user opt-in. */
if (room->has_password || room->has_spectate_password)
{
if (!show_passworded)
continue;
_len += strlcpy_lit(s, "[", sizeof(s) - _len);
_len += strlcpy(s + _len, msg_room_pwd, sizeof(s) - _len);
_len += strlcpy_lit(s + _len, "] ", sizeof(s) - _len);
}
_len += strlcpy(s + _len, room_type, sizeof(s) - _len);
_len += strlcpy_lit(s + _len, ": ", sizeof(s) - _len);
_len += strlcpy(s + _len, room->nickname, sizeof(s) - _len);
if (!room->lan && *room->country)
{
_len += strlcpy_lit(s + _len, " (", sizeof(s) - _len);
_len += strlcpy(s + _len, room->country, sizeof(s) - _len);
strlcpy_lit(s + _len, ")", sizeof(s) - _len);
}
if (menu_entries_append(list, s, cnc_netplay_room,
MENU_ENUM_LABEL_CONNECT_NETPLAY_ROOM,
(unsigned)MENU_SETTINGS_NETPLAY_ROOMS_START + i, 0, 0, NULL))
count++;
}
return count;
}
#endif
#if defined(RETROARCH_VALIDATION_DUMPS) && !defined(_WIN32)
#include <unistd.h>
#include <sys/wait.h>
#endif
#if defined(RETROARCH_VALIDATION_DUMPS)
/* Validation dump for the displaylist build path.
*
* When the RETROARCH_DISPLAYLIST_DUMP environment variable names a
* file, every displaylist type is built once through
* menu_displaylist_build_list into a scratch list and each entry's
* path, label, type and index are written out. The output is a
* byte-comparable fingerprint of the build_list switch, the gate for
* converting its cases to data - the same discipline the settings
* dump provides for setting_append_list. Types the function does not
* handle fall through its default and print an empty section, which
* keeps the fingerprint aligned across refactors. */
void menu_displaylist_validation_dump(rarch_setting_t *list_settings)
{
struct menu_state *menu_st = menu_state_get_ptr();
rarch_setting_t *saved_list = menu_st->entries.list_settings;
const char *path = getenv("RETROARCH_DISPLAYLIST_DUMP");
settings_t *settings = config_get_ptr();
RFILE *f;
unsigned t;
if (!path)
return;
/* The dump validates the list it was handed; without this the
* settings rows of every screen silently resolve to nothing and
* the fingerprint covers only the static entries. */
menu_st->entries.list_settings = list_settings;
f = filestream_open(path,
RETRO_VFS_FILE_ACCESS_WRITE,
RETRO_VFS_FILE_ACCESS_HINT_NONE);
if (!f)
return;
filestream_printf(f, "# CORE_CONTENT=%u SYSTEM_FILES=%u NETPLAY=%u URL=%u PENDING=%u\n",
(unsigned)DISPLAYLIST_CORE_CONTENT,
(unsigned)DISPLAYLIST_CORE_SYSTEM_FILES,
(unsigned)DISPLAYLIST_NETPLAY_ROOM_LIST,
(unsigned)DISPLAYLIST_CORES_UPDATER,
(unsigned)DISPLAYLIST_PENDING_CLEAR);
for (t = 0; t <= (unsigned)DISPLAYLIST_PENDING_CLEAR; t++)
{
file_list_t list;
unsigned count;
size_t i;
/* Live values would make the fingerprint flap: the information
* list samples current memory use. Skipped, not built. */
if (t == (unsigned)DISPLAYLIST_INFORMATION_LIST
|| t == (unsigned)DISPLAYLIST_SYSTEM_INFO
|| t == (unsigned)DISPLAYLIST_DISPLAY_INFO
|| t == (unsigned)DISPLAYLIST_DISPLAY_EDID_INFO
|| t == (unsigned)DISPLAYLIST_INPUT_INFO
/* The core-content family reaches for the network and
* blocks headless; nothing deterministic lives there. */
|| (t >= (unsigned)DISPLAYLIST_CORE_CONTENT
&& t <= (unsigned)DISPLAYLIST_CORE_SYSTEM_FILES))
{
filestream_printf(f, "== %u skipped\n", t);
filestream_flush(f);
continue;
}
memset(&list, 0, sizeof(list));
filestream_printf(f, "== %u ", t);
filestream_flush(f);
count = menu_displaylist_build_list(&list, settings,
(enum menu_displaylist_ctl_state)t, false);
filestream_printf(f, "count=%u size=%u\n", count, (unsigned)list.size);
filestream_flush(f);
for (i = 0; i < list.size; i++)
filestream_printf(f, "%u|%s|%s|%u|%u\n", (unsigned)i,
list.list[i].path ? list.list[i].path : "",
list.list[i].label ? list.list[i].label : "",
list.list[i].type, (unsigned)list.list[i].entry_idx);
file_list_deinitialize(&list);
}
/* Same walk with include_everything: conditionally hidden rows
* appear too, so refactors of the visibility plumbing are gated
* on the full membership, not just what this environment shows. */
for (t = 0; t <= (unsigned)DISPLAYLIST_PENDING_CLEAR; t++)
{
file_list_t list;
unsigned count;
size_t i;
/* Live values would make the fingerprint flap: the information
* list samples current memory use. Skipped, not built. */
if (t == (unsigned)DISPLAYLIST_INFORMATION_LIST
|| t == (unsigned)DISPLAYLIST_SYSTEM_INFO
|| t == (unsigned)DISPLAYLIST_DISPLAY_INFO
|| t == (unsigned)DISPLAYLIST_DISPLAY_EDID_INFO
|| t == (unsigned)DISPLAYLIST_INPUT_INFO
/* The core-content family reaches for the network and
* blocks headless; nothing deterministic lives there. */
|| (t >= (unsigned)DISPLAYLIST_CORE_CONTENT
&& t <= (unsigned)DISPLAYLIST_CORE_SYSTEM_FILES))
{
filestream_printf(f, "=a= %u skipped\n", t);
filestream_flush(f);
continue;
}
memset(&list, 0, sizeof(list));
filestream_printf(f, "=a= %u ", t);
filestream_flush(f);
count = menu_displaylist_build_list(&list, settings,
(enum menu_displaylist_ctl_state)t, true);
filestream_printf(f, "count=%u size=%u\n", count, (unsigned)list.size);
filestream_flush(f);
for (i = 0; i < list.size; i++)
filestream_printf(f, "%u|%s|%s|%u|%u\n", (unsigned)i,
list.list[i].path ? list.list[i].path : "",
list.list[i].label ? list.list[i].label : "",
list.list[i].type, (unsigned)list.list[i].entry_idx);
file_list_deinitialize(&list);
}
/* Second pass: menu_displaylist_ctl itself, the 271-case switch
* the first pass never reached. Each type builds in a forked
* child from identical pristine parent state, so one crashing or
* hanging case names itself in the dump without taking the run
* down, and no case sees another's side effects. POSIX only;
* the dump is a validation tool and never ships. */
#if !defined(_WIN32)
for (t = 0; t <= (unsigned)DISPLAYLIST_PENDING_CLEAR; t++)
{
int pfd[2];
pid_t pid;
if (t == (unsigned)DISPLAYLIST_INFORMATION_LIST
|| t == (unsigned)DISPLAYLIST_SYSTEM_INFO
|| t == (unsigned)DISPLAYLIST_DISPLAY_INFO
|| t == (unsigned)DISPLAYLIST_DISPLAY_EDID_INFO
|| t == (unsigned)DISPLAYLIST_INPUT_INFO
|| (t >= (unsigned)DISPLAYLIST_CORE_CONTENT
&& t <= (unsigned)DISPLAYLIST_CORE_SYSTEM_FILES))
{
filestream_printf(f, "=c= %u skipped\n", t);
continue;
}
/* Cases whose contract requires a caller-supplied path or
* label - the dropdown family parses the owning setting out of
* info->path, the playlist and database screens treat it as a
* file path or query - are skipped by contract rather than
* left to crash on synthetic input, so any crash the dump does
* record is a real regression. */
if ( t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_AUDIO_DEVICE
|| t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_MIDI_DEVICE
#ifdef HAVE_MICROPHONE
|| t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_MICROPHONE_DEVICE
#endif
|| t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_VIDEO_SHADER_PARAMETER
|| t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_VIDEO_SHADER_PRESET_PARAMETER
|| t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_INPUT_RETROPAD_BIND
|| t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_INPUT_DEVICE_TYPE
|| t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_INPUT_SELECT_RESERVED_DEVICE
|| t == (unsigned)DISPLAYLIST_CDROM_DETAIL_INFO
|| t == (unsigned)DISPLAYLIST_PLAYLIST
|| t == (unsigned)DISPLAYLIST_PLAYLIST_COLLECTION
|| t == (unsigned)DISPLAYLIST_DATABASES
|| t == (unsigned)DISPLAYLIST_DATABASE_QUERY
|| t == (unsigned)DISPLAYLIST_USER_BINDS_LIST)
{
filestream_printf(f, "=c= %u needs-input\n", t);
continue;
}
filestream_printf(f, "=c= %u ", t);
filestream_flush(f);
if (pipe(pfd) != 0)
break;
if ((pid = fork()) == 0)
{
file_list_t cl;
menu_displaylist_info_t info;
FILE *w = fdopen(pfd[1], "w");
size_t i2;
bool ret;
char dd_path[16];
close(pfd[0]);
memset(&cl, 0, sizeof(cl));
menu_displaylist_info_init(&info);
info.list = &cl;
/* The generic dropdowns take the owning setting's enum id
* as their path; hand them a stable range setting so their
* machinery fingerprints instead of being skipped. The id
* is spelled by the compiler, so it tracks the guarded
* enum across configurations. */
if ( t == (unsigned)DISPLAYLIST_DROPDOWN_LIST
|| t == (unsigned)DISPLAYLIST_DROPDOWN_LIST_SPECIAL)
{
snprintf(dd_path, sizeof(dd_path), "%d",
(int)MENU_ENUM_LABEL_VIDEO_ROTATION);
info.path = strdup(dd_path);
}
ret = menu_displaylist_ctl(
(enum menu_displaylist_ctl_state)t, &info, settings);
if (w)
{
fprintf(w, "ret=%d flags=%08x size=%u\n",
ret ? 1 : 0, (unsigned)info.flags, (unsigned)cl.size);
for (i2 = 0; i2 < cl.size; i2++)
fprintf(w, "%u|%s|%s|%u|%u\n", (unsigned)i2,
cl.list[i2].path ? cl.list[i2].path : "",
cl.list[i2].label ? cl.list[i2].label : "",
cl.list[i2].type, (unsigned)cl.list[i2].entry_idx);
fflush(w);
}
_exit(0);
}
else if (pid > 0)
{
char buf[512];
ssize_t r;
int status = 0;
close(pfd[1]);
while ((r = read(pfd[0], buf, sizeof(buf))) > 0)
filestream_write(f, buf, (size_t)r);
close(pfd[0]);
waitpid(pid, &status, 0);
if (WIFSIGNALED(status))
filestream_printf(f, "crashed sig=%d\n", WTERMSIG(status));
else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
filestream_printf(f, "exit=%d\n",
WIFEXITED(status) ? WEXITSTATUS(status) : -1);
filestream_flush(f);
}
else
{
close(pfd[0]);
close(pfd[1]);
break;
}
}
#endif
menu_st->entries.list_settings = saved_list;
filestream_close(f);
}
#endif
/* The empty-list fallback nearly every screen spelled out inline:
* if nothing was appended, show the no-entries row. Returns the
* possibly incremented count so call sites stay one line. */
static unsigned menu_displaylist_no_entries_fallback(
file_list_t *list, unsigned count, unsigned entry_type)
{
if (count == 0)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY_STR,
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY,
entry_type, 0, 0, NULL))
count++;
return count;
}
typedef struct menu_displaylist_settings_row
{
enum msg_hash_enums label;
uint16_t parse_type; /* enum menu_displaylist_parse_type */
uint16_t add_empty;
} menu_displaylist_settings_row_t;
/* One loop for the runs of settings entries the displaylist switch
* used to spell out call by call; a run is a readable table now. */
static unsigned menu_displaylist_parse_settings_rows(
file_list_t *list, settings_t *settings,
const menu_displaylist_settings_row_t *rows, unsigned n)
{
unsigned i, count = 0;
for (i = 0; i < n; i++)
if (menu_displaylist_parse_settings_enum(list,
(enum menu_displaylist_parse_type)rows[i].parse_type,
rows[i].add_empty != 0,
menu_setting_find_enum(rows[i].label),
rows[i].label, true,
settings->bools.menu_show_advanced_settings) == 0)
count++;
return count;
}
/* Monitor Index offers Auto and the monitors the display server
* lists, plus the index chosen now whatever it is; a server without
* a list keeps the setting's full range. The output table lives in
* a frame of its own. */
static VIDEO_NOINLINE void menu_displaylist_monitor_index_range(void)
{
static float range_max = -1.0f;
video_output_info_t outputs[16];
int n, cap;
unsigned cur;
rarch_setting_t *setting = menu_setting_find_enum(
MENU_ENUM_LABEL_VIDEO_MONITOR_INDEX);
if (!setting)
return;
if (range_max < 0.0f)
range_max = setting->max;
cap = (int)range_max;
if (cap > (int)ARRAY_SIZE(outputs))
cap = (int)ARRAY_SIZE(outputs);
n = video_display_server_list_outputs(outputs, cap);
cur = setting_uint_get(setting);
if (n <= 0)
setting->max = range_max;
else
setting->max = (float)(cur > (unsigned)n ? cur : (unsigned)n);
}
unsigned menu_displaylist_build_list(
file_list_t *list,
settings_t *settings,
enum menu_displaylist_ctl_state type,
bool include_everything)
{
unsigned i;
unsigned count = 0;
uint32_t flags = runloop_get_flags();
struct menu_state *menu_st = menu_state_get_ptr();
switch (type)
{
case DISPLAYLIST_OPTIONS_OVERRIDES:
{
char config_directory[DIR_MAX_LENGTH];
char override_path[PATH_MAX_LENGTH];
runloop_state_t *runloop_st = runloop_state_get_ptr();
rarch_system_info_t *sys_info = &runloop_st->system;
const char *rarch_path_basename = path_get(RARCH_PATH_BASENAME);
const char *core_name = sys_info ? sys_info->info.library_name : NULL;
const char *a = path_get(RARCH_PATH_CONTENT);
bool has_content = (a && *a);
bool core_override_remove = false;
bool content_dir_override_remove = false;
bool game_override_remove = false;
config_directory[0] = '\0';
override_path[0] = '\0';
fill_pathname_application_special(config_directory,
sizeof(config_directory),
APPLICATION_SPECIAL_DIRECTORY_CONFIG);
if (has_content)
{
char content_dir_name[DIR_MAX_LENGTH];
/* Game-specific path */
fill_pathname_join_special_ext(override_path,
config_directory, core_name,
path_basename_nocompression(rarch_path_basename),
FILE_PATH_CONFIG_EXTENSION,
sizeof(override_path));
game_override_remove = path_is_valid(override_path);
override_path[0] = '\0';
/* Contentdir-specific path */
fill_pathname_parent_dir_name(content_dir_name,
rarch_path_basename, sizeof(content_dir_name));
fill_pathname_join_special_ext(override_path,
config_directory, core_name,
content_dir_name,
FILE_PATH_CONFIG_EXTENSION,
sizeof(override_path));
content_dir_override_remove = path_is_valid(override_path);
override_path[0] = '\0';
}
{
/* Core-specific path */
fill_pathname_join_special_ext(override_path,
config_directory, core_name,
core_name,
FILE_PATH_CONFIG_EXTENSION,
sizeof(override_path));
core_override_remove = path_is_valid(override_path);
override_path[0] = '\0';
}
/* Show currently 'active' override file */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_INFO),
msg_hash_to_str(MENU_ENUM_LABEL_OVERRIDE_FILE_INFO),
MENU_ENUM_LABEL_OVERRIDE_FILE_INFO,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
/* Load override file */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_LOAD),
MENU_ENUM_LABEL_OVERRIDE_FILE_LOAD_STR,
MENU_ENUM_LABEL_OVERRIDE_FILE_LOAD,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (!settings->bools.kiosk_mode_enable)
{
/* Save as */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OVERRIDE_FILE_SAVE_AS),
MENU_ENUM_LABEL_OVERRIDE_FILE_SAVE_AS_STR,
MENU_ENUM_LABEL_OVERRIDE_FILE_SAVE_AS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
/* Save/Remove game/content_dir/core */
if (has_content)
{
if (settings->bools.quick_menu_show_save_game_overrides)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_GAME),
MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME_STR,
MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_GAME,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (game_override_remove)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMOVE_CURRENT_CONFIG_OVERRIDE_GAME),
MENU_ENUM_LABEL_REMOVE_CURRENT_CONFIG_OVERRIDE_GAME_STR,
MENU_ENUM_LABEL_REMOVE_CURRENT_CONFIG_OVERRIDE_GAME,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
if (settings->bools.quick_menu_show_save_content_dir_overrides)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR),
MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR_STR,
MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (content_dir_override_remove)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMOVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR),
MENU_ENUM_LABEL_REMOVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR_STR,
MENU_ENUM_LABEL_REMOVE_CURRENT_CONFIG_OVERRIDE_CONTENT_DIR,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
}
if (settings->bools.quick_menu_show_save_core_overrides)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG_OVERRIDE_CORE),
MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE_STR,
MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_OVERRIDE_CORE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (core_override_remove)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMOVE_CURRENT_CONFIG_OVERRIDE_CORE),
MENU_ENUM_LABEL_REMOVE_CURRENT_CONFIG_OVERRIDE_CORE_STR,
MENU_ENUM_LABEL_REMOVE_CURRENT_CONFIG_OVERRIDE_CORE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
}
/* Unload overrides */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OVERRIDE_UNLOAD),
MENU_ENUM_LABEL_OVERRIDE_UNLOAD_STR,
MENU_ENUM_LABEL_OVERRIDE_UNLOAD,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
break;
case DISPLAYLIST_SUBSYSTEM_SETTINGS_LIST:
{
runloop_state_t *runloop_st = runloop_state_get_ptr();
const struct retro_subsystem_info* subsystem = runloop_st->subsystem_data;
rarch_system_info_t *sys_info = &runloop_st->system;
/* Core not loaded completely, use the data we
* peeked on load core */
/* Core fully loaded, use the subsystem data */
if (sys_info && sys_info->subsystem.data)
subsystem = sys_info->subsystem.data;
#ifdef HAVE_MENU
count = menu_displaylist_populate_subsystem(subsystem, list,
settings->bools.menu_show_sublabels);
#else
count = menu_displaylist_populate_subsystem(subsystem, list, false);
#endif
}
break;
case DISPLAYLIST_PLAYLIST_SETTINGS_LIST:
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LIST),
MENU_ENUM_LABEL_PLAYLIST_MANAGER_LIST_STR,
MENU_ENUM_LABEL_PLAYLIST_MANAGER_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
{
bool playlist_show_sublabels = settings->bools.playlist_show_sublabels;
bool history_list_enable = settings->bools.history_list_enable;
bool truncate_playlist = settings->bools.ozone_truncate_playlist_name;
static menu_displaylist_build_info_selective_t build_list[] =
{
#ifdef HAVE_NETWORKING
{MENU_ENUM_LABEL_NETWORK_ON_DEMAND_THUMBNAILS, PARSE_ONLY_BOOL, true},
#endif
{MENU_ENUM_LABEL_PLAYLIST_USE_FILENAME, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PLAYLIST_ALLOW_NON_PNG, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_SINGLECLICK_PLAYLISTS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_HISTORY_LIST_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CONTENT_HISTORY_SIZE, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_CONTENT_FAVORITES_SIZE, PARSE_ONLY_INT, true},
{MENU_ENUM_LABEL_OZONE_TRUNCATE_PLAYLIST_NAME, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_PLAYLIST_SORT_ALPHABETICAL, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PLAYLIST_PORTABLE_PATHS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PLAYLIST_ENTRY_RENAME, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PLAYLIST_ENTRY_REMOVE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_PLAYLIST_SHOW_INLINE_CORE_NAME, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_PLAYLIST_SHOW_HISTORY_ICONS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_PLAYLIST_SHOW_ENTRY_IDX, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PLAYLIST_SHOW_SUBLABELS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_PLAYLIST_FUZZY_ARCHIVE_MATCH, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SCAN_WITHOUT_CORE_MATCH, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SCAN_SERIAL_AND_CRC, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PLAYLIST_USE_OLD_FORMAT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PLAYLIST_COMPRESSION, PARSE_ONLY_BOOL, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_RUNTIME_TYPE:
case MENU_ENUM_LABEL_PLAYLIST_SUBLABEL_LAST_PLAYED_STYLE:
build_list[i].checked = playlist_show_sublabels;
break;
case MENU_ENUM_LABEL_CONTENT_HISTORY_SIZE:
build_list[i].checked = history_list_enable;
break;
case MENU_ENUM_LABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME:
build_list[i].checked = truncate_playlist;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_INPUT_TURBO_FIRE_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_INPUT_TURBO_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_INPUT_TURBO_MODE, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_INPUT_TURBO_BIND, PARSE_ONLY_INT},
{MENU_ENUM_LABEL_INPUT_TURBO_BUTTON, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_INPUT_TURBO_ALLOW_DPAD, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_INPUT_TURBO_PERIOD, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_INPUT_TURBO_DUTY_CYCLE, PARSE_ONLY_UINT},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if ( build_list[i].enum_idx == MENU_ENUM_LABEL_INPUT_TURBO_ALLOW_DPAD
&& settings->uints.input_turbo_mode > INPUT_TURBO_MODE_CLASSIC_TOGGLE)
continue;
if ( build_list[i].enum_idx == MENU_ENUM_LABEL_INPUT_TURBO_BUTTON
&& settings->uints.input_turbo_mode <= INPUT_TURBO_MODE_CLASSIC_TOGGLE)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_INPUT_HAPTIC_FEEDBACK_SETTINGS_LIST:
{
char os_ver[64];
int major, minor;
const char *input_ident = input_driver_get_ident();
const frontend_ctx_driver_t *frontend =
frontend_get_ptr();
if (frontend && frontend->get_os)
frontend->get_os(os_ver, sizeof(os_ver), &major, &minor);
if (input_driver_has_keypress_vibrate())
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIBRATE_ON_KEYPRESS,
PARSE_ONLY_BOOL, false) == 0)
count++;
/* TODO/FIXME - should we dehardcode this? */
if ( !strcmp(input_ident, "android")
|| (!strcmp(input_ident, "cocoa")
&& !strcmp(os_ver, "iOS")))
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_ENABLE_DEVICE_VIBRATION,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_RUMBLE_GAIN,
PARSE_ONLY_UINT, false) == 0)
count++;
}
break;
#ifdef HAVE_NETWORKING
case DISPLAYLIST_NETWORK_REMOTE_USERS_LIST:
{
unsigned user;
for (user = 0; user < settings->uints.input_max_users; user++)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
(enum msg_hash_enums)
(MENU_ENUM_LABEL_NETWORK_REMOTE_USER_1_ENABLE + user),
PARSE_ONLY_BOOL, false) == 0)
count++;
}
break;
case DISPLAYLIST_NETPLAY_REQUEST_DEVICES_LIST:
{
unsigned user;
for (user = 0; user < MAX_USERS; user++)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
(enum msg_hash_enums)
(MENU_ENUM_LABEL_NETPLAY_REQUEST_DEVICE_1 + user),
PARSE_ONLY_BOOL, false) == 0)
count++;
}
break;
#endif
case DISPLAYLIST_INPUT_SENSOR_SETTINGS_LIST:
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_SENSORS_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
/* iOS handles sensor rotation at the driver level,
* so the manual orientation setting is not needed */
#ifndef HAVE_COCOATOUCH
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_SENSOR_ORIENTATION,
PARSE_ONLY_UINT, false) == 0)
count++;
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_SENSOR_ACCELEROMETER_SENSITIVITY,
PARSE_ONLY_FLOAT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_SENSOR_GYROSCOPE_SENSITIVITY,
PARSE_ONLY_FLOAT, false) == 0)
count++;
}
break;
case DISPLAYLIST_INPUT_RETROPAD_BINDS_LIST:
{
unsigned user;
unsigned max_users = settings->uints.input_max_users;
for (user = 0; user < max_users; user++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
(enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_USER_1_BINDS + user),
PARSE_ACTION, false) != -1)
count++;
}
}
break;
case DISPLAYLIST_INPUT_HOTKEY_BINDS_LIST:
{
/* "Hotkey Enable" */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
(enum msg_hash_enums)(
MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN + RARCH_FIRST_META_KEY),
PARSE_ONLY_BIND, false) == 0)
count++;
{
static const menu_displaylist_settings_row_t dl_rows_1[] = {
{ MENU_ENUM_LABEL_INPUT_HOTKEY_BLOCK_DELAY, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_INPUT_HOTKEY_DEVICE_MERGE, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_INPUT_HOTKEY_FOLLOWS_PLAYER1, PARSE_ONLY_BOOL, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_1, (unsigned)ARRAY_SIZE(dl_rows_1));
}
/* All other binds come last */
for (i = 0; i < RARCH_BIND_LIST_END; i++)
{
uint8_t key = input_config_bind_map_get_retro_key(i);
/* Skip "Hotkey Enable" */
if (i == RARCH_FIRST_META_KEY)
continue;
/* Hidden items */
else if (key == RARCH_OVERLAY_NEXT)
continue;
#ifndef HAVE_OPENXR
else if ( key == RARCH_HEADSET_RECENTER
|| key == RARCH_LASER_POINTER_TOGGLE
|| key == RARCH_HEADSET_VIEW_TOGGLE)
continue;
#endif
/* Show combo entries before normal binds */
else if (key == RARCH_MENU_TOGGLE)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_MENU_ENUM_TOGGLE_GAMEPAD_COMBO,
PARSE_ONLY_UINT, false) == 0)
count++;
}
else if (key == RARCH_QUIT_KEY)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_QUIT_GAMEPAD_COMBO,
PARSE_ONLY_UINT, false) == 0)
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
(enum msg_hash_enums)(
MENU_ENUM_LABEL_INPUT_HOTKEY_BIND_BEGIN + i),
PARSE_ONLY_BIND, false) == 0)
count++;
}
/* Combinations and macros: each there is, and one empty
* row to add the next with. Listed as the text settings they
* are (no entry type given): as an action a row was drawn
* with no value, and showed nothing of what it held. */
menu_setting_entries_refresh();
{
unsigned k;
for (k = 0; k < 2; k++)
{
bool blank = false;
for (i = 1; i <= 16; i++)
{
char key[32];
char text[16];
size_t has = k ? input_macro_spec(i, text, sizeof(text))
: input_entry_spec(i, text, sizeof(text));
if (!has)
{
if (blank)
continue;
blank = true;
}
snprintf(key, sizeof(key), k ? "input_macro_%u" : "input_combo_%u", i);
if (MENU_DISPLAYLIST_PARSE_SETTINGS(list,
key, PARSE_ONLY_STRING, false, 0) == 0)
count++;
}
}
}
}
break;
case DISPLAYLIST_SHADER_PRESET_MANAGER:
{
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
const char *a = path_get(RARCH_PATH_CONTENT);
bool has_content = (a && *a);
const char *dir_video_shader = settings->paths.directory_video_shader;
const char *dir_menu_config = settings->paths.directory_menu_config;
if (file_watch_supported())
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_WATCH_FOR_CHANGES),
MENU_ENUM_LABEL_SHADER_WATCH_FOR_CHANGES_STR,
MENU_ENUM_LABEL_SHADER_WATCH_FOR_CHANGES,
0, 0, 0, NULL))
count++;
}
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_REMEMBER_LAST_DIR),
MENU_ENUM_LABEL_VIDEO_SHADER_REMEMBER_LAST_DIR_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_REMEMBER_LAST_DIR,
0, 0, 0, NULL))
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_REFERENCE,
PARSE_ONLY_BOOL, false) == 0)
count++;
/* Show current shader preset */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_FILE_INFO),
msg_hash_to_str(MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_FILE_INFO),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_FILE_INFO,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_AS_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_AS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CURRENT),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CURRENT_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CURRENT,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GLOBAL),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_GLOBAL_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_GLOBAL,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_shader_manager_auto_preset_exists(SHADER_PRESET_GLOBAL,
dir_video_shader, dir_menu_config))
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_GLOBAL),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_GLOBAL_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_GLOBAL,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_CORE),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CORE_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_CORE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_shader_manager_auto_preset_exists(SHADER_PRESET_CORE,
dir_video_shader, dir_menu_config))
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_CORE),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_CORE_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_CORE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (has_content)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_PARENT),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_PARENT_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_PARENT,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_shader_manager_auto_preset_exists(SHADER_PRESET_PARENT,
dir_video_shader, dir_menu_config))
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_PARENT),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_PARENT_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_PARENT,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_GAME),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_GAME_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_SAVE_GAME,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_shader_manager_auto_preset_exists(SHADER_PRESET_GAME,
dir_video_shader, dir_menu_config))
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_REMOVE_GAME),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_GAME_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_REMOVE_GAME,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#endif
}
break;
case DISPLAYLIST_NETPLAY_ROOM_LIST:
#ifdef HAVE_NETWORKING
count = menu_displaylist_netplay_refresh_rooms(list);
#endif
break;
case DISPLAYLIST_CONTENT_SETTINGS:
count = menu_displaylist_parse_load_content_settings(list,
settings, false);
if (count == 0)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ITEMS),
MENU_ENUM_LABEL_NO_ITEMS_STR,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_NO_ITEM, 0, 0, NULL))
count++;
break;
case DISPLAYLIST_BROWSE_URL_START:
#ifdef HAVE_NETWORKING
{
char link[1024];
char name[1024];
const char *line = "<a href=\"http://www.test.com/somefile.zip\">Test</a>\n";
link[0] = name[0] = '\0';
string_parse_html_anchor(line, link, name, sizeof(link), sizeof(name));
if (menu_entries_append(list,
link,
name,
MSG_UNKNOWN,
0, 0, 0, NULL))
count++;
}
#endif
break;
case DISPLAYLIST_AUDIO_MIXER_SETTINGS_LIST:
{
#ifdef HAVE_AUDIOMIXER
char msg_lbl[128];
size_t _len = strlcpy_lit(msg_lbl, "audio_mixer_stream_", sizeof(msg_lbl));
#if 1
/* TODO - for developers -
* turn this into #if 0 if you want to be able to see
* the system streams as well. */
for (i = 0; i < AUDIO_MIXER_MAX_STREAMS; i++)
#else
for (i = 0; i < AUDIO_MIXER_MAX_SYSTEM_STREAMS; i++)
#endif
{
char msg[128];
snprintf(msg, sizeof(msg), msg_hash_to_str(MENU_ENUM_LABEL_MIXER_STREAM), i+1, "\n");
snprintf(msg_lbl + _len, sizeof(msg_lbl) - _len, "%d\n", i);
if (menu_entries_append(list, msg, msg_lbl, MSG_UNKNOWN,
(MENU_SETTINGS_AUDIO_MIXER_STREAM_BEGIN + i),
0, 0, NULL))
count++;
}
#endif
}
break;
case DISPLAYLIST_BLUETOOTH_SETTINGS_LIST:
#ifdef HAVE_BLUETOOTH
{
if (!string_is_equal(settings->arrays.bluetooth_driver, "null"))
{
/* looked for again each time, the last scan's list shown
* meanwhile: a pad put in pairing mode since is found */
task_push_bluetooth_scan(bluetooth_scan_callback);
count += bluetooth_list_fill(list);
}
}
#endif
break;
case DISPLAYLIST_WIFI_SETTINGS_LIST:
#if defined(HAVE_NETWORKING) && defined(HAVE_WIFI)
{
bool wifi_enabled = settings->bools.wifi_enabled;
bool connected = driver_wifi_connection_info(NULL);
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_WIFI_ENABLED, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_WIFI_NETWORK_SCAN, PARSE_ACTION, false},
{MENU_ENUM_LABEL_WIFI_DISCONNECT, PARSE_ACTION, false},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_WIFI_NETWORK_SCAN:
build_list[i].checked = wifi_enabled;
break;
case MENU_ENUM_LABEL_WIFI_DISCONNECT:
build_list[i].checked = wifi_enabled && connected;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (build_list[i].checked &&
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
#endif
break;
case DISPLAYLIST_WIFI_NETWORKS_LIST:
#if defined(HAVE_NETWORKING) && defined(HAVE_WIFI)
if (!string_is_equal(settings->arrays.wifi_driver, "null"))
{
wifi_network_scan_t *scan = driver_wifi_get_ssids();
/* Temporary hack: scan periodically, until we have a submenu */
if (!scan || time(NULL) > scan->scan_time + 30)
task_push_wifi_scan(wifi_scan_callback);
else
{
unsigned i;
for (i = 0; i < RBUF_LEN(scan->net_list); i++)
{
const char *ssid = scan->net_list[i].ssid;
if (menu_entries_append(list,
(ssid && *ssid) ? ssid : msg_hash_to_str(MSG_WIFI_EMPTY_SSID),
MENU_ENUM_LABEL_CONNECT_WIFI_STR,
MENU_ENUM_LABEL_CONNECT_WIFI,
MENU_WIFI, 0, 0, NULL))
count++;
}
}
}
#endif
break;
case DISPLAYLIST_SYSTEM_INFO:
count = menu_displaylist_parse_system_info(list);
break;
case DISPLAYLIST_DISPLAY_INFO:
count = menu_displaylist_parse_display_info(list);
break;
case DISPLAYLIST_INPUT_INFO:
count = menu_displaylist_parse_input_info(list);
break;
case DISPLAYLIST_DISPLAY_EDID_INFO:
#ifdef HAVE_MODELINE
count = menu_displaylist_parse_display_edid(list);
#endif
break;
case DISPLAYLIST_EXPLORE:
menu_entries_clear(list);
#if defined(HAVE_LIBRETRODB)
count = menu_displaylist_explore(list, settings);
#endif
break;
case DISPLAYLIST_SCAN_DIRECTORY_LIST:
#if 0
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY),
MENU_ENUM_LABEL_SCAN_DIRECTORY_STR,
MENU_ENUM_LABEL_SCAN_DIRECTORY,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_FILE),
MENU_ENUM_LABEL_SCAN_FILE_STR,
MENU_ENUM_LABEL_SCAN_FILE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_LIST),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_LIST_STR,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
break;
case DISPLAYLIST_INFORMATION_LIST:
count = menu_displaylist_parse_information_list(list);
break;
case DISPLAYLIST_AUDIO_OUTPUT_SETTINGS_LIST:
{
{
static const menu_displaylist_settings_row_t dl_rows_2[] = {
{ MENU_ENUM_LABEL_AUDIO_ENABLE, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_AUDIO_DRIVER, PARSE_ONLY_STRING_OPTIONS, false },
{ MENU_ENUM_LABEL_AUDIO_DEVICE, PARSE_ONLY_STRING, false },
{ MENU_ENUM_LABEL_AUDIO_OUTPUT_RATE, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_AUDIO_LATENCY, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_AUDIO_LATENCY_FLOOR, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_AUDIO_RESAMPLER_DRIVER, PARSE_ONLY_STRING_OPTIONS, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_2, (unsigned)ARRAY_SIZE(dl_rows_2));
}
if (string_is_not_equal(settings->arrays.audio_resampler, "null"))
{
/* Quality and HQ oversampling are shown for the backends
* that read them; the rest ignore both. */
unsigned caps = audio_resampler_driver_caps(
settings->arrays.audio_resampler);
if (caps & RESAMPLER_CAP_QUALITY)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_AUDIO_RESAMPLER_QUALITY,
PARSE_ONLY_UINT, false) == 0)
count++;
}
if (caps & RESAMPLER_CAP_HQ_OVERSAMPLE)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_AUDIO_RESAMPLER_HQ_OVERSAMPLING,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
{
static const menu_displaylist_settings_row_t dl_rows_3[] = {
{ MENU_ENUM_LABEL_AUDIO_FASTPATH_S16, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_AUDIO_FORMAT_NEGOTIATION, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_AUDIO_OUTPUT_LAYOUT, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_AUDIO_HEADPHONE_VIRTUAL_SURROUND, PARSE_ONLY_BOOL, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_3, (unsigned)ARRAY_SIZE(dl_rows_3));
}
}
#ifdef HAVE_WASAPI
if (string_is_equal(settings->arrays.audio_driver, "wasapi"))
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_AUDIO_WASAPI_EXCLUSIVE_MODE,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_AUDIO_WASAPI_SH_BUFFER_LENGTH,
PARSE_ONLY_UINT, false) == 0)
count++;
}
#endif
#ifdef HAVE_ASIO
/* Shown for the configured driver, as the WASAPI items are:
* the page rebuilds on a driver change without audio being
* reinitialised, so this is what tells the user ASIO is the
* driver they picked. The panel itself needs ASIO running,
* and says so if it is not. A device does not gate it - the
* driver opens its default device when none is set. */
if (string_is_equal(settings->arrays.audio_driver, "asio"))
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_AUDIO_ASIO_OUTPUT_CHANNEL,
PARSE_ONLY_UINT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_AUDIO_ASIO_CONTROL_PANEL,
PARSE_ACTION, false) == 0)
count++;
}
#endif
}
break;
#ifdef HAVE_MICROPHONE
case DISPLAYLIST_MICROPHONE_SETTINGS_LIST:
{
static const menu_displaylist_settings_row_t dl_rows_4[] = {
{ MENU_ENUM_LABEL_MICROPHONE_ENABLE, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_MICROPHONE_DRIVER, PARSE_ONLY_STRING_OPTIONS, false },
{ MENU_ENUM_LABEL_MICROPHONE_DEVICE, PARSE_ONLY_STRING, false },
{ MENU_ENUM_LABEL_MICROPHONE_INPUT_RATE, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_MICROPHONE_LATENCY, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_MICROPHONE_RESAMPLER_DRIVER, PARSE_ONLY_STRING_OPTIONS, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_4, (unsigned)ARRAY_SIZE(dl_rows_4));
}
if (audio_resampler_driver_caps(settings->arrays.microphone_resampler)
& RESAMPLER_CAP_QUALITY)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_MICROPHONE_RESAMPLER_QUALITY,
PARSE_ONLY_UINT, false) == 0)
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_MICROPHONE_BLOCK_FRAMES,
PARSE_ONLY_UINT, false) == 0)
count++;
#ifdef HAVE_WASAPI
/* Shown for the configured driver, as the audio output page
* shows its WASAPI items: the rows are always in the settings
* table now, and this is what keeps them off the page for
* every other microphone driver. */
if (string_is_equal(settings->arrays.microphone_driver, "wasapi"))
{
static const menu_displaylist_settings_row_t dl_rows_5[] = {
{ MENU_ENUM_LABEL_MICROPHONE_WASAPI_EXCLUSIVE_MODE, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_MICROPHONE_WASAPI_FLOAT_FORMAT, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_MICROPHONE_WASAPI_SH_BUFFER_LENGTH, PARSE_ONLY_UINT, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_5, (unsigned)ARRAY_SIZE(dl_rows_5));
}
#endif
break;
#endif
case DISPLAYLIST_AUDIO_SYNCHRONIZATION_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_AUDIO_SYNC, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_MAX_TIMING_SKEW, PARSE_ONLY_FLOAT, true },
{MENU_ENUM_LABEL_AUDIO_RATE_CONTROL_DELTA, PARSE_ONLY_FLOAT, true },
{MENU_ENUM_LABEL_AUDIO_THREADED_PIPELINE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_PIPELINE_FILL_CAP, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_SINK_RATE_ESTIMATION, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_THREAD_PRIORITY, PARSE_ONLY_BOOL, true },
#ifdef HAVE_WASAPI
/* Which way the thread's priority is asked for, so it
* is only worth showing where one is being asked for at
* all: checked below against the setting above it. */
{MENU_ENUM_LABEL_AUDIO_WASAPI_MMCSS, PARSE_ONLY_BOOL, false },
#endif
#ifdef HAVE_THREADS
{MENU_ENUM_LABEL_AUDIO_TIME_STRETCH, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_TIME_STRETCH_LOWPASS, PARSE_ONLY_BOOL, true },
#endif
};
#ifdef HAVE_WASAPI
/* Which way the audio thread's priority is asked for, so
* it is shown only where one is being asked for at all. */
for (i = 0; i < ARRAY_SIZE(build_list); i++)
if (build_list[i].enum_idx == MENU_ENUM_LABEL_AUDIO_WASAPI_MMCSS)
build_list[i].checked = settings->bools.audio_thread_priority;
#endif
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_AUDIO_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_AUDIO_OUTPUT_SETTINGS, PARSE_ACTION, true },
#ifdef HAVE_MICROPHONE
{MENU_ENUM_LABEL_MICROPHONE_SETTINGS, PARSE_ACTION, true },
#endif
{MENU_ENUM_LABEL_AUDIO_SYNCHRONIZATION_SETTINGS, PARSE_ACTION, true },
{MENU_ENUM_LABEL_MIDI_SETTINGS, PARSE_ACTION, true },
#if defined(HAVE_AUDIOMIXER)
{MENU_ENUM_LABEL_AUDIO_MIXER_SETTINGS, PARSE_ACTION, true },
#endif
{MENU_ENUM_LABEL_MENU_SOUNDS, PARSE_ACTION, true },
{MENU_ENUM_LABEL_AUDIO_VOLUME, PARSE_ONLY_FLOAT, true },
{MENU_ENUM_LABEL_AUDIO_MIXER_VOLUME, PARSE_ONLY_FLOAT, true },
{MENU_ENUM_LABEL_AUDIO_MUTE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_MIXER_MUTE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_RESPECT_SILENT_MODE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_SYSTEM_BGM_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_REWIND_MUTE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_FASTFORWARD_SPEEDUP, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_FASTFORWARD_CALLBACK, PARSE_ONLY_BOOL, true },
#if defined(HAVE_DSP_FILTER)
{MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN, PARSE_ONLY_PATH, true },
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
#if defined(HAVE_DSP_FILTER)
if (*settings->paths.path_audio_dsp_plugin)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN_REMOVE),
MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN_REMOVE_STR,
MENU_ENUM_LABEL_AUDIO_DSP_PLUGIN_REMOVE,
MENU_SETTING_ACTION_AUDIO_DSP_PLUGIN_REMOVE, 0, 0, NULL))
count++;
#endif
break;
case DISPLAYLIST_VIDEO_SETTINGS_LIST:
{
gfx_ctx_flags_t flags;
{
static const menu_displaylist_settings_row_t dl_rows_6[] = {
{ MENU_ENUM_LABEL_VIDEO_OUTPUT_SETTINGS, PARSE_ACTION, false },
{ MENU_ENUM_LABEL_VIDEO_SCALING_SETTINGS, PARSE_ACTION, false },
{ MENU_ENUM_LABEL_VIDEO_SYNCHRONIZATION_SETTINGS, PARSE_ACTION, false },
{ MENU_ENUM_LABEL_VIDEO_FULLSCREEN_MODE_SETTINGS, PARSE_ACTION, false },
{ MENU_ENUM_LABEL_VIDEO_WINDOWED_MODE_SETTINGS, PARSE_ACTION, false },
{ MENU_ENUM_LABEL_VIDEO_HDR_SETTINGS, PARSE_ACTION, false },
{ MENU_ENUM_LABEL_VIDEO_STEREO_SETTINGS, PARSE_ACTION, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_6, (unsigned)ARRAY_SIZE(dl_rows_6));
}
if (video_display_server_get_flags(&flags))
{
if (BIT32_GET(flags.flags, DISPSERV_CTX_MODELINE))
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_CRT_SWITCHRES_SETTINGS,
PARSE_ACTION, false) == 0)
count++;
}
else if (video_context_driver_get_flags(&flags))
{
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_CRT_SWITCHRES))
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_CRT_SWITCHRES_SETTINGS,
PARSE_ACTION, false) == 0)
count++;
}
/* Only an SDL window can hand mode switching to SDL */
if (video_display_server_sdl_available())
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SDL_DISPLAY_SERVER,
PARSE_ONLY_UINT, false) == 0)
count++;
{
static const menu_displaylist_settings_row_t dl_rows_7[] = {
{ MENU_ENUM_LABEL_SUSPEND_SCREENSAVER_ENABLE, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_VIDEO_SHADER_DELAY, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_BRIGHTNESS_CONTROL, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_VIDEO_CTX_SCALING, PARSE_ONLY_BOOL, false },
#ifdef HAVE_VIDEO_FILTER
{ MENU_ENUM_LABEL_VIDEO_FILTER_ENABLE, PARSE_ONLY_BOOL, false },
#endif
#if defined(DINGUX)
{ MENU_ENUM_LABEL_VIDEO_DINGUX_IPU_FILTER_TYPE, PARSE_ONLY_UINT, false },
#if defined(RS90) || defined(MIYOO)
{ MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE, PARSE_ONLY_UINT, false },
#endif
#endif
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_7, (unsigned)ARRAY_SIZE(dl_rows_7));
}
#ifdef HAVE_VIDEO_FILTER
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_FILTER,
PARSE_ONLY_PATH, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_FILTER_THREADS,
PARSE_ONLY_UINT, false) == 0)
count++;
if (*settings->paths.path_softfilter_plugin)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_REMOVE),
MENU_ENUM_LABEL_VIDEO_FILTER_REMOVE_STR,
MENU_ENUM_LABEL_VIDEO_FILTER_REMOVE,
MENU_SETTING_ACTION_VIDEO_FILTER_REMOVE, 0, 0, NULL))
count++;
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_NOTCH_WRITE_OVER,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_USE_METAL_ARG_BUFFERS,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
break;
case DISPLAYLIST_OPTIONS_REMAPPINGS:
{
unsigned p;
unsigned max_users = settings->uints.input_max_users;
#ifdef HAVE_CONFIGFILE
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REMAP_FILE_MANAGER_LIST),
MENU_ENUM_LABEL_REMAP_FILE_MANAGER_LIST_STR,
MENU_ENUM_LABEL_REMAP_FILE_MANAGER_LIST,
MENU_SETTING_ACTION_REMAP_FILE_MANAGER_LIST, 0, 0, NULL))
count++;
#endif
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_TURBO_FIRE_SETTINGS),
MENU_ENUM_LABEL_INPUT_TURBO_FIRE_SETTINGS_STR,
MENU_ENUM_LABEL_INPUT_TURBO_FIRE_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
for (p = 0; p < max_users; p++)
{
char val_s[NAME_MAX_LENGTH], val_d[16];
snprintf(val_s, sizeof(val_s),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS),
p+1);
snprintf(val_d, sizeof(val_d), "%d", p);
if (menu_entries_append(list, val_s, val_d,
MSG_UNKNOWN,
MENU_SETTINGS_REMAPPING_PORT_BEGIN + p, p, 0, NULL))
count++;
}
}
break;
case DISPLAYLIST_LOAD_CONTENT_LIST:
case DISPLAYLIST_LOAD_CONTENT_SPECIAL:
{
core_info_list_t *info_list = NULL;
core_info_get_list(&info_list);
if (*settings->paths.directory_menu_content)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FAVORITES),
MENU_ENUM_LABEL_FAVORITES_STR,
MENU_ENUM_LABEL_FAVORITES,
MENU_SETTING_ACTION_FAVORITES_DIR, 0, 0, NULL))
count++;
if (info_list && info_list->info_count > 0)
if (menu_entries_append(list,
msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST),
MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST_STR,
MENU_ENUM_LABEL_DOWNLOADED_FILE_DETECT_CORE_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if ( !settings->bools.kiosk_mode_enable
&& frontend_driver_parse_drive_list(list, true) != 0)
if (menu_entries_append(list, "/",
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR_STR,
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#ifdef HAVE_SMBCLIENT
{
settings_t *settings = config_get_ptr();
if (settings->bools.smb_client_enable)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SMB_CLIENT_BROWSE),
msg_hash_to_str(MENU_ENUM_SUBLABEL_SMB_CLIENT_BROWSE),
MENU_ENUM_LABEL_SMB_CLIENT_BROWSE,
FILE_TYPE_DIRECTORY, 0, 0, NULL))
count++;
}
}
#endif
#ifdef HAVE_NFSCLIENT
{
settings_t *settings = config_get_ptr();
if (*settings->arrays.nfs_server)
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NFS_CLIENT_BROWSE),
msg_hash_to_str(MENU_ENUM_SUBLABEL_NFS_CLIENT_BROWSE),
MENU_ENUM_LABEL_NFS_CLIENT_BROWSE,
FILE_TYPE_DIRECTORY, 0, 0, NULL))
count++;
}
}
#endif
if ( !settings->bools.kiosk_mode_enable
&& settings->bools.settings_show_file_browser)
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS),
MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS_STR,
MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL);
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MEDIA_PLAYER_SETTINGS),
MENU_ENUM_LABEL_MEDIA_PLAYER_SETTINGS_STR,
MENU_ENUM_LABEL_MEDIA_PLAYER_SETTINGS,
MENU_SETTING_ACTION, 0, 0, NULL);
}
break;
}
case DISPLAYLIST_INPUT_MENU_SETTINGS_LIST:
{
const char *menu_driver = menu_driver_ident();
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_MOUSE_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_POINTER_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_INPUT_SWAP_OK_CANCEL, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_INPUT_SWAP_SCROLL, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_UNIFIED_MENU_CONTROLS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_ALL_USERS_CONTROL_MENU, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_SINGLECLICK_PLAYLISTS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_ALLOW_TABS_BACK, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_SCROLL_FAST, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_SCROLL_DELAY, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_DISABLE_INFO_BUTTON, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_DISABLE_SEARCH_BUTTON, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_DISABLE_LEFT_ANALOG_IN_MENU, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_DISABLE_RIGHT_ANALOG_IN_MENU, PARSE_ONLY_BOOL, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_MENU_ALLOW_TABS_BACK:
build_list[i].checked = (!strcmp(menu_driver, "rgui"));
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_INPUT_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_INPUT_RETROPAD_BINDS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_INPUT_TURBO_FIRE_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_INPUT_HOTKEY_BINDS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_INPUT_MENU_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_INPUT_SENSOR_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_INPUT_HAPTIC_FEEDBACK_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_INPUT_MAX_USERS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_CONFIRM_QUIT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CONFIRM_CLOSE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CONFIRM_RESET, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_AUTO_MOUSE_GRAB, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_AUTO_GAME_FOCUS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_AUTODETECT_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_REMAP_BINDS_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_REMAP_SORT_BY_CONTROLLER_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PAUSE_ON_DISCONNECT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_ASSIGN_PORTS_ON_BUTTON_PRESS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_ASSIGN_PORTS_KEYBOARD, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_ROTATION, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_SOCD_HORIZONTAL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_SOCD_VERTICAL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_ICADE_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_SMALL_KEYBOARD_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_KEYBOARD_GAMEPAD_MAPPING_TYPE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_DESCRIPTOR_LABEL_SHOW, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_DESCRIPTOR_HIDE_UNBOUND, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_BUTTON_AXIS_THRESHOLD, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_INPUT_TRIGGER_FULL_RANGE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_ANALOG_DEADZONE, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_INPUT_ANALOG_TRIGGER_DEADZONE, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_INPUT_ANALOG_OUTER_DEADZONE, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_INPUT_ANALOG_ANTI_DEADZONE, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_INPUT_ANALOG_RESPONSE_CURVE, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_INPUT_ANALOG_SENSITIVITY, PARSE_ONLY_FLOAT, true},
#if defined(GEKKO)
{MENU_ENUM_LABEL_INPUT_MOUSE_SCALE, PARSE_ONLY_UINT, true},
#endif
{MENU_ENUM_LABEL_INPUT_TOUCH_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_PREFER_FRONT_TOUCH, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_TOUCH_SCALE, PARSE_ONLY_UINT, true},
#ifdef UDEV_TOUCH_SUPPORT
{MENU_ENUM_LABEL_INPUT_TOUCH_VMOUSE_POINTER, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_TOUCH_VMOUSE_MOUSE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_TOUCH_VMOUSE_TOUCHPAD, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_TOUCH_VMOUSE_TRACKBALL, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_TOUCH_VMOUSE_GESTURE, PARSE_ONLY_BOOL, true},
#endif
{MENU_ENUM_LABEL_INPUT_BIND_TIMEOUT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_BIND_HOLD, PARSE_ONLY_UINT, true},
#if defined(HAVE_DINPUT) || defined(HAVE_WINRAWINPUT)
{MENU_ENUM_LABEL_INPUT_NOWINKEY_ENABLE, PARSE_ONLY_BOOL, true},
#endif
#if defined(_WIN32) && defined(HAVE_WINRAWINPUT)
{MENU_ENUM_LABEL_INPUT_WINRAW_XINPUT_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_WINRAW_PLAYER_LIGHTS, PARSE_ONLY_BOOL, true},
#endif
#ifdef ANDROID
{MENU_ENUM_LABEL_ANDROID_INPUT_DISCONNECT_WORKAROUND, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_STYLUS_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_STYLUS_REQUIRE_CONTACT_FOR_CLICK, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_STYLUS_HOVER_MOVES_POINTER, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_INPUT_STYLUS_PRESSURE_SENSITIVITY, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_BLOCK_TIMEOUT, PARSE_ONLY_UINT, true},
#endif
{MENU_ENUM_LABEL_INPUT_JOYPAD_BACKGROUND, PARSE_ONLY_BOOL, true},
#if defined(_WIN32) && defined(HAVE_WINRAWINPUT)
{MENU_ENUM_LABEL_INPUT_KEYBOARD_BACKGROUND, PARSE_ONLY_BOOL, true},
#endif
{MENU_ENUM_LABEL_INPUT_POLL_TYPE_BEHAVIOR, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_INPUT_DRIVER, PARSE_ONLY_STRING_OPTIONS, true},
{MENU_ENUM_LABEL_JOYPAD_DRIVER, PARSE_ONLY_STRING_OPTIONS, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
#ifdef ANDROID
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_SELECT_PHYSICAL_KEYBOARD,
PARSE_ACTION, true) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_ANDROID_SYSTEM_KEYBOARD,
PARSE_ONLY_BOOL, true) == 0)
count++;
#endif
#ifdef HAVE_SDL3
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_INPUT_SDL3_SYSTEM_KEYBOARD,
PARSE_ONLY_BOOL, true) == 0)
count++;
#endif
#ifdef HAVE_LIBNX
{
unsigned user;
char key_split_joycon[PATH_MAX_LENGTH];
const char *split_joycon_str =
MENU_ENUM_LABEL_INPUT_SPLIT_JOYCON_STR;
size_t _len = strlcpy(key_split_joycon, split_joycon_str,
sizeof(key_split_joycon));
for (user = 0; user < 8; user++)
{
unsigned val = user + 1;
snprintf(key_split_joycon + _len,
sizeof(key_split_joycon) - _len,
"_%u", val);
if (MENU_DISPLAYLIST_PARSE_SETTINGS(list,
key_split_joycon, PARSE_ONLY_UINT, true, 0) != -1)
count++;
}
}
#endif
break;
case DISPLAYLIST_ACCESSIBILITY_SETTINGS_LIST:
{
bool accessibility_enable = settings->bools.accessibility_enable;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_ACCESSIBILITY_ENABLED, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_AI_SERVICE_SETTINGS, PARSE_ACTION, true },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_ACCESSIBILITY_NARRATOR_SPEECH_SPEED:
build_list[i].checked = accessibility_enable;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_AI_SERVICE_SETTINGS_LIST:
{
bool ai_service_enable = settings->bools.ai_service_enable;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_AI_SERVICE_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_AI_SERVICE_MODE, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_AI_SERVICE_URL, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_AI_SERVICE_BACKEND, PARSE_ONLY_STRING_OPTIONS, false},
{MENU_ENUM_LABEL_AI_SERVICE_PAUSE, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_AI_SERVICE_SOURCE_LANG, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_AI_SERVICE_TARGET_LANG, PARSE_ONLY_UINT, false},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_AI_SERVICE_MODE:
case MENU_ENUM_LABEL_AI_SERVICE_BACKEND:
case MENU_ENUM_LABEL_AI_SERVICE_URL:
case MENU_ENUM_LABEL_AI_SERVICE_PAUSE:
case MENU_ENUM_LABEL_AI_SERVICE_SOURCE_LANG:
case MENU_ENUM_LABEL_AI_SERVICE_TARGET_LANG:
build_list[i].checked = ai_service_enable;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_ADD_CONTENT_LIST:
#ifdef HAVE_LIBRETRODB
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY),
MENU_ENUM_LABEL_SCAN_DIRECTORY_STR,
MENU_ENUM_LABEL_SCAN_DIRECTORY,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCAN_FILE),
MENU_ENUM_LABEL_SCAN_FILE_STR,
MENU_ENUM_LABEL_SCAN_FILE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MANUAL_CONTENT_SCAN_LIST),
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_LIST_STR,
MENU_ENUM_LABEL_MANUAL_CONTENT_SCAN_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
break;
case DISPLAYLIST_NETWORK_INFO:
#if defined(HAVE_NETWORKING) && defined(HAVE_IFINFO)
{
net_ifinfo_t interfaces = {0};
network_init();
if (net_ifinfo_new(&interfaces))
{
size_t i;
char buf[NAME_MAX_LENGTH];
const char *msg_intf = msg_hash_to_str(MSG_INTERFACE);
size_t _len = strlcpy(buf, msg_intf, sizeof(buf));
for (i = 0; i < interfaces.size; i++)
{
struct net_ifinfo_entry *entry = &interfaces.entries[i];
snprintf(buf + _len, sizeof(buf) - _len, " (%s): %s\n",
entry->name, entry->host);
if (menu_entries_append(list, buf, entry->name,
MENU_ENUM_LABEL_NETWORK_INFO_ENTRY,
MENU_SETTINGS_CORE_INFO_NONE, 0, 0, NULL))
count++;
}
net_ifinfo_free(&interfaces);
}
}
#endif
break;
case DISPLAYLIST_OPTIONS_CHEATS:
#ifdef HAVE_CHEATS
cheat_manager_alloc_if_empty();
{
unsigned i;
char cheat_label[128];
char on_string[32];
char off_string[32];
menu_search_terms_t *search_terms= menu_entries_search_get_terms();
bool search_active = search_terms && (search_terms->size > 0);
unsigned num_cheats = cheat_manager_get_size();
unsigned num_cheats_shown = 0;
size_t _len = 0;
on_string[0] = '\0';
off_string[0] = '\0';
/* If a search is active, all options are
* omitted apart from 'apply changes' */
if (search_active)
{
/* On/off key strings may be required,
* so populate them... */
on_string [ _len] = '.';
on_string [++_len] = '\0';
strlcpy(on_string + _len,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON),
sizeof(on_string) - _len);
_len = 0;
off_string[ _len] = '.';
off_string[++_len] = '\0';
strlcpy(off_string + _len,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF),
sizeof(off_string) - _len);
}
else
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_START_OR_CONT),
MENU_ENUM_LABEL_CHEAT_START_OR_CONT_STR,
MENU_ENUM_LABEL_CHEAT_START_OR_CONT,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_CHEAT_APPLY_AFTER_LOAD,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_CHEAT_APPLY_AFTER_TOGGLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD),
MENU_ENUM_LABEL_CHEAT_FILE_LOAD_STR,
MENU_ENUM_LABEL_CHEAT_FILE_LOAD,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD_APPEND),
MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND_STR,
MENU_ENUM_LABEL_CHEAT_FILE_LOAD_APPEND,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS),
MENU_ENUM_LABEL_CHEAT_FILE_SAVE_AS_STR,
MENU_ENUM_LABEL_CHEAT_FILE_SAVE_AS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_TOP),
MENU_ENUM_LABEL_CHEAT_ADD_NEW_TOP_STR,
MENU_ENUM_LABEL_CHEAT_ADD_NEW_TOP,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BOTTOM),
MENU_ENUM_LABEL_CHEAT_ADD_NEW_BOTTOM_STR,
MENU_ENUM_LABEL_CHEAT_ADD_NEW_BOTTOM,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_DELETE_ALL),
MENU_ENUM_LABEL_CHEAT_DELETE_ALL_STR,
MENU_ENUM_LABEL_CHEAT_DELETE_ALL,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_RELOAD_CHEATS),
MENU_ENUM_LABEL_CHEAT_RELOAD_CHEATS_STR,
MENU_ENUM_LABEL_CHEAT_RELOAD_CHEATS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES),
MENU_ENUM_LABEL_CHEAT_APPLY_CHANGES_STR,
MENU_ENUM_LABEL_CHEAT_APPLY_CHANGES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
_len = strlcpy(cheat_label, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT), sizeof(cheat_label));
for (i = 0; i < num_cheats; i++)
{
size_t new_len = _len;
const char *cheat_description = cheat_manager_get_desc(i);
new_len += snprintf(cheat_label + _len, sizeof(cheat_label) - _len, " #%u: ", i);
if (cheat_description && *cheat_description)
strlcpy(cheat_label + new_len, cheat_description, sizeof(cheat_label) - new_len);
/* If a search is active, skip non-matching
* entries */
if (search_active)
{
size_t j;
bool entry_valid = true;
for (j = 0; j < search_terms->size; j++)
{
const char *search_term = search_terms->terms[j];
if (search_term && *search_term)
{
bool cheat_on = cheat_manager_get_code_state(i);
/* Check for 'on' keyword */
if (string_is_equal_noncase(search_term, on_string))
{
if (!cheat_on)
entry_valid = false;
}
/* Check for 'off' keyword */
else if (string_is_equal_noncase(
search_term, off_string))
{
if (cheat_on)
entry_valid = false;
}
/* Normal label comparison */
else if (!compat_strcasestr(cheat_label, search_term))
entry_valid = false;
}
if (!entry_valid)
break;
}
if (!entry_valid)
continue;
}
if (menu_entries_append(list,
cheat_label, "", MSG_UNKNOWN,
MENU_SETTINGS_CHEAT_BEGIN + i, 0, 0, NULL))
{
num_cheats_shown++;
count++;
}
}
/* If a search is active and no results are
* found, show a 'no entries available' item */
if ( search_active
&& (num_cheats_shown < 1)
&& menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY_STR,
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL))
count++;
}
#endif
break;
#ifdef HAVE_GAME_AI
case DISPLAYLIST_OPTIONS_GAME_AI:
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_GAME_AI_OVERRIDE_P1,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_GAME_AI_OVERRIDE_P2,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_GAME_AI_SHOW_DEBUG,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
break;
#endif
case DISPLAYLIST_DROPDOWN_LIST_CRT_SUPER_RESOLUTION:
menu_entries_clear(list);
{
unsigned i;
settings_t *settings = config_get_ptr();
unsigned current = settings->uints.crt_switch_resolution_super;
static const unsigned values[] = { 0, 1, 1920, 2560, 3840 };
static const char * const names[] =
{ "NATIVE", "DYNAMIC", "1920", "2560", "3840" };
for (i = 0; i < sizeof(values) / sizeof(values[0]); i++)
{
char val_d[16];
snprintf(val_d, sizeof(val_d), "%u", values[i]);
if (menu_entries_append(list,
names[i],
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_CRT_SUPER_RESOLUTION,
i, 0, NULL))
count++;
if (values[i] == current)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)
list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_HEADSET_REFRESH_RATE:
menu_entries_clear(list);
{
unsigned values[2 + VIDEO_HEADSET_MAX_RATES];
unsigned i, n, current;
rarch_setting_t *setting = menu_setting_find_enum(
MENU_ENUM_LABEL_VIDEO_OPENXR_REFRESH_RATE);
if (!setting)
break;
current = setting_uint_get(setting);
n = video_driver_headset_rate_choices(values,
sizeof(values) / sizeof(values[0]));
/* Each row carries its value; its name is the setting's own. */
for (i = 0; i < n; i++)
{
char val_d[16];
char val_s[NAME_MAX_LENGTH];
setting_uint_set(setting, values[i]);
setting->actions->repr(setting, val_s, sizeof(val_s));
snprintf(val_d, sizeof(val_d), "%u", values[i]);
if (menu_entries_append(list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_HEADSET_REFRESH_RATE,
values[i], 0, NULL))
count++;
if (values[i] == current)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)
list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
setting_uint_set(setting, current);
}
break;
case DISPLAYLIST_DROPDOWN_LIST_RESOLUTION:
menu_entries_clear(list);
{
unsigned i, size = 0;
struct video_display_config *video_list = (struct video_display_config*)
video_display_server_get_resolution_list(&size);
if (video_list)
{
for (i = 0; i < size; i++)
{
char val_d[NAME_MAX_LENGTH], str[NAME_MAX_LENGTH];
/* If there is exact refresh rate available, use it */
if (video_list[i].refreshrate_float > 0.0f)
snprintf(str, sizeof(str), "%dx%d (%.3f Hz)%s%s",
VIDEO_SCALE_W(video_list[i].dims),
VIDEO_SCALE_H(video_list[i].dims),
video_list[i].refreshrate_float,
video_list[i].interlaced ? "[i]":"",
video_list[i].dblscan ? "[d]":"");
else
snprintf(str, sizeof(str), "%dx%d (%d Hz)%s",
VIDEO_SCALE_W(video_list[i].dims),
VIDEO_SCALE_H(video_list[i].dims),
video_list[i].refreshrate,
video_list[i].interlaced ? "[i]":"");
snprintf(val_d, sizeof(val_d), "%d", i);
if (menu_entries_append(list,
str,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_RESOLUTION,
video_list[i].idx, 0, NULL))
count++;
if (video_list[i].current)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
free(video_list);
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_DEFAULT_CORE:
menu_entries_clear(list);
{
core_info_list_t *core_info_list = NULL;
playlist_t *playlist = playlist_get_cached();
/* Get core list */
core_info_get_list(&core_info_list);
if (core_info_list && playlist)
{
size_t i;
const char *current_core_name = playlist_get_default_core_name(playlist);
core_info_t *core_info = NULL;
/* Sort cores alphabetically */
core_info_qsort(core_info_list, CORE_INFO_LIST_SORT_DISPLAY_NAME);
/* Add N/A entry */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE),
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_DEFAULT_CORE,
0, 0, NULL))
count++;
if ( (!current_core_name || !*current_core_name)
|| string_is_equal(current_core_name, FILE_PATH_DETECT))
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[0].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = 0;
}
/* Loop through cores */
for (i = 0; i < core_info_list->count; i++)
{
if ((core_info = core_info_get(core_info_list, i)))
{
if (menu_entries_append(list,
core_info->display_name,
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_DEFAULT_CORE,
i + 1, 0, NULL))
count++;
if (string_is_equal(current_core_name,
core_info->display_name))
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i + 1].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = (i + 1);
}
}
}
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_LABEL_DISPLAY_MODE:
menu_entries_clear(list);
{
playlist_t *playlist = playlist_get_cached();
if (playlist)
{
size_t i;
enum playlist_label_display_mode current_display_mode =
playlist_get_label_display_mode(playlist);
for (i = 0; i <= (unsigned)LABEL_DISPLAY_MODE_KEEP_REGION_AND_DISC_INDEX; i++)
{
enum msg_hash_enums label_value;
enum playlist_label_display_mode display_mode =
(enum playlist_label_display_mode)i;
switch (display_mode)
{
case LABEL_DISPLAY_MODE_REMOVE_PARENTHESES:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_REMOVE_PARENS;
break;
case LABEL_DISPLAY_MODE_REMOVE_BRACKETS:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_REMOVE_BRACKETS;
break;
case LABEL_DISPLAY_MODE_REMOVE_PARENTHESES_AND_BRACKETS:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_REMOVE_PARENS_AND_BRACKETS;
break;
case LABEL_DISPLAY_MODE_KEEP_REGION:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_KEEP_REGION;
break;
case LABEL_DISPLAY_MODE_KEEP_DISC_INDEX:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_KEEP_DISC_INDEX;
break;
case LABEL_DISPLAY_MODE_KEEP_REGION_AND_DISC_INDEX:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_KEEP_REGION_AND_DISC_INDEX;
break;
default:
/* LABEL_DISPLAY_MODE_DEFAULT */
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_LABEL_DISPLAY_MODE_DEFAULT;
break;
}
if (menu_entries_append(list,
msg_hash_to_str(label_value),
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_LABEL_DISPLAY_MODE,
0, 0, NULL))
count++;
if (current_display_mode == display_mode)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE:
menu_entries_clear(list);
count = populate_playlist_thumbnail_mode_dropdown_list(list, PLAYLIST_THUMBNAIL_RIGHT);
break;
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE:
menu_entries_clear(list);
count = populate_playlist_thumbnail_mode_dropdown_list(list, PLAYLIST_THUMBNAIL_LEFT);
break;
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_SORT_MODE:
menu_entries_clear(list);
{
playlist_t *playlist = playlist_get_cached();
if (playlist)
{
size_t i;
/* Get current sort mode */
enum playlist_sort_mode current_sort_mode =
playlist_get_sort_mode(playlist);
/* Loop over all defined sort modes */
for (i = 0; i <= (unsigned)PLAYLIST_SORT_MODE_OFF; i++)
{
enum msg_hash_enums label_value;
enum playlist_sort_mode sort_mode =
(enum playlist_sort_mode)i;
/* Get appropriate entry label */
switch (sort_mode)
{
case PLAYLIST_SORT_MODE_ALPHABETICAL:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_SORT_MODE_ALPHABETICAL;
break;
case PLAYLIST_SORT_MODE_OFF:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_SORT_MODE_OFF;
break;
case PLAYLIST_SORT_MODE_DEFAULT:
default:
label_value = MENU_ENUM_LABEL_VALUE_PLAYLIST_MANAGER_SORT_MODE_DEFAULT;
break;
}
/* Add entry */
if (menu_entries_append(list,
msg_hash_to_str(label_value),
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_PLAYLIST_SORT_MODE,
0, 0, NULL))
count++;
/* Check whether current entry is checked */
if (current_sort_mode == sort_mode)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_SCAN_METHOD:
menu_entries_clear(list);
{
struct string_list *scan_method_list =
manual_content_scan_get_menu_scan_method_list();
if (scan_method_list)
{
unsigned current = 0;
unsigned i;
/* Get currently selected system name */
current = manual_content_scan_get_scan_method_enum();
/* Loop through names */
for (i = 0; i < scan_method_list->size; i++)
{
const char *item = scan_method_list->elems[i].data;
/* Add menu entry */
if (menu_entries_append(list,
item,
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_SCAN_METHOD,
i, 0, NULL))
count++;
/* Check whether current entry is checked */
if (current == i)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
/* Clean up */
string_list_free(scan_method_list);
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_SCAN_USE_DB:
menu_entries_clear(list);
{
struct string_list *scan_use_db_list =
manual_content_scan_get_menu_scan_use_db_list();
if (scan_use_db_list)
{
unsigned current = 0;
unsigned i;
/* Get currently selected system name */
current = manual_content_scan_get_scan_use_db_enum();
/* Loop through names */
for (i = 0; i < scan_use_db_list->size; i++)
{
const char *item = scan_use_db_list->elems[i].data;
/* Add menu entry */
if (menu_entries_append(list,
item,
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_SCAN_USE_DB,
i, 0, NULL))
count++;
/* Check whether current entry is checked */
if (current == i)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
/* Clean up */
string_list_free(scan_use_db_list);
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_SCAN_DB_SELECT:
menu_entries_clear(list);
{
bool show_hidden_files = settings->bools.show_hidden_files;
#ifdef HAVE_LIBRETRODB
const char *path_content_database = settings->paths.path_content_database;
struct string_list *scan_db_select_list =
manual_content_scan_get_menu_scan_db_select_list(
path_content_database,
show_hidden_files);
#else
struct string_list *scan_db_select_list =
manual_content_scan_get_menu_scan_db_select_list(NULL,
show_hidden_files);
#endif
if (scan_db_select_list)
{
const char *current_system_name = NULL;
unsigned i;
/* Get currently selected system name */
manual_content_scan_get_menu_scan_db_select(&current_system_name);
/* Loop through names */
for (i = 0; i < scan_db_select_list->size; i++)
{
/* Note: manual_content_scan_get_system_name_list()
* ensures that system_name cannot be empty here */
const char *system_name = scan_db_select_list->elems[i].data;
/* Add menu entry */
if (menu_entries_append(list,
system_name,
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_SCAN_DB_SELECT,
i, 0, NULL))
count++;
/* Check whether current entry is checked */
if (string_is_equal(current_system_name, system_name))
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
/* Clean up */
string_list_free(scan_db_select_list);
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME:
menu_entries_clear(list);
/* Get system name list */
{
bool show_hidden_files = settings->bools.show_hidden_files;
#ifdef HAVE_LIBRETRODB
const char *path_content_database = settings->paths.path_content_database;
struct string_list *system_name_list =
manual_content_scan_get_menu_system_name_list(
path_content_database,
show_hidden_files);
#else
struct string_list *system_name_list =
manual_content_scan_get_menu_system_name_list(NULL,
show_hidden_files);
#endif
if (system_name_list)
{
const char *current_system_name = NULL;
unsigned i;
/* Get currently selected system name */
manual_content_scan_get_menu_system_name(&current_system_name);
/* Loop through names */
for (i = 0; i < system_name_list->size; i++)
{
/* Note: manual_content_scan_get_system_name_list()
* ensures that system_name cannot be empty here */
const char *system_name = system_name_list->elems[i].data;
/* Add menu entry */
if (menu_entries_append(list,
system_name,
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_MANUAL_CONTENT_SCAN_SYSTEM_NAME,
i, 0, NULL))
count++;
/* Check whether current entry is checked */
if (string_is_equal(current_system_name, system_name))
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
/* Clean up */
string_list_free(system_name_list);
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_MANUAL_CONTENT_SCAN_CORE_NAME:
menu_entries_clear(list);
{
/* Get core name list */
struct string_list *core_name_list =
manual_content_scan_get_menu_core_name_list();
if (core_name_list)
{
const char *current_core_name = NULL;
unsigned i;
/* Get currently selected core name */
manual_content_scan_get_menu_core_name(&current_core_name);
/* Loop through names */
for (i = 0; i < core_name_list->size; i++)
{
/* Note: manual_content_scan_get_core_name_list()
* ensures that core_name cannot be empty here */
const char *core_name = core_name_list->elems[i].data;
/* Add menu entry */
if (menu_entries_append(list,
core_name,
"",
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_MANUAL_CONTENT_SCAN_CORE_NAME,
i, 0, NULL))
count++;
/* Check whether current entry is checked */
if (string_is_equal(current_core_name, core_name))
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
/* Clean up */
string_list_free(core_name_list);
}
}
break;
case DISPLAYLIST_DROPDOWN_LIST_DISK_INDEX:
menu_entries_clear(list);
{
unsigned i;
unsigned num_images = 0;
unsigned current_image = 0;
unsigned num_digits = 0;
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
if (!sys_info || !disk_control_enabled(&sys_info->disk_control))
break;
num_images = disk_control_get_num_images(&sys_info->disk_control);
current_image = disk_control_get_image_index(&sys_info->disk_control);
/* If core supports labels, index value string
* should be padded to maximum width (otherwise
* labels will be misaligned/ugly) */
if (disk_control_image_label_enabled(&sys_info->disk_control))
{
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++)
{
size_t _len;
char current_image_str[PATH_MAX_LENGTH];
char image_label[128];
current_image_str[0] = '\0';
image_label[0] = '\0';
/* Get image label, if supported by core */
disk_control_get_image_label(
&sys_info->disk_control,
i, image_label, sizeof(image_label));
_len = snprintf(
current_image_str, sizeof(current_image_str),
"%0*u", num_digits, i + 1);
/* Get string representation of disk index
* > Note that displayed index starts at '1',
* not '0' */
if (*image_label)
{
_len += strlcpy_lit(current_image_str + _len,
": ",
sizeof(current_image_str) - _len);
strlcpy(current_image_str + _len,
image_label,
sizeof(current_image_str) - _len);
}
/* Add menu entry */
if (menu_entries_append(list,
current_image_str,
"",
(enum msg_hash_enums)MENU_SETTING_DROPDOWN_ITEM_DISK_INDEX,
MENU_SETTING_DROPDOWN_ITEM_DISK_INDEX,
i, 0, NULL))
count++;
/* Check whether current disk is selected */
if (i == current_image)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
}
break;
case DISPLAYLIST_PERFCOUNTERS_CORE:
case DISPLAYLIST_PERFCOUNTERS_FRONTEND:
{
unsigned i;
struct retro_perf_counter **counters =
(type == DISPLAYLIST_PERFCOUNTERS_CORE)
? retro_get_perf_counter_libretro()
: retro_get_perf_counter_rarch();
unsigned num =
(type == DISPLAYLIST_PERFCOUNTERS_CORE)
? retro_get_perf_count_libretro()
: retro_get_perf_count_rarch();
unsigned id =
(type == DISPLAYLIST_PERFCOUNTERS_CORE)
? MENU_SETTINGS_LIBRETRO_PERF_COUNTERS_BEGIN
: MENU_SETTINGS_PERF_COUNTERS_BEGIN;
if (counters && num != 0)
{
for (i = 0; i < num; i++)
if (counters[i] && counters[i]->ident)
if (menu_entries_append(list,
counters[i]->ident, "",
MSG_UNKNOWN,
id + i , 0, 0, NULL))
count++;
}
}
break;
case DISPLAYLIST_NETWORK_SETTINGS_LIST:
{
bool netplay_allow_slaves = settings->bools.netplay_allow_slaves;
bool netplay_use_mitm_server = settings->bools.netplay_use_mitm_server;
bool network_cmd_enable = settings->bools.network_cmd_enable;
bool network_remote_enable = settings->bools.network_remote_enable;
static menu_displaylist_build_info_selective_t build_list[] = {
#ifdef HAVE_SMBCLIENT
{MENU_ENUM_LABEL_SMB_CLIENT_SETTINGS, PARSE_ACTION, true},
#endif
#ifdef HAVE_NFSCLIENT
{MENU_ENUM_LABEL_NFS_CLIENT_SETTINGS, PARSE_ACTION, true},
#endif
{MENU_ENUM_LABEL_NETPLAY_PUBLIC_ANNOUNCE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_USE_MITM_SERVER, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_MITM_SERVER, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_NETPLAY_CUSTOM_MITM_SERVER, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_NETPLAY_IP_ADDRESS, PARSE_ONLY_STRING, true},
{MENU_ENUM_LABEL_NETPLAY_TCP_UDP_PORT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_MAX_CONNECTIONS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_MAX_PING, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_PASSWORD, PARSE_ONLY_STRING, true},
{MENU_ENUM_LABEL_NETPLAY_SPECTATE_PASSWORD, PARSE_ONLY_STRING, true},
{MENU_ENUM_LABEL_NETPLAY_START_AS_SPECTATOR, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_FADE_CHAT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_CHAT_COLOR_NAME, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_CHAT_COLOR_MSG, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_ALLOW_PAUSING, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_ALLOW_SLAVES, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_REQUIRE_SLAVES, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_NETPLAY_CHECK_FRAMES, PARSE_ONLY_INT, true},
{MENU_ENUM_LABEL_NETPLAY_INPUT_LATENCY_FRAMES_MIN, PARSE_ONLY_INT, true},
{MENU_ENUM_LABEL_NETPLAY_INPUT_LATENCY_FRAMES_RANGE, PARSE_ONLY_INT, true},
{MENU_ENUM_LABEL_NETPLAY_NAT_TRAVERSAL, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_SHARE_DIGITAL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_SHARE_ANALOG, PARSE_ONLY_UINT, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_NETPLAY_REQUIRE_SLAVES:
build_list[i].checked = netplay_allow_slaves;
break;
case MENU_ENUM_LABEL_NETPLAY_MITM_SERVER:
case MENU_ENUM_LABEL_NETPLAY_CUSTOM_MITM_SERVER:
build_list[i].checked = netplay_use_mitm_server;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
/* one entry for the sixteen Request Device switches */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_REQUEST_DEVICES),
MENU_ENUM_LABEL_NETPLAY_REQUEST_DEVICES_STR,
MENU_ENUM_LABEL_NETPLAY_REQUEST_DEVICES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_NETWORK_CMD_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (network_cmd_enable)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_NETWORK_CMD_PORT,
PARSE_ONLY_UINT, false) == 0)
count++;
}
#ifdef HAVE_MCP
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_MCP_SERVER_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (settings->bools.mcp_server_enable)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_MCP_SERVER_PORT,
PARSE_ONLY_UINT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_MCP_SERVER_TOKEN,
PARSE_ONLY_STRING, false) == 0)
count++;
}
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_NETWORK_REMOTE_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (network_remote_enable)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_NETWORK_REMOTE_PORT,
PARSE_ONLY_UINT, false) == 0)
count++;
#ifdef HAVE_NETWORKGAMEPAD
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_NETWORK_REMOTE_FIRST_SENDER,
PARSE_ONLY_BOOL, false) == 0)
count++;
#endif
/* one entry for the users' switches */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETWORK_REMOTE_USERS),
MENU_ENUM_LABEL_NETWORK_REMOTE_USERS_STR,
MENU_ENUM_LABEL_NETWORK_REMOTE_USERS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_STDIN_CMD_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
break;
case DISPLAYLIST_NETPLAY_LOBBY_FILTERS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_NETPLAY_SHOW_ONLY_CONNECTABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_SHOW_ONLY_INSTALLED_CORES, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_SHOW_PASSWORDED, PARSE_ONLY_BOOL, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_CHEAT_SEARCH_SETTINGS_LIST:
#ifdef HAVE_CHEATS
{
char cheat_label[64];
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_CHEAT_START_OR_RESTART, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_BIG_ENDIAN, PARSE_ONLY_BOOL },
{MENU_ENUM_LABEL_CHEAT_SEARCH_EXACT, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_SEARCH_LT, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_SEARCH_LTE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_SEARCH_GT, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_SEARCH_GTE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_SEARCH_EQ, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_SEARCH_NEQ, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_SEARCH_EQPLUS, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_SEARCH_EQMINUS, PARSE_ONLY_UINT },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
{
unsigned int address_mask = 0;
unsigned int address = 0;
unsigned int prev_val = 0;
unsigned int curr_val = 0;
cheat_label[0] = '\0';
cheat_manager_match_action(CHEAT_MATCH_ACTION_TYPE_VIEW,
cheat_manager_state.match_idx,
&address, &address_mask, &prev_val, &curr_val);
snprintf(cheat_label, sizeof(cheat_label),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_MATCH),
address, address_mask);
if (menu_entries_append(list,
cheat_label, "", MSG_UNKNOWN,
MENU_SETTINGS_CHEAT_MATCH, 0, 0, NULL))
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_CHEAT_BROWSE_MEMORY,
PARSE_ONLY_UINT, false) != -1)
count++;
cheat_label[0] = '\0';
snprintf(cheat_label, sizeof(cheat_label),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_MATCHES),
cheat_manager_state.num_matches);
if (menu_entries_append(list,
cheat_label,
MENU_ENUM_LABEL_CHEAT_ADD_MATCHES_STR,
MENU_ENUM_LABEL_CHEAT_ADD_MATCHES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_CHEAT_COPY_MATCH,
PARSE_ONLY_UINT, false) != -1)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_CHEAT_DELETE_MATCH,
PARSE_ONLY_UINT, false) != -1)
count++;
{
rarch_setting_t *setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_DELETE_MATCH);
if (setting)
setting->max = cheat_manager_state.num_matches - 1;
if ((setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_COPY_MATCH)))
setting->max = cheat_manager_state.num_matches - 1;
if ((setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_BROWSE_MEMORY)))
setting->max = (cheat_manager_state.total_memory_size > 0)
? cheat_manager_state.total_memory_size - 1 : 0;
}
}
#endif
break;
case DISPLAYLIST_CHEAT_DETAILS_SETTINGS_LIST:
#ifdef HAVE_CHEATS
{
if (!cheat_manager_state.memory_initialized)
cheat_manager_initialize_memory(NULL, 0, true);
{
rarch_setting_t *setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_ADDRESS);
if (setting)
setting->max = (cheat_manager_state.total_memory_size == 0)
? 0 : cheat_manager_state.total_memory_size - 1;
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_ADDRESS_BIT_POSITION);
if (setting)
setting->max = (cheat_manager_state.working_cheat.memory_search_size < 3)
? 255 : 0;
setting = menu_setting_find_enum(MENU_ENUM_LABEL_CHEAT_BROWSE_MEMORY);
if (setting)
setting->max = (cheat_manager_state.total_memory_size > 0)
? cheat_manager_state.total_memory_size - 1 : 0;
}
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_CHEAT_IDX, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_STATE, PARSE_ONLY_BOOL },
{MENU_ENUM_LABEL_CHEAT_DESC, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_CHEAT_HANDLER, PARSE_ONLY_UINT },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
if (cheat_manager_state.working_cheat.handler == CHEAT_HANDLER_TYPE_EMU)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_CHEAT_CODE,
PARSE_ONLY_STRING, false) == 0)
count++;
}
else
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_CHEAT_MEMORY_SEARCH_SIZE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_TYPE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_VALUE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_ADDRESS, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_BROWSE_MEMORY, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_ADDRESS_BIT_POSITION, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_REPEAT_COUNT, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_REPEAT_ADD_TO_ADDRESS, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_REPEAT_ADD_TO_VALUE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_RUMBLE_TYPE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_RUMBLE_VALUE, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_RUMBLE_PORT, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_RUMBLE_PRIMARY_STRENGTH, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_RUMBLE_PRIMARY_DURATION, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_RUMBLE_SECONDARY_STRENGTH, PARSE_ONLY_UINT },
{MENU_ENUM_LABEL_CHEAT_RUMBLE_SECONDARY_DURATION, PARSE_ONLY_UINT },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
/* Inspect Memory At this Address */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_AFTER),
MENU_ENUM_LABEL_CHEAT_ADD_NEW_AFTER_STR,
MENU_ENUM_LABEL_CHEAT_ADD_NEW_AFTER,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_ADD_NEW_BEFORE),
MENU_ENUM_LABEL_CHEAT_ADD_NEW_BEFORE_STR,
MENU_ENUM_LABEL_CHEAT_ADD_NEW_BEFORE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_COPY_AFTER),
MENU_ENUM_LABEL_CHEAT_COPY_AFTER_STR,
MENU_ENUM_LABEL_CHEAT_COPY_AFTER,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_COPY_BEFORE),
MENU_ENUM_LABEL_CHEAT_COPY_BEFORE_STR,
MENU_ENUM_LABEL_CHEAT_COPY_BEFORE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CHEAT_DELETE),
MENU_ENUM_LABEL_CHEAT_DELETE_STR,
MENU_ENUM_LABEL_CHEAT_DELETE,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#endif
break;
case DISPLAYLIST_RECORDING_SETTINGS_LIST:
{
unsigned streaming_mode = settings->uints.streaming_mode;
bool is_ffmpeg = !strcmp(
settings->arrays.record_driver, "ffmpeg");
bool has_video = is_ffmpeg
|| !strcmp(
settings->arrays.record_driver, "avfoundation");
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_RECORD_DRIVER, PARSE_ONLY_STRING_OPTIONS, true},
{MENU_ENUM_LABEL_VIDEO_RECORD_QUALITY, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_RECORD_CONFIG, PARSE_ONLY_PATH, false},
{MENU_ENUM_LABEL_VIDEO_RECORD_THREADS, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_POST_FILTER_RECORD, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_GPU_RECORD, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_RECORD_GAME_ONLY, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_RECORD_ALLOW_FRAME_DROP, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_RECORD_HW_ENCODER, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_RECORD_FIFO_FRAMES, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_STREAMING_MODE, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_STREAM_QUALITY, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_STREAM_CONFIG, PARSE_ONLY_PATH, false},
{MENU_ENUM_LABEL_STREAMING_TITLE, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_STREAMING_URL, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_UDP_STREAM_PORT, PARSE_ONLY_UINT, false},
};
build_list[1].checked = has_video; /* MENU_ENUM_LABEL_VIDEO_RECORD_QUALITY */
build_list[2].checked = is_ffmpeg; /* MENU_ENUM_LABEL_RECORD_CONFIG */
build_list[3].checked = is_ffmpeg; /* MENU_ENUM_LABEL_VIDEO_RECORD_THREADS */
build_list[4].checked = has_video; /* MENU_ENUM_LABEL_VIDEO_POST_FILTER_RECORD */
build_list[5].checked = has_video; /* MENU_ENUM_LABEL_VIDEO_GPU_RECORD */
build_list[6].checked = has_video; /* MENU_ENUM_LABEL_VIDEO_RECORD_GAME_ONLY */
build_list[7].checked = is_ffmpeg; /* MENU_ENUM_LABEL_VIDEO_RECORD_ALLOW_FRAME_DROP */
build_list[8].checked = is_ffmpeg; /* MENU_ENUM_LABEL_VIDEO_RECORD_HW_ENCODER */
build_list[9].checked = is_ffmpeg; /* MENU_ENUM_LABEL_VIDEO_RECORD_FIFO_FRAMES */
build_list[10].checked = is_ffmpeg; /* MENU_ENUM_LABEL_STREAMING_MODE */
build_list[11].checked = is_ffmpeg; /* MENU_ENUM_LABEL_VIDEO_STREAM_QUALITY */
build_list[12].checked = is_ffmpeg; /* MENU_ENUM_LABEL_STREAM_CONFIG */
build_list[13].checked = is_ffmpeg; /* MENU_ENUM_LABEL_STREAMING_TITLE */
build_list[14].checked = is_ffmpeg; /* MENU_ENUM_LABEL_STREAMING_URL */
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_UDP_STREAM_PORT:
build_list[i].checked =
(is_ffmpeg && streaming_mode == STREAMING_MODE_LOCAL);
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (build_list[i].checked &&
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_ACCOUNTS_YOUTUBE_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_YOUTUBE_STREAM_KEY, PARSE_ONLY_STRING},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_RETRO_ACHIEVEMENTS_SETTINGS_LIST:
{
bool cheevos_enable = settings->bools.cheevos_enable;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_CHEEVOS_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CHEEVOS_USERNAME, PARSE_ONLY_STRING, false },
{MENU_ENUM_LABEL_CHEEVOS_PASSWORD, PARSE_ONLY_STRING, false },
{MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_SETTINGS, PARSE_ACTION, false },
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_SETTINGS, PARSE_ACTION, false },
{MENU_ENUM_LABEL_CHEEVOS_HARDCORE_MODE_ENABLE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_CHEEVOS_LEADERBOARDS_ENABLE, PARSE_ONLY_STRING_OPTIONS, false },
{MENU_ENUM_LABEL_CHEEVOS_RICHPRESENCE_ENABLE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_CHEEVOS_BADGES_ENABLE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_CHEEVOS_TEST_UNOFFICIAL, PARSE_ONLY_BOOL, false },
#ifdef HAVE_AUDIOMIXER
{MENU_ENUM_LABEL_CHEEVOS_UNLOCK_SOUND_ENABLE, PARSE_ONLY_BOOL, false },
#endif
#ifdef HAVE_SCREENSHOTS
{MENU_ENUM_LABEL_CHEEVOS_AUTO_SCREENSHOT, PARSE_ONLY_BOOL, false },
#endif
{MENU_ENUM_LABEL_CHEEVOS_START_ACTIVE, PARSE_ONLY_BOOL, false },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
/* The build_list array is static, so 'checked' retains
* state from previous menu builds. We must explicitly
* reset it on each pass: only CHEEVOS_ENABLE itself is
* always shown; everything else is gated on it. */
if (build_list[i].enum_idx == MENU_ENUM_LABEL_CHEEVOS_ENABLE)
build_list[i].checked = true;
else
build_list[i].checked = cheevos_enable;
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_CHEEVOS_APPEARANCE_SETTINGS_LIST:
{
#if defined(HAVE_CHEEVOS) && defined(HAVE_GFX_WIDGETS)
unsigned cheevos_anchor = settings->uints.cheevos_appearance_anchor;
bool cheevos_autopad = settings->bools.cheevos_appearance_padding_auto;
bool gfx_widgets = settings->bools.menu_enable_widgets;
#endif
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_ANCHOR, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_PADDING_AUTO, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_PADDING_H, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_PADDING_V, PARSE_ONLY_FLOAT, false},
};
#if defined(HAVE_CHEEVOS) && defined(HAVE_GFX_WIDGETS)
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_ANCHOR:
case MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_PADDING_AUTO:
build_list[i].checked = gfx_widgets;
break;
case MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_PADDING_V:
build_list[i].checked = (gfx_widgets && !cheevos_autopad);
break;
case MENU_ENUM_LABEL_CHEEVOS_APPEARANCE_PADDING_H:
build_list[i].checked = ((gfx_widgets && !cheevos_autopad) &&
!(cheevos_anchor == CHEEVOS_APPEARANCE_ANCHOR_TOPCENTER ||
cheevos_anchor == CHEEVOS_APPEARANCE_ANCHOR_BOTTOMCENTER));
break;
default:
break;
}
}
#endif
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_CHEEVOS_VISIBILITY_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_SUMMARY, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_UNLOCK, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_MASTERY, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_CHALLENGE_INDICATORS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_PROGRESS_TRACKER, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_LBOARD_START, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_LBOARD_SUBMIT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_LBOARD_CANCEL, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_LBOARD_TRACKERS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_VISIBILITY_ACCOUNT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CHEEVOS_VERBOSE_ENABLE, PARSE_ONLY_BOOL, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_ACCOUNTS_TWITCH_LIST:
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_TWITCH_STREAM_KEY,
PARSE_ONLY_STRING, false) == 0)
count++;
break;
case DISPLAYLIST_ACCOUNTS_FACEBOOK_LIST:
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_FACEBOOK_STREAM_KEY,
PARSE_ONLY_STRING, false) == 0)
count++;
break;
case DISPLAYLIST_ACCOUNTS_KICK_LIST:
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_KICK_STREAM_KEY,
PARSE_ONLY_STRING, false) == 0)
count++;
break;
case DISPLAYLIST_USER_INTERFACE_SETTINGS_LIST:
{
bool kiosk_mode_enable = settings->bools.kiosk_mode_enable;
#ifdef HAVE_COMPANION_WIMP
bool desktop_menu_enable = settings->bools.desktop_menu_enable;
#endif
bool menu_screensaver_supported = ((menu_st->flags & MENU_ST_FLAG_SCREENSAVER_SUPPORTED) > 0);
#if defined(HAVE_MATERIALUI) || defined(HAVE_XMB) || defined(HAVE_OZONE)
enum menu_screensaver_effect menu_screensaver_animation =
(enum menu_screensaver_effect)
settings->uints.menu_screensaver_animation;
#endif
uico_driver_state_t *uico_st = uico_state_get_ptr();
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_MENU_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_MENU_VIEWS_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_INPUT_MENU_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, PARSE_ACTION, true},
#if defined(HAVE_OVERLAY)
{MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS, PARSE_ACTION, true},
#endif
{MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_PAUSE_LIBRETRO, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PAUSE_NONACTIVE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_PAUSE_ON_DISCONNECT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_SAVESTATE_RESUME, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_INSERT_DISK_RESUME, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_QUIT_ON_CLOSE_CONTENT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_REMEMBER_SELECTION, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_STARTUP_PAGE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_CONFIRM_QUIT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CONFIRM_CLOSE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CONFIRM_RESET, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NAVIGATION_WRAPAROUND, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SHOW_ADVANCED_SETTINGS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_ENABLE_KIOSK_MODE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_KIOSK_MODE_PASSWORD, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_THREADED_DATA_RUNLOOP_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_THREAD_PREFER_FAST_CORES, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_VIDEO_THREAD_PRIORITY, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MAIN_THREAD_PRIORITY, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_SCREENSAVER_TIMEOUT, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_MENU_SCREENSAVER_ANIMATION, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_MENU_SCREENSAVER_ANIMATION_SPEED, PARSE_ONLY_FLOAT, false},
#if !TARGET_OS_OSX
{MENU_ENUM_LABEL_VIDEO_DISABLE_COMPOSITION, PARSE_ONLY_BOOL, true},
#endif
#ifdef HAVE_COMPANION_WIMP
{MENU_ENUM_LABEL_UI_COMPANION_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_UI_COMPANION_START_ON_BOOT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_UI_COMPANION_TOGGLE, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_DESKTOP_MENU_ENABLE, PARSE_ONLY_BOOL, true},
/* Presentation settings shared by every desktop companion. */
{MENU_ENUM_LABEL_DESKTOP_MENU_VIEW_TYPE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_THUMBNAIL_TYPE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_SUGGEST_LOADED_CORE_FIRST, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_SAVE_LAST_TAB, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_SAVE_GEOMETRY, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_SHOW_WELCOME_SCREEN, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_SCAN_FINISH_CONFIRM, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_THUMBNAIL_CACHE_LIMIT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_THUMBNAIL_MAX_SIZE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_THUMBNAIL_QUALITY, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_ICON_VIEW_ZOOM, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_ALL_PLAYLISTS_LIST_MAX_COUNT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_ALL_PLAYLISTS_GRID_MAX_COUNT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_DESKTOP_MENU_THEME, PARSE_ONLY_UINT, true},
#endif
#ifdef _3DS
{MENU_ENUM_LABEL_VIDEO_3DS_DISPLAY_MODE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_BOTTOM_SETTINGS, PARSE_ACTION, true},
#endif
{MENU_ENUM_LABEL_APPICON_SETTINGS, PARSE_ONLY_STRING_OPTIONS, false},
{MENU_ENUM_LABEL_USER_LANGUAGE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_DRIVER, PARSE_ONLY_STRING_OPTIONS, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_APPICON_SETTINGS:
if (uico_st->drv && uico_st->drv->get_app_icons)
{
struct string_list *icons = uico_st->drv->get_app_icons();
build_list[i].checked = icons && icons->size > 1;
}
break;
case MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS:
case MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS:
build_list[i].checked = settings->bools.settings_show_onscreen_display;
break;
case MENU_ENUM_LABEL_MENU_FILE_BROWSER_SETTINGS:
build_list[i].checked = settings->bools.settings_show_file_browser;
break;
case MENU_ENUM_LABEL_MENU_KIOSK_MODE_PASSWORD:
build_list[i].checked = kiosk_mode_enable;
break;
case MENU_ENUM_LABEL_MENU_SCREENSAVER_TIMEOUT:
build_list[i].checked = menu_screensaver_supported;
break;
#if defined(HAVE_MATERIALUI) || defined(HAVE_XMB) || defined(HAVE_OZONE)
case MENU_ENUM_LABEL_MENU_SCREENSAVER_ANIMATION:
build_list[i].checked = menu_screensaver_supported;
break;
case MENU_ENUM_LABEL_MENU_SCREENSAVER_ANIMATION_SPEED:
build_list[i].checked =
menu_screensaver_supported
&& (menu_screensaver_animation != MENU_SCREENSAVER_BLANK);
break;
#endif
#ifdef HAVE_COMPANION_WIMP
case MENU_ENUM_LABEL_UI_COMPANION_TOGGLE:
build_list[i].checked = desktop_menu_enable;
break;
#endif
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_OPTIONS_DISK:
count = menu_displaylist_parse_disk_options(list);
break;
case DISPLAYLIST_MIDI_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_MIDI_OUTPUT, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_MIDI_INPUT, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_MIDI_VOLUME, PARSE_ONLY_UINT },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_VIDEO_WINDOWED_MODE_SETTINGS_LIST:
{
#if (defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)) || \
(defined(HAVE_COCOA) && !defined(HAVE_COCOATOUCH)) || \
defined(HAVE_SDL3) && !defined(WEBOS)
bool window_custom_size_enable = settings->bools.video_window_save_positions;
#else
bool window_custom_size_enable = settings->bools.video_window_custom_size_enable;
#endif
static menu_displaylist_build_info_selective_t build_list[] = {
#if (defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)) || \
(defined(HAVE_COCOA) && !defined(HAVE_COCOATOUCH)) || \
defined(HAVE_SDL3) && !defined(WEBOS)
{MENU_ENUM_LABEL_VIDEO_WINDOW_SAVE_POSITION, PARSE_ONLY_BOOL, true },
#else
{MENU_ENUM_LABEL_VIDEO_WINDOW_CUSTOM_SIZE_ENABLE, PARSE_ONLY_BOOL, true },
#endif
{MENU_ENUM_LABEL_VIDEO_SCALE, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_WINDOW_WIDTH, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_WINDOW_HEIGHT, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_WINDOW_AUTO_WIDTH_MAX, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_WINDOW_AUTO_HEIGHT_MAX, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_WINDOW_OPACITY, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_VIDEO_WINDOW_SHOW_DECORATIONS, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_UI_MENUBAR_ENABLE, PARSE_ONLY_BOOL, true },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_VIDEO_SCALE:
build_list[i].checked = !window_custom_size_enable;
break;
case MENU_ENUM_LABEL_VIDEO_WINDOW_WIDTH:
case MENU_ENUM_LABEL_VIDEO_WINDOW_HEIGHT:
build_list[i].checked = window_custom_size_enable;
break;
case MENU_ENUM_LABEL_VIDEO_WINDOW_AUTO_WIDTH_MAX:
case MENU_ENUM_LABEL_VIDEO_WINDOW_AUTO_HEIGHT_MAX:
build_list[i].checked = !window_custom_size_enable;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_VIDEO_FULLSCREEN_MODE_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_VIDEO_FULLSCREEN, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_VIDEO_WINDOWED_FULLSCREEN, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_VIDEO_FSE_NEGOTIATION, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_VIDEO_FULLSCREEN_X, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_VIDEO_FULLSCREEN_Y, PARSE_ONLY_UINT, true },
#ifdef __WINRT__
{MENU_ENUM_LABEL_VIDEO_FORCE_RESOLUTION, PARSE_ONLY_BOOL, true },
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_VIDEO_OUTPUT_SETTINGS_LIST:
{
bool *threaded = video_driver_get_threaded();
{
static const menu_displaylist_settings_row_t dl_rows_8[] = {
{ MENU_ENUM_LABEL_VIDEO_DRIVER, PARSE_ONLY_STRING_OPTIONS, false },
{ MENU_ENUM_LABEL_VIDEO_THREADED, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_VIDEO_GPU_INDEX, PARSE_ONLY_INT, false },
{ MENU_ENUM_LABEL_VIDEO_MONITOR_INDEX, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_VIDEO_SWAPCHAIN_BIT_DEPTH, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_VIDEO_HW_DECODE, PARSE_ONLY_UINT, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_8, (unsigned)ARRAY_SIZE(dl_rows_8));
#if defined(_WIN32) && !defined(__WINRT__)
if ( video_context_driver_get_api() == GFX_CTX_OPENGL_API
|| video_context_driver_get_api() == GFX_CTX_VULKAN_API)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_DXGI_PRESENT,
PARSE_ONLY_BOOL, false) == 0)
count++;
#endif
/* Only the GPUs the driver found: an index past them
* names no device, and picking one leaves the frontend
* on a GPU that may not reach the display at all. */
{
rarch_setting_t *gpu_setting = menu_setting_find_enum(
MENU_ENUM_LABEL_VIDEO_GPU_INDEX);
struct string_list *gpu_devices =
video_driver_get_gpu_api_devices(
video_context_driver_get_api());
if (gpu_setting && gpu_devices && gpu_devices->size > 0)
gpu_setting->max = (float)(gpu_devices->size - 1);
}
menu_displaylist_monitor_index_range();
}
#if defined(WIIU)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_WIIU_PREFER_DRC,
PARSE_ONLY_BOOL, false) == 0)
count++;
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_ROTATION,
PARSE_ONLY_UINT, false) == 0)
count++;
if (video_display_server_can_set_screen_orientation())
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_SCREEN_ORIENTATION,
PARSE_ONLY_UINT, false) == 0)
count++;
#if defined(PS2)
if (true)
#else
if (video_display_server_has_resolution_list())
#endif
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_SCREEN_RESOLUTION,
PARSE_ACTION, false) == 0)
count++;
}
#if defined(HAVE_WINDOW_OFFSET)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_WINDOW_OFFSET_X,
PARSE_ONLY_INT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_WINDOW_OFFSET_Y,
PARSE_ONLY_INT, false) == 0)
count++;
#endif
{
static const menu_displaylist_settings_row_t dl_rows_9[] = {
{ MENU_ENUM_LABEL_PAL60_ENABLE, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_VIDEO_GAMMA, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_VIDEO_SOFT_FILTER, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_VIDEO_FILTER_FLICKER, PARSE_ONLY_UINT, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_9, (unsigned)ARRAY_SIZE(dl_rows_9));
}
#if defined(DINGUX) && defined(DINGUX_BETA)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_DINGUX_REFRESH_RATE,
PARSE_ONLY_UINT, false) == 0)
count++;
#endif
if (threaded && !*threaded)
{
{
static const menu_displaylist_settings_row_t dl_rows_10[] = {
{ MENU_ENUM_LABEL_VIDEO_REFRESH_RATE, PARSE_ONLY_FLOAT, false },
{ MENU_ENUM_LABEL_VIDEO_REFRESH_RATE_POLLED, PARSE_ONLY_FLOAT, false },
{ MENU_ENUM_LABEL_VIDEO_REFRESH_RATE_AUTO, PARSE_ONLY_FLOAT, false },
/* Governs the estimate on the row above; lives beside it. */
{ MENU_ENUM_LABEL_VIDEO_FRAME_TIME_SAMPLE_FROM_DISPLAY, PARSE_ONLY_BOOL, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_10, (unsigned)ARRAY_SIZE(dl_rows_10));
}
}
if (video_display_server_has_resolution_list())
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_AUTOSWITCH_REFRESH_RATE,
PARSE_ONLY_UINT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_AUTOSWITCH_PAL_THRESHOLD,
PARSE_ONLY_FLOAT, false) == 0)
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_FORCE_SRGB_DISABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
break;
case DISPLAYLIST_VIDEO_SYNCHRONIZATION_SETTINGS_LIST:
{
size_t i;
bool video_vsync = settings->bools.video_vsync;
bool video_hard_sync = settings->bools.video_hard_sync;
bool video_wait_swap = settings->bools.video_waitable_swapchains;
unsigned bfi = settings->uints.video_black_frame_insertion;
unsigned shader_subframes = settings->uints.video_shader_subframes;
bool sub_shaders = video_driver_test_all_flags(GFX_CTX_FLAGS_SUBFRAME_SHADERS);
bool adaptive_vsync = video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC);
bool hard_sync = video_driver_test_all_flags(GFX_CTX_FLAGS_HARD_SYNC);
bool frame_latency = video_driver_test_all_flags(GFX_CTX_FLAGS_CUSTOMIZABLE_FRAME_LATENCY);
bool swapchain_images = video_driver_test_all_flags(GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES);
/* checked is the AND of every runtime condition that gated
* the entry in the previous inline form; order preserved. */
menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_VIDEO_VSYNC, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_VIDEO_SWAP_INTERVAL, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_SHADER_SUBFRAMES, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_SCAN_SUBFRAMES, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION,PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_BFI_DARK_FRAMES, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_ADAPTIVE_VSYNC, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_HARD_SYNC, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_HARD_SYNC_FRAMES, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VIDEO_D3D9EX_PRESENT, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_THREADED_PRESENT_REPEAT, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_THREADED_DISPLAY_PACING, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_PRESENT_TIMING_FROM_DISPLAY, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY, PARSE_ONLY_INT, false},
{MENU_ENUM_LABEL_VIDEO_MAX_SWAPCHAIN_IMAGES, PARSE_ONLY_UINT, false},
#if defined(HAVE_D3DKMT) || defined(HAVE_KMS)
{MENU_ENUM_LABEL_VIDEO_SCANLINE_SYNC, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_VIDEO_SCANLINE_SYNC_OFFSET, PARSE_ONLY_UINT, true},
#endif
{MENU_ENUM_LABEL_VIDEO_FRAME_DELAY_AUTO, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_VIDEO_FRAME_DELAY, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_VIDEO_DRIVER_PACING, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE, PARSE_ONLY_BOOL, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_VIDEO_SWAP_INTERVAL:
case MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION:
build_list[i].checked = video_vsync;
break;
case MENU_ENUM_LABEL_VIDEO_SHADER_SUBFRAMES:
build_list[i].checked = video_vsync && sub_shaders;
break;
case MENU_ENUM_LABEL_VIDEO_SCAN_SUBFRAMES:
build_list[i].checked = video_vsync && sub_shaders && (shader_subframes > 1);
break;
case MENU_ENUM_LABEL_VIDEO_BFI_DARK_FRAMES:
build_list[i].checked = video_vsync && (bfi > 0);
break;
case MENU_ENUM_LABEL_VIDEO_ADAPTIVE_VSYNC:
build_list[i].checked = video_vsync && adaptive_vsync;
break;
case MENU_ENUM_LABEL_VIDEO_HARD_SYNC:
build_list[i].checked = video_vsync && hard_sync;
break;
case MENU_ENUM_LABEL_VIDEO_HARD_SYNC_FRAMES:
build_list[i].checked = video_vsync && hard_sync && video_hard_sync;
break;
case MENU_ENUM_LABEL_VIDEO_D3D9EX_PRESENT:
{
/* Only the Direct3D 9 drivers read it */
const char *ident = video_driver_get_ident();
build_list[i].checked =
string_is_equal(ident, "d3d9_hlsl")
|| string_is_equal(ident, "d3d9_cg");
}
break;
case MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS:
build_list[i].checked = video_vsync && frame_latency;
break;
case MENU_ENUM_LABEL_VIDEO_PRESENT_TIMING_FROM_DISPLAY:
/* Only where a repeat can happen at all: this is
* what paces one. */
build_list[i].checked = *video_driver_get_threaded()
&& !video_driver_is_hw_context()
&& config_get_ptr()->bools.video_threaded_present_repeat;
break;
build_list[i].checked = *video_driver_get_threaded();
break;
case MENU_ENUM_LABEL_VIDEO_THREADED_DISPLAY_PACING:
build_list[i].checked = *video_driver_get_threaded()
&& !video_driver_is_hw_context();
break;
case MENU_ENUM_LABEL_VIDEO_THREADED_PRESENT_REPEAT:
/* Only where threaded video is on and can be honoured:
* a hardware-rendered core runs unthreaded whatever
* the setting says. */
build_list[i].checked = *video_driver_get_threaded()
&& !video_driver_is_hw_context();
break;
case MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY:
build_list[i].checked = video_vsync && frame_latency && video_wait_swap;
break;
case MENU_ENUM_LABEL_VIDEO_MAX_SWAPCHAIN_IMAGES:
build_list[i].checked = swapchain_images;
break;
case MENU_ENUM_LABEL_VIDEO_DRIVER_PACING:
/* The drivers with a backend for the release */
{
const char *ident = video_driver_get_ident();
build_list[i].checked =
string_is_equal(ident, "vulkan")
|| string_is_equal(ident, "d3d11")
|| string_is_equal(ident, "d3d12");
}
break;
case MENU_ENUM_LABEL_VIDEO_SCANLINE_SYNC:
case MENU_ENUM_LABEL_VIDEO_SCANLINE_SYNC_OFFSET:
/* Kept while on, so it can be turned off */
build_list[i].checked = video_display_server_has_scanline()
|| settings->bools.video_scanline_sync;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
/* These rows are hard-gated by live driver state exactly
* as the previous inline form was; include_everything
* does not relax them, preserving the fingerprint. */
if (!build_list[i].checked)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_VIDEO_HDR_SETTINGS_LIST:
{
if ((video_driver_get_disp_flags() & VIDEO_FLAG_HDR_SUPPORT))
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HDR_ENABLE,
PARSE_ONLY_UINT, false) == 0)
count++;
if (settings->uints.video_hdr_mode > 0)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HDR_PAPER_WHITE_NITS,
PARSE_ONLY_FLOAT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HDR_MAX_NITS,
PARSE_ONLY_FLOAT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HDR_USE_DISPLAY_PEAK,
PARSE_ONLY_BOOL, false) == 0)
count++;
#ifdef HAVE_WAYLAND
/* Only the Wayland context reads this */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HDR_SEND_LUMINANCE,
PARSE_ONLY_BOOL, false) == 0)
count++;
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HDR_EXPAND_GAMUT,
PARSE_ONLY_UINT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HDR_SCANLINES,
PARSE_ONLY_BOOL, false) == 0)
count++;
if(settings->bools.video_hdr_scanlines)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HDR_SUBPIXEL_LAYOUT,
PARSE_ONLY_UINT, false) == 0)
count++;
}
}
}
}
break;
case DISPLAYLIST_VIDEO_STEREO_SETTINGS_LIST:
#ifdef HAVE_OPENXR
/* A headset gives each eye its own image. */
#ifdef ANDROID
if (!video_context_driver_headset_inline())
#else
if ( !settings->bools.video_openxr_enable
|| !video_driver_has_headset_path(
settings->arrays.video_driver))
#endif
#endif
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_STEREO_MODE,
PARSE_ONLY_UINT, false) == 0)
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_STEREO_SWAP_EYES,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SCREEN_LAYOUT,
PARSE_ONLY_UINT, false) == 0)
count++;
#ifdef HAVE_OPENXR
if (video_driver_has_headset_path(settings->arrays.video_driver))
{
#ifndef ANDROID
/* A headset's own context needs no switch: Android starts
* in the headset when there is one. */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_OPENXR_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_OPENXR_REFRESH_RATE,
PARSE_ONLY_UINT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_OPENXR_PERF_BOOST,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_OPENXR_DISTANCE,
PARSE_ONLY_FLOAT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_OPENXR_WIDTH,
PARSE_ONLY_FLOAT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_OPENXR_PLACEMENT,
PARSE_ONLY_UINT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_OPENXR_CONTROLLERS,
PARSE_ONLY_UINT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_OPENXR_LASER,
PARSE_ONLY_UINT, false) == 0)
count++;
}
#endif
break;
case DISPLAYLIST_VIDEO_SCALING_SETTINGS_LIST:
{
#if defined(DINGUX)
if ( string_is_equal(settings->arrays.video_driver, "sdl_dingux")
|| string_is_equal(settings->arrays.video_driver, "sdl_rs90"))
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_DINGUX_IPU_KEEP_ASPECT,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
else
#endif
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (settings->bools.video_scale_integer)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER_AXIS,
PARSE_ONLY_UINT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER_SCALING,
PARSE_ONLY_UINT, false) == 0)
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_ASPECT_RATIO_INDEX,
PARSE_ONLY_UINT, false) == 0)
count++;
switch (settings->uints.video_aspect_ratio_idx)
{
case ASPECT_RATIO_CONFIG:
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_ASPECT_RATIO,
PARSE_ONLY_FLOAT, false) == 0)
count++;
break;
case ASPECT_RATIO_CUSTOM:
{
static const menu_displaylist_settings_row_t dl_rows_11[] = {
{ MENU_ENUM_LABEL_VIDEO_VIEWPORT_CUSTOM_X, PARSE_ONLY_INT, false },
{ MENU_ENUM_LABEL_VIDEO_VIEWPORT_CUSTOM_Y, PARSE_ONLY_INT, false },
{ MENU_ENUM_LABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT, PARSE_ONLY_UINT, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_11, (unsigned)ARRAY_SIZE(dl_rows_11));
}
break;
default:
break;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_X,
PARSE_ONLY_FLOAT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_Y,
PARSE_ONLY_FLOAT, false) == 0)
count++;
#if defined(RARCH_MOBILE)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_X,
PARSE_ONLY_FLOAT, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_VIEWPORT_BIAS_PORTRAIT_Y,
PARSE_ONLY_FLOAT, false) == 0)
count++;
#endif
}
{
static const menu_displaylist_settings_row_t dl_rows_12[] = {
{ MENU_ENUM_LABEL_VIDEO_VI_WIDTH, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_VIDEO_VFILTER, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_VIDEO_SMOOTH, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_VIDEO_CROP_OVERSCAN, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_VIDEO_OVERSCAN_CORRECTION_TOP, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_VIDEO_OVERSCAN_CORRECTION_BOTTOM, PARSE_ONLY_UINT, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_12, (unsigned)ARRAY_SIZE(dl_rows_12));
}
}
break;
case DISPLAYLIST_CRT_SWITCHRES_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_CRT_SWITCH_HIRES_MENU, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_USE_CUSTOM_REFRESH_RATE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CRT_SWITCH_RESOLUTION_SUPER, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_CRT_SWITCH_PORCH_ADJUST, PARSE_ONLY_INT },
{MENU_ENUM_LABEL_CRT_SWITCH_X_AXIS_CENTERING, PARSE_ONLY_INT },
{MENU_ENUM_LABEL_CRT_SWITCH_VERTICAL_ADJUST, PARSE_ONLY_INT },
#ifdef HAVE_MODELINE
{MENU_ENUM_LABEL_CRT_SWITCH_WRITE_EDID, PARSE_ACTION },
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
#ifdef HAVE_LAKKA
case DISPLAYLIST_LAKKA_SERVICES_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_SSH_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SAMBA_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_BLUETOOTH_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_LOCALAP_ENABLE, PARSE_ONLY_BOOL},
#ifdef HAVE_RETROFLAG
{MENU_ENUM_LABEL_SAFESHUTDOWN_ENABLE, PARSE_ONLY_BOOL},
#endif
{MENU_ENUM_LABEL_TIMEZONE, PARSE_ONLY_STRING_OPTIONS},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
#endif
#ifdef HAVE_LAKKA_SWITCH
case DISPLAYLIST_LAKKA_SWITCH_OPTIONS_LIST:
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_SWITCH_OC_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
/* Reboot-to-payload needs the pmc_r2p kernel driver. The
* payload selector has no backing rarch_setting_t; its
* Left/Right/OK/value callbacks live in menu/cbs. */
if (r2p_is_supported())
{
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_REBOOT_PAYLOAD),
msg_hash_to_str(MENU_ENUM_LABEL_REBOOT_PAYLOAD),
MENU_ENUM_LABEL_REBOOT_PAYLOAD,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_REBOOT_FORCE_SELF_ON_UPDATE,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_SWITCH_CEC_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_BLUETOOTH_ERTM_DISABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
break;
#endif
case DISPLAYLIST_MENU_VIEWS_SETTINGS_LIST:
{
const char *menu_driver = menu_driver_ident();
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_QUICK_MENU_VIEWS_SETTINGS, PARSE_ACTION, true },
{MENU_ENUM_LABEL_SETTINGS_VIEWS_SETTINGS, PARSE_ACTION, true },
{MENU_ENUM_LABEL_MENU_SHOW_LOAD_CORE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_LOAD_CONTENT, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_LOAD_DISC, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_DUMP_DISC, PARSE_ONLY_BOOL, true },
#if defined(HAVE_CDROM) && defined(HAVE_LAKKA)
{MENU_ENUM_LABEL_MENU_SHOW_EJECT_DISC, PARSE_ONLY_BOOL, true },
#endif
{MENU_ENUM_LABEL_CONTENT_SHOW_PLAYLISTS, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_PLAYLIST_TABS, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_HISTORY, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_FAVORITES, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_FAVORITES_FIRST, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_IMAGES, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_MUSIC, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_VIDEO, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_NETPLAY, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_ADD_ENTRY, PARSE_ONLY_UINT, true },
#if defined(HAVE_DYNAMIC)
{MENU_ENUM_LABEL_CONTENT_SHOW_CONTENTLESS_CORES, PARSE_ONLY_UINT, true },
#endif
{MENU_ENUM_LABEL_CONTENT_SHOW_EXPLORE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_SETTINGS, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CONTENT_SHOW_SETTINGS_PASSWORD, PARSE_ONLY_STRING, true},
#ifdef HAVE_ONLINE_UPDATER
{MENU_ENUM_LABEL_MENU_SHOW_ONLINE_UPDATER, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_CORE_UPDATER, PARSE_ONLY_BOOL, true },
#endif
#ifdef HAVE_MIST
{MENU_ENUM_LABEL_MENU_SHOW_CORE_MANAGER_STEAM, PARSE_ONLY_BOOL, true },
#endif
{MENU_ENUM_LABEL_MENU_SHOW_INFORMATION, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_CONFIGURATIONS, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_SHOW_WIMP, PARSE_ONLY_UINT, true },
#if !TARGET_OS_IPHONE
{MENU_ENUM_LABEL_MENU_SHOW_QUIT_RETROARCH, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_RESTART_RETROARCH, PARSE_ONLY_BOOL, true },
#endif
{MENU_ENUM_LABEL_MENU_SHOW_REBOOT, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_SHUTDOWN, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_TIMEDATE_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_TIMEDATE_STYLE, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_TIMEDATE_DATE_SEPARATOR, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_BATTERY_LEVEL_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_CORE_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_SUBLABELS, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_SHOW_CONFIRM, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_RGUI_SHOW_START_SCREEN, PARSE_ONLY_BOOL, true },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
if ( build_list[i].enum_idx == MENU_ENUM_LABEL_MENU_SHOW_SUBLABELS
&& settings->bools.menu_show_sublabels
&& ( string_is_equal(menu_driver, "ozone")
|| string_is_equal(menu_driver, "glui"))
&& MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_MENU_SHOW_SUBLABELS_CURRENT_SELECTION_ONLY,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
}
break;
case DISPLAYLIST_MEDIA_PLAYER_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_MEDIA_PLAYER_SEEK_SECONDS, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_MEDIA_PLAYER_CONTROLS_TIMEOUT, PARSE_ONLY_UINT},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
break;
case DISPLAYLIST_MENU_FILE_BROWSER_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_RGUI_BROWSER_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_CACHE_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_SHOW_HIDDEN_FILES, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_MENU_FILE_BROWSER_EXTENSION_DISPLAY, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_FILTER_BY_CURRENT_CORE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_USE_LAST_START_DIRECTORY, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_SUGGEST_ALWAYS, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_USE_BUILTIN_IMAGE_VIEWER, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_USE_BUILTIN_PLAYER, PARSE_ONLY_BOOL},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_ACCOUNTS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_ACCOUNTS_RETRO_ACHIEVEMENTS, PARSE_ACTION},
{MENU_ENUM_LABEL_ACCOUNTS_YOUTUBE, PARSE_ACTION},
{MENU_ENUM_LABEL_ACCOUNTS_TWITCH, PARSE_ACTION},
{MENU_ENUM_LABEL_ACCOUNTS_FACEBOOK, PARSE_ACTION},
{MENU_ENUM_LABEL_ACCOUNTS_KICK, PARSE_ACTION},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_ACCOUNTS_CHEEVOS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_CHEEVOS_USERNAME, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_CHEEVOS_PASSWORD, PARSE_ONLY_STRING},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
#if defined(HAVE_OVERLAY)
case DISPLAYLIST_ONSCREEN_OVERLAY_SETTINGS_LIST:
{
bool input_overlay_enable = settings->bools.input_overlay_enable;
bool input_overlay_ptr_enable = settings->bools.input_overlay_pointer_enable;
bool input_overlay_auto_scale = settings->bools.input_overlay_auto_scale;
enum overlay_show_input_type
input_overlay_show_inputs = (enum overlay_show_input_type)
settings->uints.input_overlay_show_inputs;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_INPUT_OVERLAY_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_OVERLAY_AUTOLOAD_PREFERRED, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_OVERLAY_PRESET, PARSE_ONLY_PATH, false },
{MENU_ENUM_LABEL_OVERLAY_OPACITY, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_BEHIND_MENU, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_WHEN_GAMEPAD_CONNECTED, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_INPUTS, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_INPUTS_PORT, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_MOUSE_CURSOR, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_AUTO_ROTATE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_AUTO_SCALE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_OVERLAY_SCALE_LANDSCAPE, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_ASPECT_ADJUST_LANDSCAPE, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_X_SEPARATION_LANDSCAPE, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_Y_SEPARATION_LANDSCAPE, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_X_OFFSET_LANDSCAPE, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_Y_OFFSET_LANDSCAPE, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_SCALE_PORTRAIT, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_ASPECT_ADJUST_PORTRAIT, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_X_SEPARATION_PORTRAIT, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_Y_SEPARATION_PORTRAIT, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_X_OFFSET_PORTRAIT, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_OVERLAY_Y_OFFSET_PORTRAIT, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_INPUT_OVERLAY_POINTER_ENABLE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_OVERLAY_LIGHTGUN_SETTINGS, PARSE_ACTION, false },
{MENU_ENUM_LABEL_OVERLAY_MOUSE_SETTINGS, PARSE_ACTION, false },
{MENU_ENUM_LABEL_OSK_OVERLAY_SETTINGS, PARSE_ACTION, false },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_INPUT_OVERLAY_BEHIND_MENU:
case MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_IN_MENU:
case MENU_ENUM_LABEL_INPUT_OVERLAY_HIDE_WHEN_GAMEPAD_CONNECTED:
case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_INPUTS:
case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_MOUSE_CURSOR:
case MENU_ENUM_LABEL_INPUT_OVERLAY_AUTO_ROTATE:
case MENU_ENUM_LABEL_INPUT_OVERLAY_AUTO_SCALE:
case MENU_ENUM_LABEL_OVERLAY_AUTOLOAD_PREFERRED:
case MENU_ENUM_LABEL_OVERLAY_PRESET:
case MENU_ENUM_LABEL_OVERLAY_OPACITY:
case MENU_ENUM_LABEL_INPUT_OVERLAY_POINTER_ENABLE:
build_list[i].checked = input_overlay_enable;
break;
case MENU_ENUM_LABEL_INPUT_OVERLAY_SHOW_INPUTS_PORT:
build_list[i].checked = input_overlay_enable &&
(input_overlay_show_inputs == OVERLAY_SHOW_INPUT_PHYSICAL);
break;
case MENU_ENUM_LABEL_OVERLAY_SCALE_LANDSCAPE:
case MENU_ENUM_LABEL_OVERLAY_ASPECT_ADJUST_LANDSCAPE:
case MENU_ENUM_LABEL_OVERLAY_X_SEPARATION_LANDSCAPE:
case MENU_ENUM_LABEL_OVERLAY_Y_SEPARATION_LANDSCAPE:
case MENU_ENUM_LABEL_OVERLAY_X_OFFSET_LANDSCAPE:
case MENU_ENUM_LABEL_OVERLAY_Y_OFFSET_LANDSCAPE:
case MENU_ENUM_LABEL_OVERLAY_SCALE_PORTRAIT:
case MENU_ENUM_LABEL_OVERLAY_ASPECT_ADJUST_PORTRAIT:
case MENU_ENUM_LABEL_OVERLAY_X_SEPARATION_PORTRAIT:
case MENU_ENUM_LABEL_OVERLAY_Y_SEPARATION_PORTRAIT:
case MENU_ENUM_LABEL_OVERLAY_X_OFFSET_PORTRAIT:
case MENU_ENUM_LABEL_OVERLAY_Y_OFFSET_PORTRAIT:
build_list[i].checked = input_overlay_enable &&
!input_overlay_auto_scale;
break;
case MENU_ENUM_LABEL_INPUT_OVERLAY_DPAD_DIAGONAL_SENSITIVITY:
build_list[i].checked = input_overlay_enable &&
BIT16_GET(menu_st->overlay_types, OVERLAY_TYPE_DPAD_AREA);
break;
case MENU_ENUM_LABEL_INPUT_OVERLAY_ABXY_DIAGONAL_SENSITIVITY:
build_list[i].checked = input_overlay_enable &&
BIT16_GET(menu_st->overlay_types, OVERLAY_TYPE_ABXY_AREA);
break;
case MENU_ENUM_LABEL_INPUT_OVERLAY_ANALOG_RECENTER_ZONE:
build_list[i].checked = input_overlay_enable &&
(BIT16_GET(menu_st->overlay_types, OVERLAY_TYPE_ANALOG_LEFT)
|| BIT16_GET(menu_st->overlay_types, OVERLAY_TYPE_ANALOG_RIGHT));
break;
case MENU_ENUM_LABEL_OVERLAY_LIGHTGUN_SETTINGS:
case MENU_ENUM_LABEL_OVERLAY_MOUSE_SETTINGS:
build_list[i].checked = input_overlay_enable && input_overlay_ptr_enable;
break;
case MENU_ENUM_LABEL_OSK_OVERLAY_SETTINGS:
build_list[i].checked = input_overlay_enable;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_OSK_OVERLAY_SETTINGS_LIST:
{
static const menu_displaylist_settings_row_t dl_rows_13[] = {
{ MENU_ENUM_LABEL_OSK_OVERLAY_PRESET, PARSE_ONLY_PATH, false },
{ MENU_ENUM_LABEL_INPUT_OSK_OVERLAY_AUTO_SCALE, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_OSK_OVERLAY_OPACITY, PARSE_ONLY_FLOAT, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_13, (unsigned)ARRAY_SIZE(dl_rows_13));
}
break;
case DISPLAYLIST_OVERLAY_LIGHTGUN_SETTINGS_LIST:
{
static const menu_displaylist_settings_row_t dl_rows_14[] = {
{ MENU_ENUM_LABEL_INPUT_OVERLAY_LIGHTGUN_PORT, PARSE_ONLY_INT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_LIGHTGUN_TRIGGER_ON_TOUCH, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_LIGHTGUN_TRIGGER_DELAY, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_LIGHTGUN_TWO_TOUCH_INPUT, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_LIGHTGUN_THREE_TOUCH_INPUT, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_LIGHTGUN_FOUR_TOUCH_INPUT, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_LIGHTGUN_ALLOW_OFFSCREEN, PARSE_ONLY_BOOL, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_14, (unsigned)ARRAY_SIZE(dl_rows_14));
}
break;
case DISPLAYLIST_OVERLAY_MOUSE_SETTINGS_LIST:
{
static const menu_displaylist_settings_row_t dl_rows_15[] = {
{ MENU_ENUM_LABEL_INPUT_OVERLAY_MOUSE_SPEED, PARSE_ONLY_FLOAT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_MOUSE_HOLD_TO_DRAG, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_MOUSE_HOLD_MSEC, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_MOUSE_DTAP_TO_DRAG, PARSE_ONLY_BOOL, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_MOUSE_DTAP_MSEC, PARSE_ONLY_UINT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_MOUSE_SWIPE_THRESHOLD, PARSE_ONLY_FLOAT, false },
{ MENU_ENUM_LABEL_INPUT_OVERLAY_MOUSE_ALT_TWO_TOUCH_INPUT, PARSE_ONLY_UINT, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_15, (unsigned)ARRAY_SIZE(dl_rows_15));
}
break;
#endif
case DISPLAYLIST_LATENCY_SETTINGS_LIST:
{
bool video_vsync = settings->bools.video_vsync;
bool video_hard_sync = settings->bools.video_hard_sync;
bool video_wait_swap = settings->bools.video_waitable_swapchains;
#ifdef HAVE_RUNAHEAD
bool runahead_supported = true;
bool runahead_enabled = settings->bools.run_ahead_enabled;
bool preempt_enabled = settings->bools.preemptive_frames_enable;
#endif
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_VIDEO_FRAME_DELAY_AUTO, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_VIDEO_FRAME_DELAY, PARSE_ONLY_UINT, true },
#ifdef HAVE_RUNAHEAD
{MENU_ENUM_LABEL_RUNAHEAD_MODE, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_RUN_AHEAD_FRAMES, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_PREEMPT_FRAMES, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS, PARSE_ONLY_BOOL, false },
#endif
{MENU_ENUM_LABEL_AUDIO_LATENCY, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_AUDIO_LATENCY_FLOOR, PARSE_ONLY_UINT, true },
#ifdef HAVE_MICROPHONE
{MENU_ENUM_LABEL_MICROPHONE_LATENCY, PARSE_ONLY_UINT, true },
#endif
};
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_VSYNC,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (video_vsync)
{
if (video_driver_test_all_flags(GFX_CTX_FLAGS_ADAPTIVE_VSYNC))
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_ADAPTIVE_VSYNC,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
if (video_driver_test_all_flags(GFX_CTX_FLAGS_HARD_SYNC))
{
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HARD_SYNC,
PARSE_ONLY_BOOL, false);
count++;
if (video_hard_sync)
{
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_HARD_SYNC_FRAMES,
PARSE_ONLY_UINT, false);
count++;
}
}
if (video_driver_test_all_flags(GFX_CTX_FLAGS_CUSTOMIZABLE_FRAME_LATENCY))
{
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_WAITABLE_SWAPCHAINS,
PARSE_ONLY_BOOL, false);
count++;
if (video_wait_swap)
{
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_MAX_FRAME_LATENCY,
PARSE_ONLY_INT, false);
count++;
}
}
}
if (video_driver_test_all_flags(GFX_CTX_FLAGS_CUSTOMIZABLE_SWAPCHAIN_IMAGES))
{
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_MAX_SWAPCHAIN_IMAGES,
PARSE_ONLY_UINT, false);
count++;
}
#if defined(HAVE_D3DKMT) || defined(HAVE_KMS)
if ( video_display_server_has_scanline()
|| settings->bools.video_scanline_sync)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SCANLINE_SYNC,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_VIDEO_SCANLINE_SYNC_OFFSET,
PARSE_ONLY_UINT, false) == 0)
count++;
}
#endif
#ifdef HAVE_RUNAHEAD
if ( (flags & RUNLOOP_FLAG_CORE_RUNNING)
&& !retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
runahead_supported = core_info_current_supports_runahead();
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_RUNAHEAD_MODE:
build_list[i].checked = runahead_supported;
break;
case MENU_ENUM_LABEL_RUN_AHEAD_FRAMES:
build_list[i].checked = runahead_supported && runahead_enabled;
break;
case MENU_ENUM_LABEL_PREEMPT_FRAMES:
build_list[i].checked = runahead_supported && preempt_enabled;
break;
case MENU_ENUM_LABEL_RUN_AHEAD_HIDE_WARNINGS:
build_list[i].checked = runahead_supported && (runahead_enabled || preempt_enabled);
break;
default:
break;
}
}
#endif
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
#ifdef HAVE_RUNAHEAD
if (!runahead_supported)
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN_AHEAD_UNSUPPORTED),
MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED_STR,
MENU_ENUM_LABEL_RUN_AHEAD_UNSUPPORTED,
FILE_TYPE_NONE, 0, 0, NULL))
count++;
#endif
#ifndef HAVE_LAKKA
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_GAMEMODE_ENABLE, PARSE_ONLY_BOOL, false) == 0)
count++;
#endif /*HAVE_LAKKA?*/
}
break;
case DISPLAYLIST_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST:
{
bool video_font_enable = settings->bools.video_font_enable;
bool video_msg_bgcolor_enable = settings->bools.video_msg_bgcolor_enable;
#ifdef HAVE_GFX_WIDGETS
video_driver_state_t *video_st= video_state_get_ptr();
bool widgets_supported = video_st->current_video
&& video_st->current_video->gfx_widgets_enabled
&& video_st->current_video->gfx_widgets_enabled(video_st->data);
bool widgets_active = gfx_widgets_ready();
bool menu_widget_scale_auto = settings->bools.menu_widget_scale_auto;
#else
bool widgets_active = false;
#endif
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS, PARSE_ACTION, false },
{MENU_ENUM_LABEL_VIDEO_FONT_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_WIDGETS_ENABLE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_MENU_WIDGET_SCALE_AUTO, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_MENU_WIDGET_SCALE_FACTOR, PARSE_ONLY_FLOAT, false },
#if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE))
{MENU_ENUM_LABEL_MENU_WIDGET_SCALE_FACTOR_WINDOWED, PARSE_ONLY_FLOAT, false },
#endif
{MENU_ENUM_LABEL_VIDEO_FONT_PATH, PARSE_ONLY_PATH, false },
{MENU_ENUM_LABEL_VIDEO_FONT_SIZE, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_X, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_Y, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_COLOR_RED, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_COLOR_GREEN, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_COLOR_BLUE, PARSE_ONLY_FLOAT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_ENABLE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_RED, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_GREEN, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_BLUE, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_OPACITY, PARSE_ONLY_FLOAT, false },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
#ifdef HAVE_GFX_WIDGETS
case MENU_ENUM_LABEL_MENU_WIDGETS_ENABLE:
build_list[i].checked = video_font_enable && widgets_supported;
break;
case MENU_ENUM_LABEL_MENU_WIDGET_SCALE_AUTO:
build_list[i].checked = widgets_active;
break;
case MENU_ENUM_LABEL_MENU_WIDGET_SCALE_FACTOR:
build_list[i].checked = widgets_active && !menu_widget_scale_auto;
break;
#if !(defined(RARCH_CONSOLE) || defined(RARCH_MOBILE))
case MENU_ENUM_LABEL_MENU_WIDGET_SCALE_FACTOR_WINDOWED:
build_list[i].checked = widgets_active && !menu_widget_scale_auto;
break;
#endif
#endif
case MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS:
case MENU_ENUM_LABEL_VIDEO_FONT_PATH:
case MENU_ENUM_LABEL_VIDEO_FONT_SIZE:
build_list[i].checked = video_font_enable || widgets_active;
break;
case MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_X:
case MENU_ENUM_LABEL_VIDEO_MESSAGE_POS_Y:
case MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_ENABLE:
build_list[i].checked = !widgets_active && video_font_enable;
break;
case MENU_ENUM_LABEL_VIDEO_MESSAGE_COLOR_RED:
case MENU_ENUM_LABEL_VIDEO_MESSAGE_COLOR_GREEN:
case MENU_ENUM_LABEL_VIDEO_MESSAGE_COLOR_BLUE:
build_list[i].checked = video_font_enable;
break;
case MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_RED:
case MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_GREEN:
case MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_BLUE:
case MENU_ENUM_LABEL_VIDEO_MESSAGE_BGCOLOR_OPACITY:
build_list[i].checked = !widgets_active &&
video_font_enable &&
video_msg_bgcolor_enable;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS_LIST:
{
bool video_font_enable = settings->bools.video_font_enable;
bool video_fps_show = settings->bools.video_fps_show;
bool video_memory_show = settings->bools.video_memory_show;
#ifdef HAVE_GFX_WIDGETS
bool widgets_active = gfx_widgets_ready();
bool notifications_active = video_font_enable || widgets_active;
#ifdef HAVE_SCREENSHOTS
bool notification_show_screenshot = settings->bools.notification_show_screenshot;
#endif
#else
bool notifications_active = video_font_enable;
#endif
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_FPS_SHOW, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_FPS_UPDATE_INTERVAL, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_FRAMECOUNT_SHOW, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_MEMORY_SHOW, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_MEMORY_UPDATE_INTERVAL, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_TIME_SHOW, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_STATISTICS_SHOW, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_STATISTICS_HIDE_IN_MENU, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_MENU_SHOW_LOAD_CONTENT_ANIMATION, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_WHEN_MENU_IS_ALIVE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_AUTOCONFIG, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_AUTOCONFIG_FAILS, PARSE_ONLY_BOOL, false },
#ifdef HAVE_CHEATS
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_CHEATS_APPLIED, PARSE_ONLY_BOOL, false },
#endif
#ifdef HAVE_PATCH
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_PATCH_APPLIED, PARSE_ONLY_BOOL, false },
#endif
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_REMAP_LOAD, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_CONFIG_OVERRIDE_LOAD, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_SET_INITIAL_DISK, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_DISK_CONTROL, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_SAVE_STATE, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_FAST_FORWARD, PARSE_ONLY_BOOL, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_REFRESH_RATE, PARSE_ONLY_BOOL, false },
#ifdef HAVE_SCREENSHOTS
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_SCREENSHOT, PARSE_ONLY_BOOL, false },
#ifdef HAVE_GFX_WIDGETS
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_SCREENSHOT_DURATION, PARSE_ONLY_UINT, false },
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_SCREENSHOT_FLASH, PARSE_ONLY_UINT, false },
#endif
#endif
#if defined(HAVE_NETWORKING) && defined(HAVE_GFX_WIDGETS)
{MENU_ENUM_LABEL_NETPLAY_PING_SHOW, PARSE_ONLY_BOOL, false },
#endif
#ifdef HAVE_NETWORKING
{MENU_ENUM_LABEL_NOTIFICATION_SHOW_NETPLAY_EXTRA, PARSE_ONLY_BOOL, false },
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_FPS_UPDATE_INTERVAL:
build_list[i].checked = notifications_active && video_fps_show;
break;
case MENU_ENUM_LABEL_MEMORY_UPDATE_INTERVAL:
build_list[i].checked = notifications_active && video_memory_show;
break;
case MENU_ENUM_LABEL_STATISTICS_SHOW:
build_list[i].checked = notifications_active && video_font_enable;
break;
case MENU_ENUM_LABEL_STATISTICS_HIDE_IN_MENU:
build_list[i].checked = notifications_active && video_font_enable
&& settings->bools.video_statistics_show;
break;
#ifdef HAVE_GFX_WIDGETS
#ifdef HAVE_NETWORKING
case MENU_ENUM_LABEL_NETPLAY_PING_SHOW:
build_list[i].checked = widgets_active;
break;
#endif
case MENU_ENUM_LABEL_MENU_SHOW_LOAD_CONTENT_ANIMATION:
build_list[i].checked = widgets_active;
break;
#ifdef HAVE_SCREENSHOTS
case MENU_ENUM_LABEL_NOTIFICATION_SHOW_SCREENSHOT_DURATION:
build_list[i].checked = widgets_active && notification_show_screenshot;
break;
case MENU_ENUM_LABEL_NOTIFICATION_SHOW_SCREENSHOT_FLASH:
build_list[i].checked = widgets_active;
break;
#endif
#endif
default:
build_list[i].checked = notifications_active;
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_CONFIGURATIONS_LIST:
{
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CONFIGURATIONS),
MENU_ENUM_LABEL_CONFIGURATIONS_STR,
MENU_ENUM_LABEL_CONFIGURATIONS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_CURRENT_CONFIG),
MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG_STR,
MENU_ENUM_LABEL_SAVE_CURRENT_CONFIG,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG),
MENU_ENUM_LABEL_SAVE_NEW_CONFIG_STR,
MENU_ENUM_LABEL_SAVE_NEW_CONFIG,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_MAIN_CONFIG),
MENU_ENUM_LABEL_SAVE_MAIN_CONFIG_STR,
MENU_ENUM_LABEL_SAVE_MAIN_CONFIG,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_AS_CONFIG),
MENU_ENUM_LABEL_SAVE_AS_CONFIG_STR,
MENU_ENUM_LABEL_SAVE_AS_CONFIG,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RESET_TO_DEFAULT_CONFIG),
MENU_ENUM_LABEL_RESET_TO_DEFAULT_CONFIG_STR,
MENU_ENUM_LABEL_RESET_TO_DEFAULT_CONFIG,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (!settings->bools.global_core_options && (sys_info->info.library_name && *sys_info->info.library_name)
&& menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_OPTIONS_RESET),
"",
MENU_ENUM_LABEL_CORE_OPTIONS_RESET,
MENU_SETTING_ACTION_CORE_OPTIONS_RESET, 0, 0, NULL))
count++;
break;
}
case DISPLAYLIST_PRIVACY_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_CAMERA_ALLOW, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_DISCORD_ALLOW, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_LOCATION_ALLOW, PARSE_ONLY_BOOL},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_SAVING_SETTINGS_LIST:
{
bool savestate_auto_index = settings->bools.savestate_auto_index;
bool replay_auto_index = settings->bools.replay_auto_index;
static menu_displaylist_build_info_selective_t build_list[] = {
#if HAVE_CLOUDSYNC
{MENU_ENUM_LABEL_CLOUD_SYNC_SETTINGS, PARSE_ACTION, true},
#endif
{MENU_ENUM_LABEL_SORT_SAVEFILES_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SORT_SAVEFILES_BY_CONTENT_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SAVEFILES_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL, true},
#if defined(HAVE_COMPRESSION)
{MENU_ENUM_LABEL_SAVE_FILE_COMPRESSION, PARSE_ONLY_BOOL, true},
#endif
{MENU_ENUM_LABEL_AUTOSAVE_INTERVAL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_BLOCK_SRAM_OVERWRITE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SORT_SAVESTATES_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SORT_SAVESTATES_BY_CONTENT_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SAVESTATES_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SAVESTATE_AUTO_SAVE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SAVESTATE_AUTO_LOAD, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SAVESTATE_THUMBNAIL_ENABLE, PARSE_ONLY_BOOL, true},
#if defined(HAVE_COMPRESSION)
{MENU_ENUM_LABEL_SAVESTATE_FILE_COMPRESSION, PARSE_ONLY_BOOL, true},
#endif
{MENU_ENUM_LABEL_SAVESTATE_AUTOMATIC_INTERVAL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_SAVESTATE_AUTO_INDEX, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SAVESTATE_MAX_KEEP, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_REPLAY_AUTO_INDEX, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_REPLAY_MAX_KEEP, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_REPLAY_CHECKPOINT_INTERVAL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_REPLAY_CHECKPOINT_DESERIALIZE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SORT_SCREENSHOTS_BY_CONTENT_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SCREENSHOTS_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_VIDEO_GPU_SCREENSHOT, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CONTENT_RUNTIME_LOG_AGGREGATE, PARSE_ONLY_BOOL, true},
#if defined(HAVE_COMPRESSION) && defined(HAVE_RZSTD)
{MENU_ENUM_LABEL_SAVE_COMPRESSION_CODEC, PARSE_ONLY_UINT, true},
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_SAVESTATE_MAX_KEEP:
build_list[i].checked = savestate_auto_index;
break;
case MENU_ENUM_LABEL_REPLAY_MAX_KEEP:
build_list[i].checked = replay_auto_index;
break;
case MENU_ENUM_LABEL_VIDEO_GPU_SCREENSHOT:
{
#ifdef HAVE_SCREENSHOTS
video_driver_state_t *video_st = video_state_get_ptr();
build_list[i].checked =
video_st->current_video->read_viewport
&& video_st->current_video->viewport_info;
#endif
break;
}
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (build_list[i].checked &&
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_CLOUD_SYNC_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_CLOUD_SYNC_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CLOUD_SYNC_SYNC_MODE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_CLOUD_SYNC_DESTRUCTIVE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CLOUD_SYNC_SYNC_SAVES, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CLOUD_SYNC_SYNC_CONFIGS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CLOUD_SYNC_SYNC_THUMBS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CLOUD_SYNC_SYNC_SYSTEM, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_CLOUD_SYNC_DRIVER, PARSE_ONLY_STRING_OPTIONS, true},
{MENU_ENUM_LABEL_CLOUD_SYNC_URL, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_CLOUD_SYNC_USERNAME, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_CLOUD_SYNC_PASSWORD, PARSE_ONLY_STRING, false},
#ifdef HAVE_S3
{MENU_ENUM_LABEL_CLOUD_SYNC_S3_URL, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_CLOUD_SYNC_ACCESS_KEY_ID, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_CLOUD_SYNC_SECRET_ACCESS_KEY, PARSE_ONLY_STRING, false},
#endif
/* The SMB and NFS drivers use the network share settings:
* the entry that opens them, under the driver using them. */
#ifdef HAVE_SMBCLIENT
{MENU_ENUM_LABEL_SMB_CLIENT_SETTINGS, PARSE_ACTION, false},
#endif
#ifdef HAVE_NFSCLIENT
{MENU_ENUM_LABEL_NFS_CLIENT_SETTINGS, PARSE_ACTION, false},
{MENU_ENUM_LABEL_CLOUD_SYNC_NFS_SUBDIR, PARSE_ONLY_STRING, false},
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
switch(build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_CLOUD_SYNC_USERNAME:
case MENU_ENUM_LABEL_CLOUD_SYNC_URL:
case MENU_ENUM_LABEL_CLOUD_SYNC_PASSWORD:
build_list[i].checked =
string_is_equal(settings->arrays.cloud_sync_driver, "webdav");
break;
case MENU_ENUM_LABEL_CLOUD_SYNC_S3_URL:
case MENU_ENUM_LABEL_CLOUD_SYNC_ACCESS_KEY_ID:
case MENU_ENUM_LABEL_CLOUD_SYNC_SECRET_ACCESS_KEY:
build_list[i].checked =
string_is_equal(settings->arrays.cloud_sync_driver, "s3");
break;
#ifdef HAVE_SMBCLIENT
case MENU_ENUM_LABEL_SMB_CLIENT_SETTINGS:
build_list[i].checked =
string_is_equal(settings->arrays.cloud_sync_driver, "smb");
break;
#endif
#ifdef HAVE_NFSCLIENT
case MENU_ENUM_LABEL_NFS_CLIENT_SETTINGS:
case MENU_ENUM_LABEL_CLOUD_SYNC_NFS_SUBDIR:
build_list[i].checked =
string_is_equal(settings->arrays.cloud_sync_driver, "nfs");
break;
#endif
default:
break;
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (build_list[i].checked &&
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
/* Add action items when cloud sync is enabled */
if (settings->bools.cloud_sync_enable)
{
{
static const menu_displaylist_settings_row_t dl_rows_16[] = {
{ MENU_ENUM_LABEL_CLOUD_SYNC_SYNC_NOW, PARSE_ACTION, false },
{ MENU_ENUM_LABEL_CLOUD_SYNC_RESOLVE_KEEP_LOCAL, PARSE_ACTION, false },
{ MENU_ENUM_LABEL_CLOUD_SYNC_RESOLVE_KEEP_SERVER, PARSE_ACTION, false },
};
count += menu_displaylist_parse_settings_rows(list, settings,
dl_rows_16, (unsigned)ARRAY_SIZE(dl_rows_16));
}
}
}
break;
#ifdef HAVE_MIST
case DISPLAYLIST_STEAM_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_STEAM_RICH_PRESENCE_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_STEAM_RICH_PRESENCE_FORMAT, PARSE_ONLY_UINT, false},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_STEAM_RICH_PRESENCE_FORMAT:
build_list[i].checked = settings->bools.steam_rich_presence_enable;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
#endif
case DISPLAYLIST_SETTINGS_ALL:
{
#ifdef HAVE_TRANSLATE
bool settings_show_ai_service = settings->bools.settings_show_ai_service;
#endif
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_VIDEO_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_AUDIO_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_INPUT_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_LATENCY_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_DRIVER_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_PLAYLIST_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_CORE_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_SAVING_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_RECORDING_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_CONFIGURATION_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_ACCESSIBILITY_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_BLUETOOTH_SETTINGS, PARSE_ACTION, true},
#ifdef HAVE_NETWORKING
{MENU_ENUM_LABEL_WIFI_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_NETWORK_SETTINGS, PARSE_ACTION, true},
#endif
#ifdef HAVE_CHEEVOS
{MENU_ENUM_LABEL_RETRO_ACHIEVEMENTS_SETTINGS, PARSE_ACTION},
#endif
{MENU_ENUM_LABEL_USER_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_DIRECTORY_SETTINGS, PARSE_ACTION, true},
{MENU_ENUM_LABEL_LAKKA_SERVICES, PARSE_ACTION, true},
#ifdef HAVE_LAKKA_SWITCH
{MENU_ENUM_LABEL_LAKKA_SWITCH_OPTIONS, PARSE_ACTION, true},
#endif
#ifdef HAVE_MIST
{MENU_ENUM_LABEL_STEAM_SETTINGS, PARSE_ACTION, true},
#endif
{MENU_ENUM_LABEL_LOGGING_SETTINGS, PARSE_ACTION, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_AI_SERVICE_SETTINGS:
#ifdef HAVE_TRANSLATE
build_list[i].checked = settings_show_ai_service;
#else
build_list[i].checked = false;
#endif
break;
case MENU_ENUM_LABEL_DRIVER_SETTINGS:
build_list[i].checked = settings->bools.settings_show_drivers;
break;
case MENU_ENUM_LABEL_VIDEO_SETTINGS:
build_list[i].checked = settings->bools.settings_show_video;
break;
case MENU_ENUM_LABEL_AUDIO_SETTINGS:
build_list[i].checked = settings->bools.settings_show_audio;
break;
case MENU_ENUM_LABEL_INPUT_SETTINGS:
build_list[i].checked = settings->bools.settings_show_input;
break;
case MENU_ENUM_LABEL_LATENCY_SETTINGS:
build_list[i].checked = settings->bools.settings_show_latency;
break;
case MENU_ENUM_LABEL_CORE_SETTINGS:
build_list[i].checked = settings->bools.settings_show_core;
break;
case MENU_ENUM_LABEL_CONFIGURATION_SETTINGS:
build_list[i].checked = settings->bools.settings_show_configuration;
break;
case MENU_ENUM_LABEL_SAVING_SETTINGS:
build_list[i].checked = settings->bools.settings_show_saving;
break;
case MENU_ENUM_LABEL_LOGGING_SETTINGS:
build_list[i].checked = settings->bools.settings_show_logging;
break;
case MENU_ENUM_LABEL_FRAME_THROTTLE_SETTINGS:
build_list[i].checked = settings->bools.settings_show_frame_throttle;
break;
case MENU_ENUM_LABEL_RECORDING_SETTINGS:
build_list[i].checked = settings->bools.settings_show_recording;
break;
case MENU_ENUM_LABEL_USER_INTERFACE_SETTINGS:
build_list[i].checked = settings->bools.settings_show_user_interface;
break;
case MENU_ENUM_LABEL_ACCESSIBILITY_SETTINGS:
build_list[i].checked = settings->bools.settings_show_accessibility;
break;
case MENU_ENUM_LABEL_POWER_MANAGEMENT_SETTINGS:
build_list[i].checked = settings->bools.settings_show_power_management;
break;
case MENU_ENUM_LABEL_RETRO_ACHIEVEMENTS_SETTINGS:
build_list[i].checked = settings->bools.settings_show_achievements;
break;
case MENU_ENUM_LABEL_NETWORK_SETTINGS:
build_list[i].checked = settings->bools.settings_show_network;
break;
case MENU_ENUM_LABEL_PLAYLIST_SETTINGS:
build_list[i].checked = settings->bools.settings_show_playlists;
break;
case MENU_ENUM_LABEL_USER_SETTINGS:
build_list[i].checked = settings->bools.settings_show_user;
break;
case MENU_ENUM_LABEL_DIRECTORY_SETTINGS:
build_list[i].checked = settings->bools.settings_show_directory;
break;
#ifdef HAVE_MIST
case MENU_ENUM_LABEL_STEAM_SETTINGS:
build_list[i].checked = settings->bools.settings_show_steam;
break;
#endif
/* MISSING:
* MENU_ENUM_LABEL_BLUETOOTH_SETTINGS
* MENU_ENUM_LABEL_WIFI_SETTINGS
* MENU_ENUM_LABEL_LAKKA_SERVICES
*/
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (build_list[i].checked &&
MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_POWER_MANAGEMENT_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_FASTFORWARD_FRAMESKIP, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SUSTAINED_PERFORMANCE_MODE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CPU_PERFPOWER, PARSE_ACTION},
#ifdef HAVE_LAKKA
{MENU_ENUM_LABEL_GAMEMODE_ENABLE, PARSE_ONLY_BOOL},
#endif /*HAVE_LAKKA*/
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
{MENU_ENUM_LABEL_WIN32_POWER_PLAN, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_WIN32_POWER_PLAN_IDLE_DISABLE, PARSE_ONLY_BOOL},
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
#ifdef _3DS
u8 device_model = 0xFF;
CFGU_GetSystemModel(&device_model);
if ( (device_model == 2)
|| (device_model == 4)
|| (device_model == 5))
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_NEW3DS_SPEEDUP_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
#endif
}
break;
case DISPLAYLIST_ONSCREEN_DISPLAY_SETTINGS_LIST:
{
/* Not used */
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_ONSCREEN_NOTIFICATIONS_SETTINGS, PARSE_ACTION},
#if defined(HAVE_OVERLAY)
{MENU_ENUM_LABEL_ONSCREEN_OVERLAY_SETTINGS, PARSE_ACTION},
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_USER_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_PRIVACY_SETTINGS, PARSE_ACTION},
{MENU_ENUM_LABEL_ACCOUNTS_LIST, PARSE_ACTION},
#if defined(HAVE_KEYCHAIN) && defined(HAVE_CRYPTO) && defined(HAVE_CONFIGFILE)
{MENU_ENUM_LABEL_KEYCHAIN_PASSPHRASE, PARSE_ACTION},
#endif
{MENU_ENUM_LABEL_NETPLAY_NICKNAME, PARSE_ONLY_STRING},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_UPDATER_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_CORE_UPDATER_BUILDBOT_URL, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_UPDATER_SHOW_EXPERIMENTAL_CORES, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP_HISTORY_SIZE, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_CORE_UPDATER_AUTO_BACKUP_COMPRESS, PARSE_ONLY_BOOL},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_MENU_SOUNDS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_AUDIO_ENABLE_MENU, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_MENU_SOUND_OK, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_MENU_SOUND_CANCEL, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_MENU_SOUND_NOTICE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_MENU_SOUND_BGM, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_MENU_SOUND_SCROLL, PARSE_ONLY_BOOL},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_SETTINGS_VIEWS_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_SETTINGS_SHOW_USER_INTERFACE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_ONSCREEN_DISPLAY, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_FILE_BROWSER, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_VIDEO, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_AUDIO, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_INPUT, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_LATENCY, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_FRAME_THROTTLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_DRIVERS, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_PLAYLISTS, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_CORE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_SAVING, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_RECORDING, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_CONFIGURATION, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_ACCESSIBILITY, PARSE_ONLY_BOOL},
#ifdef HAVE_TRANSLATE
{MENU_ENUM_LABEL_SETTINGS_SHOW_AI_SERVICE, PARSE_ONLY_BOOL},
#endif
{MENU_ENUM_LABEL_SETTINGS_SHOW_POWER_MANAGEMENT, PARSE_ONLY_BOOL},
#ifdef HAVE_NETWORKING
{MENU_ENUM_LABEL_SETTINGS_SHOW_NETWORK, PARSE_ONLY_BOOL},
#endif
#ifdef HAVE_CHEEVOS
{MENU_ENUM_LABEL_SETTINGS_SHOW_ACHIEVEMENTS, PARSE_ONLY_BOOL},
#endif
{MENU_ENUM_LABEL_SETTINGS_SHOW_USER, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SETTINGS_SHOW_DIRECTORY, PARSE_ONLY_BOOL},
#ifdef HAVE_MIST
{MENU_ENUM_LABEL_SETTINGS_SHOW_STEAM, PARSE_ONLY_BOOL},
#endif
{MENU_ENUM_LABEL_SETTINGS_SHOW_LOGGING, PARSE_ONLY_BOOL},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_QUICK_MENU_VIEWS_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_RESUME_CONTENT, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_RESTART_CONTENT, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_CLOSE_CONTENT, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVESTATE_SUBMENU, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_LOAD_STATE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_UNDO_SAVE_LOAD_STATE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_REPLAY, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_OPTIONS, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_CORE_OPTIONS_FLUSH, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_CONTROLS, PARSE_ONLY_BOOL},
#ifdef HAVE_SCREENSHOTS
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_TAKE_SCREENSHOT, PARSE_ONLY_BOOL},
#endif
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_START_RECORDING, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_START_STREAMING, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_ADD_TO_FAVORITES, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_ADD_TO_PLAYLIST, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CONTENT_SHOW_OVERLAYS, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CONTENT_SHOW_LATENCY, PARSE_ONLY_BOOL},
#ifdef HAVE_REWIND
{MENU_ENUM_LABEL_CONTENT_SHOW_REWIND, PARSE_ONLY_BOOL},
#endif
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_CORE_OVERRIDES, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_CONTENT_DIR_OVERRIDES, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_SAVE_GAME_OVERRIDES, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_CHEATS, PARSE_ONLY_BOOL},
#ifdef HAVE_GAME_AI
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_GAME_AI, PARSE_ONLY_BOOL},
#endif
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
gfx_ctx_flags_t flags;
flags.flags = 0;
video_context_driver_get_flags(&flags);
if (
BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG)
|| BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL)
|| BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG)
|| BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_HLSL))
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
MENU_ENUM_LABEL_QUICK_MENU_SHOW_SHADERS,
PARSE_ONLY_BOOL, false) == 0)
count++;
}
}
#endif
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_SET_CORE_ASSOCIATION, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_RESET_CORE_ASSOCIATION, PARSE_ONLY_BOOL},
#ifdef HAVE_NETWORKING
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_DOWNLOAD_THUMBNAILS, PARSE_ONLY_BOOL},
#endif
{MENU_ENUM_LABEL_QUICK_MENU_SHOW_INFORMATION, PARSE_ONLY_BOOL},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_CORE_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
#ifdef HAVE_ONLINE_UPDATER
{MENU_ENUM_LABEL_UPDATER_SETTINGS, PARSE_ACTION},
#endif
{MENU_ENUM_LABEL_CORE_INFO_CACHE_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_INFO_SAVESTATE_BYPASS, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_SYSTEMFILES_IN_CONTENT_DIR_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CORE_OPTION_CATEGORY_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_DRIVER_SWITCH_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_VIDEO_ALLOW_ROTATE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_VIDEO_SHARED_CONTEXT, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_DUMMY_ON_CORE_SHUTDOWN, PARSE_ONLY_BOOL},
#ifndef HAVE_DYNAMIC
{MENU_ENUM_LABEL_ALWAYS_RELOAD_CORE_ON_RUN_CONTENT, PARSE_ONLY_BOOL},
#endif
};
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_MANAGER_LIST),
MENU_ENUM_LABEL_CORE_MANAGER_LIST_STR,
MENU_ENUM_LABEL_CORE_MANAGER_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
/* core_manager_list has no backing setting, so it cannot
* be a PARSE_ACTION array entry; the raw append above is
* the only mechanism for settingless action rows today. */
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_CONFIGURATION_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_CONFIG_SAVE_ON_EXIT, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_REMAP_SAVE_ON_EXIT, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_GAME_SPECIFIC_OPTIONS, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_AUTO_OVERRIDES_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_AUTO_REMAPS_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_INITIAL_DISK_CHANGE_ENABLE, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_CONFIG_SAVE_MINIMAL, PARSE_ONLY_BOOL},
{MENU_ENUM_LABEL_GLOBAL_CORE_OPTIONS, PARSE_ONLY_BOOL},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_DIRECTORY_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_RGUI_BROWSER_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_CACHE_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_SYSTEM_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_SAVEFILE_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_SAVESTATE_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_LIBRETRO_DIR_PATH, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_LIBRETRO_INFO_PATH, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_RGUI_CONFIG_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_CORE_ASSETS_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_ASSETS_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_THUMBNAILS_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_DYNAMIC_WALLPAPERS_DIRECTORY, PARSE_ONLY_DIR},
#ifdef HAVE_CHEATS
{MENU_ENUM_LABEL_CHEAT_DATABASE_PATH, PARSE_ONLY_DIR},
#endif
{MENU_ENUM_LABEL_CONTENT_DATABASE_DIRECTORY, PARSE_ONLY_DIR},
#ifdef HAVE_VIDEO_FILTER
{MENU_ENUM_LABEL_VIDEO_FILTER_DIR, PARSE_ONLY_DIR},
#endif
#ifdef HAVE_DSP_FILTER
{MENU_ENUM_LABEL_AUDIO_FILTER_DIR, PARSE_ONLY_DIR},
#endif
{MENU_ENUM_LABEL_VIDEO_SHADER_DIR, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_RECORDING_OUTPUT_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_RECORDING_CONFIG_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_OVERLAY_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_OSK_OVERLAY_DIRECTORY, PARSE_ONLY_DIR},
#ifdef HAVE_SCREENSHOTS
{MENU_ENUM_LABEL_SCREENSHOT_DIRECTORY, PARSE_ONLY_DIR},
#endif
{MENU_ENUM_LABEL_JOYPAD_AUTOCONFIG_DIR, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_INPUT_REMAPPING_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_PLAYLIST_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_CONTENT_FAVORITES_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_CONTENT_HISTORY_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_CONTENT_IMAGE_HISTORY_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_CONTENT_MUSIC_HISTORY_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_CONTENT_VIDEO_HISTORY_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_RUNTIME_LOG_DIRECTORY, PARSE_ONLY_DIR},
{MENU_ENUM_LABEL_LOG_DIR, PARSE_ONLY_DIR},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_DRIVER_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_MENU_DRIVER, PARSE_ONLY_STRING_OPTIONS},
{MENU_ENUM_LABEL_VIDEO_DRIVER, PARSE_ONLY_STRING_OPTIONS},
{MENU_ENUM_LABEL_AUDIO_DRIVER, PARSE_ONLY_STRING_OPTIONS},
#ifdef HAVE_MICROPHONE
{MENU_ENUM_LABEL_MICROPHONE_DRIVER, PARSE_ONLY_STRING_OPTIONS},
#endif
{MENU_ENUM_LABEL_INPUT_DRIVER, PARSE_ONLY_STRING_OPTIONS},
{MENU_ENUM_LABEL_JOYPAD_DRIVER, PARSE_ONLY_STRING_OPTIONS},
{MENU_ENUM_LABEL_RECORD_DRIVER, PARSE_ONLY_STRING_OPTIONS},
{MENU_ENUM_LABEL_MIDI_DRIVER, PARSE_ONLY_STRING_OPTIONS},
#ifdef HAVE_COMPANION_WIMP
{MENU_ENUM_LABEL_UI_COMPANION_DRIVER, PARSE_ONLY_STRING_OPTIONS},
#endif
#ifdef HAVE_BLUETOOTH
{MENU_ENUM_LABEL_BLUETOOTH_DRIVER, PARSE_ONLY_STRING_OPTIONS},
#endif
#if defined(HAVE_LAKKA) || defined(HAVE_WIFI)
{MENU_ENUM_LABEL_WIFI_DRIVER, PARSE_ONLY_STRING_OPTIONS},
#endif
{MENU_ENUM_LABEL_CAMERA_DRIVER, PARSE_ONLY_STRING_OPTIONS},
{MENU_ENUM_LABEL_LOCATION_DRIVER, PARSE_ONLY_STRING_OPTIONS},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_LOGGING_SETTINGS_LIST:
{
bool log_to_file = settings->bools.log_to_file;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_LOG_VERBOSITY, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_FRONTEND_LOG_LEVEL, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_LIBRETRO_LOG_LEVEL, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_LOG_TO_FILE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_LOG_TO_FILE_TIMESTAMP, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_PERFCNT_ENABLE, PARSE_ONLY_BOOL, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_FRONTEND_LOG_LEVEL:
case MENU_ENUM_LABEL_LIBRETRO_LOG_LEVEL:
build_list[i].checked = verbosity_is_enabled();
break;
case MENU_ENUM_LABEL_LOG_TO_FILE_TIMESTAMP:
build_list[i].checked = log_to_file;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_FRAME_TIME_COUNTER_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_VIDEO_REFRESH_RATE_AUTO, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_VIDEO_FRAME_TIME_SAMPLE_GATED, PARSE_ONLY_BOOL, true},
/* Auto-reset toggle is redundant when gated sampling
* is active (no contamination enters the buffer to
* begin with), so it is hidden in that case to keep
* the menu focused. */
{MENU_ENUM_LABEL_FRAME_TIME_COUNTER_AUTO_RESET, PARSE_ONLY_BOOL, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_FRAME_TIME_COUNTER_AUTO_RESET:
build_list[i].checked =
!settings->bools.video_frame_time_sample_gated;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_REWIND_SETTINGS_LIST:
{
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_REWIND_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_REWIND_GRANULARITY, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_REWIND_BUFFER_SIZE, PARSE_ONLY_SIZE, true },
{MENU_ENUM_LABEL_REWIND_BUFFER_SIZE_STEP, PARSE_ONLY_UINT, true },
{MENU_ENUM_LABEL_AUDIO_REWIND_MUTE, PARSE_ONLY_BOOL, true },
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
/* Every item other than the toggle itself depends on
* rewind support being enabled; hide them while it is
* off (but keep them reachable from global search). */
if ( !include_everything
&& !settings->bools.rewind_enable
&& build_list[i].enum_idx != MENU_ENUM_LABEL_REWIND_ENABLE)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST:
{
#ifdef HAVE_REWIND
bool rewind_supported = true;
#endif
static menu_displaylist_build_info_selective_t build_list[] = {
#ifdef HAVE_REWIND
{MENU_ENUM_LABEL_REWIND_SETTINGS, PARSE_ACTION, false},
#endif
{MENU_ENUM_LABEL_FRAME_TIME_COUNTER_SETTINGS, PARSE_ACTION, true },
{MENU_ENUM_LABEL_FASTFORWARD_RATIO, PARSE_ONLY_FLOAT, true },
{MENU_ENUM_LABEL_FASTFORWARD_FRAMESKIP, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_FASTFORWARD_MUTE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_FASTFORWARD_SPEEDUP, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_AUDIO_FASTFORWARD_CALLBACK, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_SLOWMOTION_RATIO, PARSE_ONLY_FLOAT, true },
{MENU_ENUM_LABEL_VRR_RUNLOOP_ENABLE, PARSE_ONLY_BOOL, true },
{MENU_ENUM_LABEL_MENU_FRAME_RATE, PARSE_ONLY_UINT, true },
};
#ifdef HAVE_REWIND
if ( (flags & RUNLOOP_FLAG_CORE_RUNNING)
&& !retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
rewind_supported = core_info_current_supports_rewind();
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_REWIND_SETTINGS:
build_list[i].checked = rewind_supported;
break;
default:
break;
}
}
#endif
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
case DISPLAYLIST_MENU_SETTINGS_LIST:
{
bool menu_horizontal_animation = settings->bools.menu_horizontal_animation;
bool menu_materialui_icons_enable = settings->bools.menu_materialui_icons_enable;
bool menu_materialui_show_nav_bar = settings->bools.menu_materialui_show_nav_bar;
bool menu_use_preferred_system_color_theme = settings->bools.menu_use_preferred_system_color_theme;
bool truncate_playlist = settings->bools.ozone_truncate_playlist_name;
unsigned menu_rgui_color_theme = settings->uints.menu_rgui_color_theme;
unsigned menu_rgui_particle_effect = settings->uints.menu_rgui_particle_effect;
unsigned menu_screensaver_timeout = settings->uints.menu_screensaver_timeout;
unsigned ozone_font_scale = settings->uints.menu_ozone_font_scale;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_MENU_SCALE_FACTOR, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_OZONE_PADDING_FACTOR, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_MENU_FRAMEBUFFER_OPACITY, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_MENU_HDR_BRIGHTNESS_NITS, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_XMB_RIBBON_ENABLE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_XMB_THEME, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_XMB_MENU_COLOR_THEME, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_XMB_ALPHA_FACTOR, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_OZONE_MENU_COLOR_THEME, PARSE_ONLY_STRING_OPTIONS, false},
{MENU_ENUM_LABEL_MATERIALUI_MENU_COLOR_THEME, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_RGUI_MENU_COLOR_THEME, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_RGUI_MENU_THEME_PRESET, PARSE_ONLY_PATH, false},
{MENU_ENUM_LABEL_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_WALLPAPER, PARSE_ONLY_PATH , true},
{MENU_ENUM_LABEL_DYNAMIC_WALLPAPER, PARSE_ONLY_BOOL , true},
{MENU_ENUM_LABEL_MENU_WALLPAPER_OPACITY, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_MENU_RGUI_PARTICLE_EFFECT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_RGUI_PARTICLE_EFFECT_SPEED, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_MENU_RGUI_PARTICLE_EFFECT_SCREENSAVER, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_MENU_RGUI_BACKGROUND_FILLER_THICKNESS_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_BORDER_FILLER_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_BORDER_FILLER_THICKNESS_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_FULL_WIDTH_LAYOUT, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_TRANSPARENCY, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_MENU_LINEAR_FILTER, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_INTERNAL_UPSCALE_LEVEL, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_RGUI_ASPECT_RATIO, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_RGUI_ASPECT_RATIO_LOCK, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_XMB_VERTICAL_FADE_FACTOR, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_XMB_SHOW_HORIZONTAL_LIST, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_XMB_SHOW_TITLE_HEADER, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_XMB_TITLE_MARGIN, PARSE_ONLY_INT, true},
{MENU_ENUM_LABEL_MENU_XMB_TITLE_MARGIN_HORIZONTAL_OFFSET, PARSE_ONLY_INT, true},
{MENU_ENUM_LABEL_XMB_LAYOUT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_RGUI_SHADOWS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_XMB_SHADOWS_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_TEXTURE_MIPMAPPING, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MATERIALUI_ICONS_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MATERIALUI_PLAYLIST_ICONS_ENABLE, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_XMB_ENTRY_ICONS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_XMB_SWITCH_ICONS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_XMB_CURRENT_MENU_ICON, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_RGUI_SWITCH_ICONS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MATERIALUI_SWITCH_ICONS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_OZONE_HEADER_ICON, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_OZONE_HEADER_SEPARATOR, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_OZONE_SHOW_SIDEBAR, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_OZONE_COLLAPSE_SIDEBAR, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MATERIALUI_LANDSCAPE_LAYOUT_OPTIMIZATION, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MATERIALUI_SHOW_NAV_BAR, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MATERIALUI_AUTO_ROTATE_NAV_BAR, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_MATERIALUI_MENU_THUMBNAIL_VIEW_PORTRAIT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MATERIALUI_MENU_THUMBNAIL_VIEW_LANDSCAPE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MATERIALUI_DUAL_THUMBNAIL_LIST_VIEW_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MATERIALUI_THUMBNAIL_BACKGROUND_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_INLINE_THUMBNAILS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_THUMBNAILS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_LEFT_THUMBNAILS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_ICON_THUMBNAILS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_XMB_VERTICAL_THUMBNAILS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_XMB_THUMBNAIL_SCALE_FACTOR, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_OZONE_THUMBNAIL_SCALE_FACTOR, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_MENU_THUMBNAIL_UPSCALE_THRESHOLD, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_RGUI_SWAP_THUMBNAILS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DOWNSCALER, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DITHER, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_THUMBNAIL_DELAY, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_THUMBNAIL_BACKGROUND_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_THUMBNAIL_PREVIEW_AUDIO, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_THUMBNAIL_PREVIEW_THREADS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_XMB_FONT, PARSE_ONLY_PATH, true},
{MENU_ENUM_LABEL_OZONE_FONT, PARSE_ONLY_PATH, true},
{MENU_ENUM_LABEL_OZONE_FONT_SCALE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_GLOBAL, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_TITLE, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_SIDEBAR, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_LABEL, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_SUBLABEL, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_TIME, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_FOOTER, PARSE_ONLY_FLOAT, false},
{MENU_ENUM_LABEL_MENU_FONT_COLOR_RED, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_FONT_COLOR_GREEN, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_FONT_COLOR_BLUE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_OZONE_TRUNCATE_PLAYLIST_NAME, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_MENU_TICKER_TYPE, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_TICKER_SPEED, PARSE_ONLY_FLOAT, true},
{MENU_ENUM_LABEL_MENU_TICKER_SMOOTH, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_SHOW_FULL_PATHS, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_OZONE_SCROLL_CONTENT_METADATA, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_RGUI_EXTENDED_ASCII, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MATERIALUI_MENU_TRANSITION_ANIMATION, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_MENU_HORIZONTAL_ANIMATION, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_MENU_XMB_ANIMATION_HORIZONTAL_HIGHLIGHT, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_MENU_XMB_ANIMATION_OPENING_MAIN_MENU, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_MENU_XMB_ANIMATION_MOVE_UP_DOWN, PARSE_ONLY_UINT, true},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_MENU_XMB_ANIMATION_HORIZONTAL_HIGHLIGHT:
case MENU_ENUM_LABEL_MENU_XMB_ANIMATION_OPENING_MAIN_MENU:
build_list[i].checked = menu_horizontal_animation;
break;
case MENU_ENUM_LABEL_RGUI_MENU_THEME_PRESET:
build_list[i].checked = (menu_rgui_color_theme == RGUI_THEME_CUSTOM);
break;
case MENU_ENUM_LABEL_MENU_RGUI_TRANSPARENCY:
build_list[i].checked =
(menu_rgui_color_theme != RGUI_THEME_CUSTOM)
&& (menu_rgui_color_theme != RGUI_THEME_DYNAMIC);
break;
case MENU_ENUM_LABEL_MENU_RGUI_PARTICLE_EFFECT_SPEED:
build_list[i].checked =
(menu_rgui_particle_effect != RGUI_PARTICLE_EFFECT_NONE);
break;
case MENU_ENUM_LABEL_MENU_RGUI_PARTICLE_EFFECT_SCREENSAVER:
build_list[i].checked =
(menu_screensaver_timeout != 0)
&& (menu_rgui_particle_effect != RGUI_PARTICLE_EFFECT_NONE);
break;
case MENU_ENUM_LABEL_MATERIALUI_PLAYLIST_ICONS_ENABLE:
build_list[i].checked = menu_materialui_icons_enable;
break;
case MENU_ENUM_LABEL_MATERIALUI_AUTO_ROTATE_NAV_BAR:
build_list[i].checked = menu_materialui_show_nav_bar;
break;
case MENU_ENUM_LABEL_OZONE_MENU_COLOR_THEME:
build_list[i].checked = !menu_use_preferred_system_color_theme;
break;
case MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_GLOBAL:
build_list[i].checked = (ozone_font_scale == 1);
break;
case MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_TITLE:
case MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_SIDEBAR:
case MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_LABEL:
case MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_SUBLABEL:
case MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_TIME:
case MENU_ENUM_LABEL_OZONE_FONT_SCALE_FACTOR_FOOTER:
build_list[i].checked = (ozone_font_scale == 2);
break;
case MENU_ENUM_LABEL_OZONE_SORT_AFTER_TRUNCATE_PLAYLIST_NAME:
build_list[i].checked = truncate_playlist;
break;
case MENU_ENUM_LABEL_MENU_HDR_BRIGHTNESS_NITS:
build_list[i].checked = (settings->uints.video_hdr_mode > 0);
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
#ifdef _3DS
case DISPLAYLIST_MENU_BOTTOM_SETTINGS_LIST:
{
bool video_3ds_lcd_bottom = settings->bools.video_3ds_lcd_bottom;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_VIDEO_3DS_LCD_BOTTOM, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_BOTTOM_ASSETS_DIRECTORY, PARSE_ONLY_DIR, false},
{MENU_ENUM_LABEL_BOTTOM_FONT_ENABLE, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_BOTTOM_FONT_COLOR_RED, PARSE_ONLY_INT, false},
{MENU_ENUM_LABEL_BOTTOM_FONT_COLOR_GREEN, PARSE_ONLY_INT, false},
{MENU_ENUM_LABEL_BOTTOM_FONT_COLOR_BLUE, PARSE_ONLY_INT, false},
{MENU_ENUM_LABEL_BOTTOM_FONT_COLOR_OPACITY, PARSE_ONLY_INT, false},
{MENU_ENUM_LABEL_BOTTOM_FONT_SCALE, PARSE_ONLY_FLOAT, false},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_BOTTOM_ASSETS_DIRECTORY:
case MENU_ENUM_LABEL_BOTTOM_FONT_ENABLE:
case MENU_ENUM_LABEL_BOTTOM_FONT_COLOR_RED:
case MENU_ENUM_LABEL_BOTTOM_FONT_COLOR_GREEN:
case MENU_ENUM_LABEL_BOTTOM_FONT_COLOR_BLUE:
case MENU_ENUM_LABEL_BOTTOM_FONT_COLOR_OPACITY:
case MENU_ENUM_LABEL_BOTTOM_FONT_SCALE:
build_list[i].checked = video_3ds_lcd_bottom;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
#endif
case DISPLAYLIST_BROWSE_URL_LIST:
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BROWSE_URL),
MENU_ENUM_LABEL_BROWSE_URL_STR,
MENU_ENUM_LABEL_BROWSE_URL,
0, 0, 0, NULL))
count++;
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_BROWSE_START),
MENU_ENUM_LABEL_BROWSE_START_STR,
MENU_ENUM_LABEL_BROWSE_START,
0, 0, 0, NULL))
count++;
break;
case DISPLAYLIST_DISC_INFO:
#ifdef HAVE_CDROM
count = menu_displaylist_parse_disc_info(list,
MENU_SET_CDROM_INFO);
#endif
break;
case DISPLAYLIST_DUMP_DISC:
#ifdef HAVE_CDROM
count = menu_displaylist_parse_disc_info(list,
MENU_SET_CDROM_LIST);
#endif
break;
#ifdef HAVE_LAKKA
case DISPLAYLIST_EJECT_DISC:
#ifdef HAVE_CDROM
count = menu_displaylist_parse_disc_info(list,
MENU_SET_EJECT_DISC);
#endif /* HAVE_CDROM */
break;
#endif /* HAVE_LAKKA */
#ifdef HAVE_SMBCLIENT
case DISPLAYLIST_SMB_CLIENT_SETTINGS_LIST:
{
bool smb_enable = settings->bools.smb_client_enable;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_SMB_CLIENT_ENABLE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_SMB_CLIENT_SERVER, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_SMB_CLIENT_SHARE, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_SMB_CLIENT_SUBDIR, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_SMB_CLIENT_USERNAME, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_SMB_CLIENT_PASSWORD, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_SMB_CLIENT_WORKGROUP, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_SMB_CLIENT_AUTH_MODE, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_SMB_CLIENT_NUM_CONTEXTS, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_SMB_CLIENT_TIMEOUT, PARSE_ONLY_UINT, false},
{MENU_ENUM_LABEL_SMB_CLIENT_READAHEAD, PARSE_ONLY_UINT, false},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_SMB_CLIENT_SERVER:
case MENU_ENUM_LABEL_SMB_CLIENT_SHARE:
case MENU_ENUM_LABEL_SMB_CLIENT_SUBDIR:
case MENU_ENUM_LABEL_SMB_CLIENT_USERNAME:
case MENU_ENUM_LABEL_SMB_CLIENT_PASSWORD:
case MENU_ENUM_LABEL_SMB_CLIENT_WORKGROUP:
case MENU_ENUM_LABEL_SMB_CLIENT_AUTH_MODE:
case MENU_ENUM_LABEL_SMB_CLIENT_NUM_CONTEXTS:
case MENU_ENUM_LABEL_SMB_CLIENT_TIMEOUT:
case MENU_ENUM_LABEL_SMB_CLIENT_READAHEAD:
build_list[i].checked = smb_enable;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked && !include_everything)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx,
build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
#endif
#ifdef HAVE_NFSCLIENT
case DISPLAYLIST_NFS_CLIENT_SETTINGS_LIST:
{
static const menu_displaylist_build_info_t build_list[] = {
{MENU_ENUM_LABEL_NFS_CLIENT_SERVER, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_NFS_CLIENT_EXPORT, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_NFS_CLIENT_SUBDIR, PARSE_ONLY_STRING},
{MENU_ENUM_LABEL_NFS_CLIENT_TIMEOUT, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_NFS_CLIENT_NUM_CONTEXTS, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_NFS_CLIENT_PORT, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_NFS_CLIENT_MOUNT_PORT, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_NFS_CLIENT_VERSION, PARSE_ONLY_UINT},
{MENU_ENUM_LABEL_NFS_CLIENT_READAHEAD, PARSE_ONLY_UINT},
};
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx,
build_list[i].parse_type,
false) == 0)
count++;
}
}
break;
#endif
default:
break;
}
return count;
}
/* Returns true if selection pointer should be reset
* to zero when viewing specified history playlist */
static bool history_needs_navigation_clear(
menu_handle_t *menu, playlist_t *playlist)
{
if (menu)
{
/* If content is running, compare last selected path
* with current content path */
if (!retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
return string_is_equal(menu->deferred_path, path_get(RARCH_PATH_CONTENT));
/* If content is not running, have to examine the
* playlist... */
if (playlist)
{
if (menu->rpl_entry_selection_ptr < playlist_size(playlist))
{
const struct playlist_entry *entry = NULL;
playlist_get_index(playlist, menu->rpl_entry_selection_ptr, &entry);
return !string_is_equal(menu->deferred_path, entry->path);
}
}
}
return false;
}
static unsigned menu_displaylist_build_shader_parameter(
file_list_t *list, unsigned entry_type, unsigned _offset,
unsigned setting_type)
{
video_shader_ctx_t shader_info;
float current_value = 0.0f;
float original_value = 0.0f;
unsigned count = 0;
float min = 0.0f;
float max = 0.0f;
float half_step = 0.0f;
unsigned i = 0;
unsigned checked = 0;
bool checked_found = false;
struct video_shader_parameter *param = NULL;
unsigned offset = entry_type - _offset;
struct menu_state *menu_st = menu_state_get_ptr();
video_shader_driver_get_current_shader(&shader_info);
param = &shader_info.data->parameters[offset];
if (!param)
return 0;
min = param->minimum;
max = param->maximum;
half_step = param->step * 0.5f;
current_value = min;
original_value = video_shader_param_get(param);
if (half_step <= 0.0) /* safety check */
{
char val_s[16], val_d[16];
snprintf(val_s, sizeof(val_s), "%.2f", current_value);
snprintf(val_d, sizeof(val_d), "%d", 0);
menu_entries_append(list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type,
i, entry_type, NULL);
count = 1;
checked = 1.0;
checked_found = true;
}
else
{
for (i = 0; current_value < (max + 0.0001f); i++)
{
char val_s[16], val_d[16];
snprintf(val_s, sizeof(val_s), "%.2f", current_value);
snprintf(val_d, sizeof(val_d), "%d", i);
if (menu_entries_append(list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type,
i, entry_type, NULL))
{
if (!checked_found &&
(fabs(current_value - original_value) < half_step))
{
checked = count;
checked_found = true;
}
count++;
}
current_value += param->step;
}
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
return count;
}
#ifdef HAVE_NETWORKING
static size_t print_buf_lines(file_list_t *list, const char *label,
char *s, size_t len, enum msg_file_type type, bool append)
{
size_t i;
size_t count = 0;
char *line_start = s;
if (!s || !len)
return 0;
for (i = 0; i < len; i++)
{
if (*(s + i) == '\0')
break;
if (*(s + i) != '\n')
continue;
*(s + i) = '\0';
if (append)
{
if (menu_entries_append(list, line_start, label,
MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0, NULL))
count++;
}
else
{
menu_entries_prepend(list, line_start, label,
MENU_ENUM_LABEL_URL_ENTRY, type, 0, 0);
count++;
}
*(s + i) = '\n';
line_start = s + i + 1;
}
if (append && type != FILE_TYPE_DOWNLOAD_LAKKA)
file_list_sort_on_alt(list);
return count;
}
static unsigned menu_displaylist_netplay_kick(file_list_t *list)
{
unsigned count = 0;
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_REFRESH_CLIENT_INFO, NULL))
{
size_t i;
char client_id[4];
net_driver_state_t *net_st = networking_state_get_ptr();
for (i = 0; i < net_st->client_info_count; i++)
{
netplay_client_info_t *client = &net_st->client_info[i];
snprintf(client_id, sizeof(client_id), "%d", client->id);
if (menu_entries_append(list, client->name, client_id,
MENU_ENUM_LABEL_NETPLAY_KICK_CLIENT,
MENU_NETPLAY_KICK,
0, i, NULL))
count++;
}
}
return count;
}
static unsigned menu_displaylist_netplay_ban(file_list_t *list)
{
unsigned count = 0;
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_REFRESH_CLIENT_INFO, NULL))
{
size_t i;
char client_id[4];
net_driver_state_t *net_st = networking_state_get_ptr();
for (i = 0; i < net_st->client_info_count; i++)
{
netplay_client_info_t *client = &net_st->client_info[i];
snprintf(client_id, sizeof(client_id), "%d", client->id);
if (menu_entries_append(list, client->name, client_id,
MENU_ENUM_LABEL_NETPLAY_BAN_CLIENT,
MENU_NETPLAY_BAN,
0, i, NULL))
count++;
}
}
return count;
}
#endif
bool menu_displaylist_has_subsystems(void)
{
runloop_state_t *runloop_st = runloop_state_get_ptr();
const struct retro_subsystem_info* subsystem = runloop_st->subsystem_data;
rarch_system_info_t *sys_info = &runloop_st->system;
/* Core not loaded completely, use the data we
* peeked on load core */
/* Core fully loaded, use the subsystem data */
if (sys_info && sys_info->subsystem.data)
subsystem = sys_info->subsystem.data;
return (subsystem && runloop_st->subsystem_current_count > 0);
}
static bool menu_displaylist_keyboard_index(const rarch_setting_t *setting)
{
return setting->enum_idx >= MENU_ENUM_LABEL_INPUT_KEYBOARD_INDEX
&& setting->enum_idx <= MENU_ENUM_LABEL_INPUT_KEYBOARD_INDEX_LAST;
}
static bool menu_displaylist_ctl_internal(
enum menu_displaylist_ctl_state type,
menu_displaylist_info_t *info,
settings_t *settings)
{
struct menu_state *menu_st = menu_state_get_ptr();
menu_dialog_t *p_dialog = &menu_st->dialog_st;
bool push_list = (menu_st->driver_ctx->list_push
&& menu_st->driver_ctx->list_push(menu_st->driver_data,
menu_st->userdata, info, type) == 0);
if (!push_list)
{
menu_handle_t *menu = menu_st->driver_data;
bool load_content = true;
bool use_filebrowser = false;
unsigned count = 0;
int ret = 0;
switch (type)
{
case DISPLAYLIST_NETWORK_HOSTING_SETTINGS_LIST:
#ifdef HAVE_NETWORKING
{
size_t i;
file_list_t *list = info->list;
bool netplay_allow_slaves = settings->bools.netplay_allow_slaves;
bool netplay_use_mitm_server = settings->bools.netplay_use_mitm_server;
static menu_displaylist_build_info_selective_t build_list[] = {
{MENU_ENUM_LABEL_NETPLAY_TCP_UDP_PORT, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_MAX_CONNECTIONS, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_MAX_PING, PARSE_ONLY_UINT, true},
{MENU_ENUM_LABEL_NETPLAY_PUBLIC_ANNOUNCE, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_USE_MITM_SERVER, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_MITM_SERVER, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_NETPLAY_CUSTOM_MITM_SERVER, PARSE_ONLY_STRING, false},
{MENU_ENUM_LABEL_NETPLAY_PASSWORD, PARSE_ONLY_STRING, true},
{MENU_ENUM_LABEL_NETPLAY_SPECTATE_PASSWORD, PARSE_ONLY_STRING, true},
{MENU_ENUM_LABEL_NETPLAY_ALLOW_PAUSING, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_ALLOW_SLAVES, PARSE_ONLY_BOOL, true},
{MENU_ENUM_LABEL_NETPLAY_REQUIRE_SLAVES, PARSE_ONLY_BOOL, false},
{MENU_ENUM_LABEL_NETPLAY_NAT_TRAVERSAL, PARSE_ONLY_BOOL, true},
};
menu_entries_clear(list);
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_ENABLED, NULL))
{
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_SERVER, NULL))
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_DISABLE_HOST),
MENU_ENUM_LABEL_NETPLAY_DISCONNECT_STR,
MENU_ENUM_LABEL_NETPLAY_DISCONNECT,
MENU_SETTING_ACTION, 0, 0, NULL);
if (netplay_driver_ctl(RARCH_NETPLAY_CTL_IS_DATA_INITED, NULL))
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_KICK),
MENU_ENUM_LABEL_NETPLAY_KICK_STR,
MENU_ENUM_LABEL_NETPLAY_KICK,
MENU_SETTING_ACTION, 0, 0, NULL);
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_BAN),
MENU_ENUM_LABEL_NETPLAY_BAN_STR,
MENU_ENUM_LABEL_NETPLAY_BAN,
MENU_SETTING_ACTION, 0, 0, NULL);
}
}
}
else
{
menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE_HOST),
MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST_STR,
MENU_ENUM_LABEL_NETPLAY_ENABLE_HOST,
MENU_SETTING_ACTION, 0, 0, NULL);
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
switch (build_list[i].enum_idx)
{
case MENU_ENUM_LABEL_NETPLAY_REQUIRE_SLAVES:
build_list[i].checked = netplay_allow_slaves;
break;
case MENU_ENUM_LABEL_NETPLAY_MITM_SERVER:
case MENU_ENUM_LABEL_NETPLAY_CUSTOM_MITM_SERVER:
build_list[i].checked = netplay_use_mitm_server;
break;
default:
break;
}
}
for (i = 0; i < ARRAY_SIZE(build_list); i++)
{
if (!build_list[i].checked)
continue;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list,
build_list[i].enum_idx, build_list[i].parse_type,
false) == 0)
count++;
}
}
#endif
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_NETPLAY_KICK_LIST:
#ifdef HAVE_NETWORKING
menu_entries_clear(info->list);
count = menu_displaylist_netplay_kick(info->list);
if (count == 0)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_CLIENTS_FOUND),
MENU_ENUM_LABEL_NO_NETPLAY_CLIENTS_FOUND_STR,
MENU_ENUM_LABEL_NO_NETPLAY_CLIENTS_FOUND,
0, 0, 0, NULL))
count++;
#endif
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_NETPLAY_BAN_LIST:
#ifdef HAVE_NETWORKING
menu_entries_clear(info->list);
count = menu_displaylist_netplay_ban(info->list);
if (count == 0)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_NETPLAY_CLIENTS_FOUND),
MENU_ENUM_LABEL_NO_NETPLAY_CLIENTS_FOUND_STR,
MENU_ENUM_LABEL_NO_NETPLAY_CLIENTS_FOUND,
0, 0, 0, NULL))
count++;
#endif
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_OPTIONS_REMAPPINGS_PORT:
{
unsigned max_users = settings->uints.input_max_users;
const char *menu_driver = menu_driver_ident();
#ifdef HAVE_RGUI
bool is_rgui = !strcmp(menu_driver, "rgui");
#endif
file_list_t *list = info->list;
unsigned port = string_to_unsigned(info->path);
unsigned mapped_port = settings->uints.input_remap_ports[port];
size_t selection = menu_st->selection_ptr;
menu_entries_clear(info->list);
{
char key[64];
key[0] = '\0';
snprintf(key, sizeof(key),
MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE_STR, mapped_port + 1);
if (MENU_DISPLAYLIST_PARSE_SETTINGS(list,
key, PARSE_ONLY_UINT, true, MENU_SETTINGS_INPUT_LIBRETRO_DEVICE) == 0)
count++;
snprintf(key, sizeof(key),
MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE_STR, port + 1);
if (MENU_DISPLAYLIST_PARSE_SETTINGS(list,
key, PARSE_ONLY_UINT, true, MENU_SETTINGS_INPUT_ANALOG_DPAD_MODE) == 0)
count++;
snprintf(key, sizeof(key),
MENU_ENUM_LABEL_INPUT_REMAP_PORT_STR, port + 1);
if (MENU_DISPLAYLIST_PARSE_SETTINGS(list,
key, PARSE_ONLY_UINT, true, MENU_SETTINGS_INPUT_INPUT_REMAP_PORT) == 0)
count++;
}
{
char name[NAME_MAX_LENGTH];
size_t _len = 0;
unsigned j;
unsigned device = (mapped_port < MAX_USERS)
? settings->uints.input_libretro_device[mapped_port]
: RETRO_DEVICE_NONE;
device &= RETRO_DEVICE_MASK;
if ( device == RETRO_DEVICE_JOYPAD
|| device == RETRO_DEVICE_ANALOG
|| device == RETRO_DEVICE_KEYBOARD)
{
const char *val_port = msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PORT);
/* press a button, land on its entry below */
if (menu_entries_append(list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_INPUT_REMAP_FIND),
MENU_ENUM_LABEL_INPUT_REMAP_FIND_STR,
MENU_ENUM_LABEL_INPUT_REMAP_FIND,
MENU_SETTING_ACTION, 0, port, NULL))
count++;
for (j = 0; j < RARCH_ANALOG_BIND_LIST_END; j++)
{
char descriptor[300];
unsigned retro_id =
(j < RARCH_ANALOG_BIND_LIST_END)
? input_config_bind_order[j]
: j;
const struct retro_keybind *keybind =
input_config_bind(port, retro_id);
const struct retro_keybind *auto_bind =
(const struct retro_keybind*)
input_config_get_bind_auto(port, retro_id);
size_t desc_len = input_config_get_bind_string(
settings, descriptor,
keybind, auto_bind,
input_config_bind_names(port, retro_id),
input_autoconf_bind_names(port, retro_id),
sizeof(descriptor));
if (!strstr(descriptor, "Auto"))
{
char desc_lbl[400];
_len = strlcpy(desc_lbl,
msg_hash_to_str(input_config_bind_label(retro_id)),
sizeof(desc_lbl));
_len += strlcpy_lit(desc_lbl + _len, ", ", sizeof(desc_lbl) - _len);
strlcpy(desc_lbl + _len, descriptor, sizeof(desc_lbl) - _len);
desc_len = strlcpy(descriptor, desc_lbl, sizeof(descriptor));
}
#ifdef HAVE_RGUI
/* Add user index when display driver == rgui and sublabels
* are disabled, but only if there is more than one user */
if ( is_rgui
&& max_users > 1
&& !settings->bools.menu_show_sublabels)
{
desc_len += strlcpy_lit(descriptor + desc_len, " [", sizeof(descriptor) - desc_len);
snprintf(descriptor + desc_len, sizeof(descriptor) - desc_len," %s %u]",
val_port, port + 1);
}
#endif
_len = snprintf(name, sizeof(name), "p%u_", port + 1);
strlcpy(name + _len,
input_config_bind_map_get_base(retro_id),
sizeof(name) - _len);
if (device == RETRO_DEVICE_JOYPAD || device == RETRO_DEVICE_ANALOG)
{
if (menu_entries_append(list, descriptor, name,
MSG_UNKNOWN,
MENU_SETTINGS_INPUT_DESC_BEGIN +
(port * RARCH_ANALOG_BIND_LIST_END) + retro_id, 0, 0, NULL))
count++;
}
else if (device == RETRO_DEVICE_KEYBOARD)
{
if (menu_entries_append(list, descriptor, name,
MSG_UNKNOWN,
MENU_SETTINGS_INPUT_DESC_KBD_BEGIN +
(port * RARCH_ANALOG_BIND_LIST_END) + retro_id, 0, 0, NULL))
count++;
}
}
}
}
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
if (selection >= count)
{
/* 'None' shortens the list: stay on Mapped Port,
* its last entry */
if (mapped_port >= MAX_USERS && count)
menu_st->selection_ptr = count - 1;
else
info->flags |= MD_FLAG_NEED_CLEAR;
}
}
break;
#ifdef HAVE_CDROM
case DISPLAYLIST_CDROM_DETAIL_INFO:
{
RFILE *file;
media_detect_cd_info_t cd_info = {{0}};
char file_path[PATH_MAX_LENGTH] = {0};
char drive = info->path[0];
bool atip = false;
menu_entries_clear(info->list);
count = 0;
if (cdrom_drive_has_media(drive))
{
cdrom_device_fillpath(file_path, sizeof(file_path), drive, 0, true);
/* opening the cue triggers storing of TOC info internally */
if ((file = filestream_open(file_path, RETRO_VFS_FILE_ACCESS_READ,
0)))
{
unsigned i;
const cdrom_toc_t *toc = retro_vfs_file_get_cdrom_toc(
filestream_get_vfs_handle(file));
unsigned first_data_track = 1;
atip = cdrom_has_atip(
filestream_get_vfs_handle(file));
for (i = 0; i < toc->num_tracks; i++)
{
if (!toc->track[i].audio)
{
first_data_track = i + 1;
break;
}
}
/* open first data track */
memset(file_path, 0, sizeof(file_path));
cdrom_device_fillpath(file_path, sizeof(file_path), drive, first_data_track, false);
if (media_detect_cd_info(file_path, 0, &cd_info))
{
char entry[NAME_MAX_LENGTH];
unsigned i;
/* Format strings below */
static const struct
{
enum msg_hash_enums label;
size_t field;
} text_fields[] = {
{ MENU_ENUM_LABEL_VALUE_DISC_INFO_TITLE, offsetof(media_detect_cd_info_t, title) },
{ MENU_ENUM_LABEL_VALUE_DISC_INFO_SYSTEM, offsetof(media_detect_cd_info_t, system) },
{ MENU_ENUM_LABEL_VALUE_DISC_INFO_SERIAL, offsetof(media_detect_cd_info_t, serial) },
{ MENU_ENUM_LABEL_VALUE_DISC_INFO_VERSION, offsetof(media_detect_cd_info_t, version) },
{ MENU_ENUM_LABEL_VALUE_DISC_INFO_RELEASE_DATE, offsetof(media_detect_cd_info_t, release_date) }
};
for (i = 0; i < sizeof(text_fields) / sizeof(text_fields[0]); i++)
{
const char *v = (const char*)&cd_info + text_fields[i].field;
if (!*v)
continue;
snprintf(entry, sizeof(entry),
msg_hash_to_str(text_fields[i].label), v);
if (menu_entries_append(info->list, entry, "",
MSG_UNKNOWN, FILE_TYPE_NONE, 0, 0, NULL))
count++;
}
/* Genuine disc: the ATIP is what a pressed
* disc lacks */
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFO_GENUINE),
msg_hash_to_str(atip
? MENU_ENUM_LABEL_VALUE_NO
: MENU_ENUM_LABEL_VALUE_YES));
if (menu_entries_append(info->list, entry, "",
MSG_UNKNOWN, FILE_TYPE_NONE, 0, 0, NULL))
count++;
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFO_TRACKS),
toc->num_tracks);
if (menu_entries_append(info->list, entry, "",
MSG_UNKNOWN, FILE_TYPE_NONE, 0, 0, NULL))
count++;
for (i = 0; i < toc->num_tracks; i++)
{
char mode[32];
unsigned char min = 0;
unsigned char sec = 0;
unsigned char frame = 0;
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFO_TRACK), i + 1);
if (menu_entries_append(info->list, entry, "",
MSG_UNKNOWN, FILE_TYPE_NONE, 0, 0, NULL))
count++;
if (toc->track[i].audio)
strlcpy(mode,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFO_TRACK_AUDIO),
sizeof(mode));
else
snprintf(mode, sizeof(mode),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFO_TRACK_DATA_MODE),
toc->track[i].mode % 10);
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFO_TRACK_MODE), mode);
if (menu_entries_append(info->list, entry, "",
MSG_UNKNOWN, FILE_TYPE_NONE, 0, 0, NULL))
count++;
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFO_TRACK_SIZE),
toc->track[i].track_bytes / 1000.0 / 1000.0);
if (menu_entries_append(info->list, entry, "",
MSG_UNKNOWN, FILE_TYPE_NONE, 0, 0, NULL))
count++;
cdrom_lba_to_msf(toc->track[i].track_size, &min, &sec, &frame);
snprintf(entry, sizeof(entry),
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DISC_INFO_TRACK_LENGTH),
min, sec, frame);
if (menu_entries_append(info->list, entry, "",
MSG_UNKNOWN, FILE_TYPE_NONE, 0, 0, NULL))
count++;
}
}
else
RARCH_ERR("[CDROM] Could not detect any disc info.\n");
filestream_close(file);
}
else
RARCH_ERR("[CDROM] Error opening file for reading: %s.\n", file_path);
}
else
{
const char *_msg = msg_hash_to_str(MSG_NO_DISC_INSERTED);
RARCH_LOG("[CDROM] No media is inserted or drive is not ready.\n");
runloop_msg_queue_push(_msg, strlen(_msg), 1, 100, true, NULL,
MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
}
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
break;
}
case DISPLAYLIST_LOAD_DISC:
menu_entries_clear(info->list);
count = menu_displaylist_parse_disc_info(info->list,
MENU_SET_LOAD_CDROM_LIST);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
break;
#else
case DISPLAYLIST_CDROM_DETAIL_INFO:
case DISPLAYLIST_LOAD_DISC:
/* No-op */
break;
#endif
#ifdef HAVE_LAKKA
case DISPLAYLIST_CPU_POLICY_LIST:
menu_entries_clear(info->list);
menu_entries_append(info->list,
info->path,
info->path,
MENU_ENUM_LABEL_CPU_POLICY_MIN_FREQ,
MENU_SETTINGS_CPU_POLICY_SET_MINFREQ, 0, 0, NULL);
menu_entries_append(info->list,
info->path,
info->path,
MENU_ENUM_LABEL_CPU_POLICY_MAX_FREQ,
MENU_SETTINGS_CPU_POLICY_SET_MAXFREQ, 0, 0, NULL);
menu_entries_append(info->list,
info->path,
info->path,
MENU_ENUM_LABEL_CPU_POLICY_GOVERNOR,
MENU_SETTINGS_CPU_POLICY_SET_GOVERNOR, 0, 0, NULL);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
break;
case DISPLAYLIST_CPU_PERFPOWER_LIST:
{
cpu_scaling_driver_t **drivers = get_cpu_scaling_drivers(true);
menu_entries_clear(info->list);
if (drivers)
{
int count = 0;
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_PERF_MODE),
MENU_ENUM_LABEL_CPU_PERF_MODE_STR,
MENU_ENUM_LABEL_CPU_PERF_MODE,
0, 0, 0, NULL);
switch (get_cpu_scaling_mode(NULL))
{
case CPUSCALING_MANUAL:
while (*drivers)
{
char policyid[16];
snprintf(policyid, sizeof(policyid), "%u", count++);
menu_entries_append(info->list,
policyid,
policyid,
MENU_ENUM_LABEL_CPU_POLICY_ENTRY,
0, 0, 0, NULL);
drivers++;
}
break;
case CPUSCALING_MANAGED_PER_CONTEXT:
/* Allows user to pick two governors */
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_POLICY_CORE_GOVERNOR),
"0",
MENU_ENUM_LABEL_CPU_POLICY_CORE_GOVERNOR,
0, 0, 0, NULL);
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CPU_POLICY_MENU_GOVERNOR),
"1",
MENU_ENUM_LABEL_CPU_POLICY_MENU_GOVERNOR,
0, 0, 0, NULL);
/* fallthrough */
case CPUSCALING_MANAGED_PERFORMANCE:
/* Allow users to choose max/min frequencies */
menu_entries_append(info->list,
"0",
"0",
MENU_ENUM_LABEL_CPU_MANAGED_MIN_FREQ,
MENU_SETTINGS_CPU_MANAGED_SET_MINFREQ,
0, 0, NULL);
menu_entries_append(info->list,
"1",
"1",
MENU_ENUM_LABEL_CPU_MANAGED_MAX_FREQ,
MENU_SETTINGS_CPU_MANAGED_SET_MAXFREQ,
0, 0, NULL);
break;
case CPUSCALING_MAX_PERFORMANCE:
case CPUSCALING_MIN_POWER:
case CPUSCALING_BALANCED:
/* No settings for these modes */
break;
}
}
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
break;
}
#endif
#if defined(HAVE_LIBNX)
case DISPLAYLIST_SWITCH_CPU_PROFILE:
{
size_t _len;
unsigned i;
char text[128];
/* TODO/FIXME - localize */
runloop_msg_queue_push(
"Warning : extended overclocking can damage the Switch",
STRLEN_CONST("Warning : extended overclocking can damage the Switch"),
1, 90, true, NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
menu_entries_clear(info->list);
{
u32 currentClock = 0;
if (hosversionBefore(8, 0, 0))
pcvGetClockRate(PcvModule_CpuBus, &currentClock);
else
{
ClkrstSession session = {0};
clkrstOpenSession(&session, PcvModuleId_CpuBus, 3);
clkrstGetClockRate(&session, &currentClock);
clkrstCloseSession(&session);
}
/* TODO/FIXME - localize */
_len = strlcpy_lit(text, "Current clock: ", sizeof(text));
snprintf(text + _len, sizeof(text) - _len, "%i", currentClock);
}
if (menu_entries_append(info->list,
text, "", 0, MENU_INFO_MESSAGE,
0, 0, NULL))
count++;
for (i = 0; SWITCH_CPU_PROFILES[i]; i++)
{
char title[NAME_MAX_LENGTH];
size_t _len = strlcpy(title, SWITCH_CPU_PROFILES[i],
sizeof(title));
_len += strlcpy_lit(title + _len, " (", sizeof(title) - _len);
_len += strlcpy(title + _len, SWITCH_CPU_SPEEDS[i],
sizeof(title) - _len);
_len += strlcpy_lit(title + _len, ")", sizeof(title) - _len);
if (menu_entries_append(info->list, title, "", 0,
MENU_SET_SWITCH_CPU_PROFILE, 0, i, NULL))
count++;
}
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
break;
}
#endif /* HAVE_LIBNX */
case DISPLAYLIST_MUSIC_LIST:
{
#if defined(HAVE_AUDIOMIXER) || defined(HAVE_FFMPEG) || defined(HAVE_MPV)
char combined_path[PATH_MAX_LENGTH];
const char *ext = NULL;
bool multimedia_builtin_mediaplayer_enable = settings->bools.multimedia_builtin_mediaplayer_enable;
fill_pathname_join_special(combined_path, menu->scratch2_buf,
menu->scratch_buf, sizeof(combined_path));
ext = path_get_extension(combined_path);
#endif
menu_entries_clear(info->list);
#if defined(HAVE_AUDIOMIXER) || defined(HAVE_FFMPEG) || defined(HAVE_MPV)
if (multimedia_builtin_mediaplayer_enable)
{
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
struct retro_system_info sysinfo = {0};
#endif
#ifdef HAVE_AUDIOMIXER
if (audio_driver_mixer_extension_supported(ext))
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION),
MENU_ENUM_LABEL_ADD_TO_MIXER_AND_COLLECTION_STR,
MENU_ENUM_LABEL_ADD_TO_MIXER_AND_COLLECTION,
FILE_TYPE_PLAYLIST_ENTRY, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY),
MENU_ENUM_LABEL_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY_STR,
MENU_ENUM_LABEL_ADD_TO_MIXER_AND_COLLECTION_AND_PLAY,
FILE_TYPE_PLAYLIST_ENTRY, 0, 0, NULL))
count++;
}
#endif
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV)
#if defined(HAVE_FFMPEG)
libretro_ffmpeg_retro_get_system_info(&sysinfo);
#elif defined(HAVE_MPV)
libretro_mpv_retro_get_system_info(&sysinfo);
#endif
if (strstr(sysinfo.valid_extensions,ext))
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RUN_MUSIC),
MENU_ENUM_LABEL_RUN_MUSIC_STR,
MENU_ENUM_LABEL_RUN_MUSIC,
FILE_TYPE_PLAYLIST_ENTRY, 0, 0, NULL))
count++;
}
#endif
}
#endif
}
if (count == 0)
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ITEMS),
MENU_ENUM_LABEL_NO_ITEMS_STR,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_NO_ITEM, 0, 0, NULL);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
break;
case DISPLAYLIST_MIXER_STREAM_SETTINGS_LIST:
menu_entries_clear(info->list);
#ifdef HAVE_AUDIOMIXER
{
char lbl[128];
unsigned id = info->type - MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_BEGIN;
size_t _len = strlcpy_lit(lbl, "mixer_stream_", sizeof(lbl));
_len += snprintf(lbl + _len, sizeof(lbl) - _len, "%d", id);
strlcpy_lit(lbl + _len, "_action_play", sizeof(lbl) - _len);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY),
lbl,
MSG_UNKNOWN,
(MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_BEGIN + id),
0, 0, NULL))
count++;
strlcpy_lit(lbl + _len, "_action_play_looped", sizeof(lbl) - _len);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_LOOPED),
lbl,
MSG_UNKNOWN,
(MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_LOOPED_BEGIN + id),
0, 0, NULL))
count++;
strlcpy_lit(lbl + _len, "_action_play_sequential",sizeof(lbl) - _len);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_PLAY_SEQUENTIAL),
lbl,
MSG_UNKNOWN,
(MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_PLAY_SEQUENTIAL_BEGIN + id),
0, 0, NULL))
count++;
strlcpy_lit(lbl + _len, "_action_stop", sizeof(lbl) - _len);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_STOP),
lbl,
MSG_UNKNOWN,
(MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_STOP_BEGIN + id),
0, 0, NULL))
count++;
strlcpy_lit(lbl + _len, "_action_remove", sizeof(lbl) - _len);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_REMOVE),
lbl,
MSG_UNKNOWN,
(MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_REMOVE_BEGIN + id),
0, 0, NULL))
count++;
strlcpy_lit(lbl + _len, "_action_volume", sizeof(lbl) - _len);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_MIXER_ACTION_VOLUME),
lbl,
MSG_UNKNOWN,
(MENU_SETTINGS_AUDIO_MIXER_STREAM_ACTIONS_VOLUME_BEGIN + id),
0, 0, NULL))
count++;
}
#endif
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
break;
case DISPLAYLIST_NETPLAY:
menu_entries_clear(info->list);
info->flags |= MD_FLAG_NEED_PUSH;
/* TODO/FIXME ? */
break;
case DISPLAYLIST_INFORMATION:
menu_entries_clear(info->list);
if (settings)
count = menu_displaylist_parse_content_information(menu,
settings, info->list);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DATABASE_ENTRY:
menu_entries_clear(info->list);
{
char *elem0 = NULL;
char *elem1 = NULL;
#ifdef HAVE_LIBRETRODB
bool parse_database = false;
#endif
if (info->label && *info->label)
{
char *delim = strchr(info->label, '|');
if (delim)
{
*delim = '\0';
if (*(delim + 1) != '\0')
elem1 = delim + 1;
if (info->label[0] != '\0')
elem0 = info->label;
}
}
if (info->path_b && *info->path_b)
{
free(info->path_b);
info->path_b = NULL;
}
if (elem0 && elem1)
{
info->path_b = strdup(elem1);
/* Trim label in place by null-terminating at the delimiter
* (already done above). info->label still owns the buffer
* and now only contains elem0. */
#ifdef HAVE_LIBRETRODB
parse_database = true;
#endif
}
else
{
/* Neither element needed; free label since the original
* code path freed it unconditionally. */
free(info->label);
info->label = NULL;
}
#ifdef HAVE_LIBRETRODB
if (parse_database)
ret = menu_displaylist_parse_database_entry(menu, info,
settings->bools.menu_show_advanced_settings,
settings->bools.playlist_use_old_format,
settings->bools.playlist_compression,
settings->bools.playlist_fuzzy_archive_match,
settings->bools.playlist_portable_paths,
settings->paths.directory_playlist,
settings->paths.directory_menu_content
);
else
info->flags |= MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
#else
ret = 0;
info->flags |= MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
#endif
}
info->flags |= MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DATABASE_QUERY:
menu_entries_clear(info->list);
#ifdef HAVE_LIBRETRODB
{
unsigned i;
const char *query = (info->path_c && *info->path_c) ? info->path_c : NULL;
/* Full .rdb scan - runs on the task queue; result
* arrives via the one-slot cache and this list is
* refreshed by the task callback. The cache owns the
* returned list. */
database_info_list_t *db_list = menu_dbinfo_cache_get(info->path, query);
if (db_list)
{
for (i = 0; i < db_list->count; i++)
{
if (db_list->list[i].name && *db_list->list[i].name)
if (menu_entries_append(info->list, db_list->list[i].name,
info->path, MENU_ENUM_LABEL_RDB_ENTRY, FILE_TYPE_RDB_ENTRY, 0, 0, NULL))
count++;
}
}
else if (!menu_dbinfo_cache_has(info->path, query))
{
/* Never scanned (a cached NULL means the scan
* failed: fall through with no entries so the
* empty-list fallback shows, without re-pushing) */
if (!menu_dbinfo_load_in_progress(NULL))
task_push_dbinfo_load(info->path, query);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_EXPLORE_INITIALISING_LIST),
MENU_ENUM_LABEL_EXPLORE_INITIALISING_LIST_STR,
MENU_ENUM_LABEL_EXPLORE_INITIALISING_LIST,
FILE_TYPE_NONE, 0, 0, NULL))
count++;
}
}
#endif
if (info->path && *info->path)
free(info->path);
info->path = strdup(info->path_b);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_SORT
| MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_OPTIONS_SHADERS:
menu_entries_clear(info->list);
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
unsigned i;
struct video_shader *shader = menu_shader_get();
unsigned pass_count = shader ? shader->passes : 0;
bool video_shader_enable = settings->bools.video_shader_enable;
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_VIDEO_SHADERS_ENABLE,
PARSE_ONLY_BOOL, false) == 0)
count++;
if (video_shader_enable)
{
char buf_tmp[64];
size_t _len;
const char *val_shdr =
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER);
const char *shdr_pass =
MENU_ENUM_LABEL_VIDEO_SHADER_PASS_STR;
const char *shdr_filter_pass =
MENU_ENUM_LABEL_VIDEO_SHADER_FILTER_PASS_STR;
const char *shdr_scale_pass =
MENU_ENUM_LABEL_VIDEO_SHADER_SCALE_PASS_STR;
const char *val_filter =
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_FILTER);
const char *val_scale =
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SCALE);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_MANAGER),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_MANAGER_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_MANAGER,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS),
MENU_ENUM_LABEL_VIDEO_SHADER_PARAMETERS_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PARAMETERS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET,
FILE_TYPE_PATH, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_PREPEND),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_PREPEND_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_PREPEND,
FILE_TYPE_PATH, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_APPEND),
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_APPEND_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_PRESET_APPEND,
FILE_TYPE_PATH, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES),
MENU_ENUM_LABEL_SHADER_APPLY_CHANGES_STR,
MENU_ENUM_LABEL_SHADER_APPLY_CHANGES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES),
MENU_ENUM_LABEL_VIDEO_SHADER_NUM_PASSES_STR,
MENU_ENUM_LABEL_VIDEO_SHADER_NUM_PASSES,
0, 0, 0, NULL))
count++;
_len = strlcpy(buf_tmp, val_shdr, sizeof(buf_tmp));
for (i = 0; i < pass_count; i++)
{
size_t _len3;
size_t _len2 = _len + snprintf(buf_tmp + _len, sizeof(buf_tmp) - _len, " #%u", i);
if (menu_entries_append(info->list, buf_tmp, shdr_pass,
MENU_ENUM_LABEL_VIDEO_SHADER_PASS,
MENU_SETTINGS_SHADER_PASS_0 + i, 0, 0, NULL))
count++;
buf_tmp[ _len2] = ' ';
buf_tmp[++_len2] = '\0';
_len3 = _len2;
strlcpy(buf_tmp + _len3, val_filter, sizeof(buf_tmp) - _len3);
if (menu_entries_append(info->list, buf_tmp, shdr_filter_pass,
MENU_ENUM_LABEL_VIDEO_SHADER_FILTER_PASS,
MENU_SETTINGS_SHADER_PASS_FILTER_0 + i, 0, 0, NULL))
count++;
_len3 = _len2;
strlcpy(buf_tmp + _len3, val_scale, sizeof(buf_tmp) - _len3);
if (menu_entries_append(info->list, buf_tmp, shdr_scale_pass,
MENU_ENUM_LABEL_VIDEO_SHADER_SCALE_PASS,
MENU_SETTINGS_SHADER_PASS_SCALE_0 + i, 0, 0, NULL))
count++;
}
}
}
#endif
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_CORE_CONTENT:
menu_entries_clear(info->list);
#ifdef HAVE_NETWORKING
count = (unsigned)print_buf_lines(info->list, "", menu->core_buf,
menu->core_len, FILE_TYPE_DOWNLOAD_CORE_CONTENT,
true);
/* Mark entries with "[#]" if the file already exists in the
* download directory (core assets folder + category sub-folder). */
{
char content_dir[PATH_MAX_LENGTH];
const char *core_assets = settings->paths.directory_core_assets;
content_dir[0] = '\0';
if (core_assets && *core_assets && info->path && *info->path)
{
const char *category = path_basename(info->path);
if (category && *category)
fill_pathname_join_special(content_dir, core_assets,
category, sizeof(content_dir));
}
if (*content_dir)
{
size_t i;
for (i = 0; i < count; i++)
{
char chk_path[PATH_MAX_LENGTH];
const char *fname = info->list->list[i].path;
if (!fname || !*fname)
continue;
fill_pathname_join_special(chk_path, content_dir, fname,
sizeof(chk_path));
if (path_is_valid(chk_path))
file_list_set_label_at_offset(info->list, i, "[#]");
}
}
}
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
#endif
break;
case DISPLAYLIST_CORE_CONTENT_DIRS:
menu_entries_clear(info->list);
{
#ifdef HAVE_NETWORKING
char new_label[NAME_MAX_LENGTH];
const char *
network_buildbot_assets_url = settings->paths.network_buildbot_assets_url;
fill_pathname_join_special(new_label,
network_buildbot_assets_url,
"cores", sizeof(new_label));
if ((count = (unsigned)print_buf_lines(info->list, new_label, menu->core_buf,
menu->core_len, FILE_TYPE_DOWNLOAD_URL, true)) == 0)
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY_STR,
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
#endif
}
break;
case DISPLAYLIST_CORE_SYSTEM_FILES:
menu_entries_clear(info->list);
#ifdef HAVE_NETWORKING
count = (unsigned)print_buf_lines(info->list, "", menu->core_buf,
menu->core_len, FILE_TYPE_DOWNLOAD_CORE_SYSTEM_FILES,
true);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
#endif
break;
case DISPLAYLIST_CORES_UPDATER:
menu_entries_clear(info->list);
#ifdef HAVE_NETWORKING
{
core_updater_list_t *core_list = core_updater_list_get_cached();
menu_search_terms_t *search_terms= menu_entries_search_get_terms();
bool show_experimental_cores = settings->bools.network_buildbot_show_experimental_cores;
size_t selection = menu_st->selection_ptr;
if (core_list)
{
size_t menu_index = 0;
size_t i;
for (i = 0; i < core_updater_list_size(core_list); i++)
{
const core_updater_list_entry_t *entry = NULL;
if (core_updater_list_get_index(core_list, i, &entry))
{
/* Skip 'experimental' cores, if required
* > Note: We always show cores that are already
* installed, regardless of status (a user should
* always have the option to update existing cores) */
if ( !show_experimental_cores
&& (entry->is_experimental
&& !path_is_valid(entry->local_core_path)))
continue;
/* If a search is active, skip non-matching
* entries */
if (search_terms)
{
bool entry_valid = true;
size_t j;
for (j = 0; j < search_terms->size; j++)
{
const char *search_term = search_terms->terms[j];
if ( (search_term && *search_term)
&& (entry->display_name && *entry->display_name)
&& !compat_strcasestr(entry->display_name, search_term))
{
entry_valid = false;
break;
}
}
if (!entry_valid)
continue;
}
if (menu_entries_append(info->list,
entry->remote_filename,
"",
MENU_ENUM_LABEL_CORE_UPDATER_ENTRY,
FILE_TYPE_DOWNLOAD_CORE, 0, 0, NULL))
{
file_list_set_alt_at_offset(
info->list, menu_index, entry->display_name);
menu_index++;
count++;
}
}
}
}
if (selection >= count)
info->flags |= MD_FLAG_NEED_CLEAR;
}
#endif
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_PL_THUMBNAILS_UPDATER:
menu_entries_clear(info->list);
#ifdef HAVE_NETWORKING
count = menu_displaylist_parse_pl_thumbnail_download_list(
info->list,
settings->paths.directory_playlist,
settings->bools.show_hidden_files);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
#endif
break;
case DISPLAYLIST_LAKKA:
menu_entries_clear(info->list);
#ifdef HAVE_NETWORKING
count = (unsigned)print_buf_lines(info->list, "", menu->core_buf,
menu->core_len, FILE_TYPE_DOWNLOAD_LAKKA,
true);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_CLEAR;
#endif
break;
case DISPLAYLIST_PLAYLIST_COLLECTION:
/* Note: This would appear to be legacy code. Cannot find
* a single instance where this case is met... */
menu_entries_clear(info->list);
if ( string_starts_with_size(info->path, "content_", STRLEN_CONST("content_"))
&& string_ends_with_size (info->path, ".lpl", strlen(info->path), STRLEN_CONST(".lpl")))
{
if (!strcmp(info->path, FILE_PATH_CONTENT_HISTORY))
{
if (menu_displaylist_ctl(DISPLAYLIST_HISTORY, info, settings))
return menu_displaylist_process(info);
return false;
}
if (!strcmp(info->path, FILE_PATH_CONTENT_FAVORITES))
{
if (menu_displaylist_ctl(DISPLAYLIST_FAVORITES, info, settings))
return menu_displaylist_process(info);
return false;
}
}
{
size_t _len;
char path_playlist[PATH_MAX_LENGTH];
playlist_t *playlist = NULL;
const char *dir_playlist = settings->paths.directory_playlist;
fill_pathname_join_special(path_playlist, dir_playlist, info->path,
sizeof(path_playlist));
menu_displaylist_set_new_playlist(menu, settings, path_playlist,
true);
_len = strlcpy(path_playlist,
MENU_ENUM_LABEL_COLLECTION_STR,
sizeof(path_playlist));
playlist = playlist_get_cached();
if (playlist)
{
if (menu_displaylist_parse_playlist(info->list, info->path,
playlist, settings, path_playlist, _len, true) == 0)
info->flags |= MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
ret = 0;
}
if (ret == 0)
{
/* Playlists themselves are sorted
* > Display lists generated from playlists
* must never be sorted */
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
}
}
break;
case DISPLAYLIST_HISTORY:
{
bool history_list_enable = settings->bools.history_list_enable;
const char *path_content_history = settings->paths.path_content_history;
menu_entries_clear(info->list);
if (history_list_enable)
count = menu_displaylist_parse_playlist_generic(
menu, info, settings, "history", STRLEN_CONST("history"),
path_content_history,
false, /* Not a collection */
false, /* Do not sort */
&ret);
if (count == 0)
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_HISTORY_AVAILABLE),
MENU_ENUM_LABEL_NO_HISTORY_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_HISTORY_AVAILABLE,
MENU_INFO_MESSAGE, 0, 0, NULL))
count++;
info->flags &= ~MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
}
}
ret = 0;
/* Playlists themselves are sorted
* > Display lists generated from playlists
* must never be sorted */
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
if (history_needs_navigation_clear(menu, g_defaults.content_history))
info->flags |= MD_FLAG_NEED_NAVIGATION_CLEAR;
break;
case DISPLAYLIST_FAVORITES:
{
const char *path_content_favorites = settings->paths.path_content_favorites;
menu_entries_clear(info->list);
count = menu_displaylist_parse_playlist_generic(menu, info,
settings, "favorites",
STRLEN_CONST("favorites"),
path_content_favorites,
false, /* Not a conventional collection */
true, /* Enable sorting (if allowed by user config) */
&ret);
if (count == 0)
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_FAVORITES_AVAILABLE),
MENU_ENUM_LABEL_NO_FAVORITES_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_FAVORITES_AVAILABLE,
MENU_INFO_MESSAGE, 0, 0, NULL))
count++;
info->flags &= ~MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
}
ret = 0;
/* Playlists themselves are sorted
* > Display lists generated from playlists
* must never be sorted */
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_MUSIC_HISTORY:
menu_entries_clear(info->list);
{
const char *
path_content_music_history = settings->paths.path_content_music_history;
if (settings->bools.history_list_enable)
count = menu_displaylist_parse_playlist_generic(menu, info,
settings,
"music_history",
STRLEN_CONST("music_history"),
path_content_music_history,
false, /* Not a collection */
false, /* Do not sort */
&ret);
if (count == 0)
{
if (menu_entries_append(info->list,
msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_NO_MUSIC_AVAILABLE),
MENU_ENUM_LABEL_NO_MUSIC_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_MUSIC_AVAILABLE,
MENU_INFO_MESSAGE, 0, 0, NULL))
count++;
info->flags &= ~MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
ret = 0;
}
}
if (ret == 0)
{
/* Playlists themselves are sorted
* > Display lists generated from playlists
* must never be sorted */
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
if (history_needs_navigation_clear(menu, g_defaults.music_history))
info->flags |= MD_FLAG_NEED_NAVIGATION_CLEAR;
}
break;
case DISPLAYLIST_VIDEO_HISTORY:
menu_entries_clear(info->list);
#if defined(HAVE_FFMPEG) || defined(HAVE_MPV) || defined(HAVE_WEBMPLAYER)
{
bool history_list_enable = settings->bools.history_list_enable;
const char *
path_content_video_history = settings->paths.path_content_video_history;
if (history_list_enable)
count = menu_displaylist_parse_playlist_generic(menu, info,
settings,
"video_history",
STRLEN_CONST("video_history"),
path_content_video_history,
false, /* Not a collection */
false, /* Do not sort */
&ret);
else
ret = 0;
}
#endif
if (count == 0)
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_VIDEOS_AVAILABLE),
MENU_ENUM_LABEL_NO_VIDEOS_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_VIDEOS_AVAILABLE,
MENU_INFO_MESSAGE, 0, 0, NULL))
count++;
info->flags &= ~MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
ret = 0;
}
if (ret == 0)
{
/* Playlists themselves are sorted
* > Display lists generated from playlists
* must never be sorted */
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
#if (defined(HAVE_FFMPEG) || defined(HAVE_MPV) || defined(HAVE_WEBMPLAYER))
if (history_needs_navigation_clear(menu, g_defaults.video_history))
info->flags |= MD_FLAG_NEED_NAVIGATION_CLEAR;
#endif
}
break;
case DISPLAYLIST_ACHIEVEMENT_SUBMENU_LIST:
#ifdef HAVE_CHEEVOS
menu_entries_clear(info->list);
rcheevos_menu_populate_submenu(info);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
#endif
break;
case DISPLAYLIST_ACHIEVEMENT_LIST:
#ifdef HAVE_CHEEVOS
menu_entries_clear(info->list);
rcheevos_menu_populate(info,
settings->bools.cheevos_enable,
settings->bools.cheevos_hardcore_mode_enable);
#endif
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_CORES_SUPPORTED:
menu_entries_clear(info->list);
{
const char *core_path_current = path_get(RARCH_PATH_CORE);
#if defined(HAVE_DYNAMIC)
bool enable_load_with_current = (core_path_current && *core_path_current);
#else
bool enable_load_with_current = (core_path_current && *core_path_current)
&& !settings->bools.always_reload_core_on_run_content;
#endif
count = menu_displaylist_parse_supported_cores(info,
enable_load_with_current, core_path_current,
menu->deferred_path,
MENU_ENUM_LABEL_DETECT_CORE_LIST_OK,
MENU_ENUM_LABEL_DETECT_CORE_LIST_OK_CURRENT_CORE);
}
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_CORES_COLLECTION_SUPPORTED:
menu_entries_clear(info->list);
{
const char *core_path_current = path_get(RARCH_PATH_CORE);
#if defined(HAVE_DYNAMIC)
bool enable_load_with_current = (core_path_current && *core_path_current);
#else
bool enable_load_with_current = (core_path_current && *core_path_current)
&& !settings->bools.always_reload_core_on_run_content;
#endif
count = menu_displaylist_parse_supported_cores(info,
enable_load_with_current, core_path_current,
menu->deferred_path,
MENU_ENUM_LABEL_FILE_BROWSER_CORE_SELECT_FROM_COLLECTION,
MENU_ENUM_LABEL_FILE_BROWSER_CORE_SELECT_FROM_COLLECTION_CURRENT_CORE);
}
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
/* Pre-select current associated core */
if (menu)
{
size_t idx = menu->rpl_entry_selection_ptr;
playlist_t *cached_playlist = playlist_get_cached();
const struct playlist_entry *entry = NULL;
const core_info_t* core_info = NULL;
if (cached_playlist)
playlist_get_index(cached_playlist, idx, &entry);
if (!entry)
break;
core_info = playlist_entry_get_core_info(entry);
if ( core_info
&& (core_info->display_name && *core_info->display_name))
{
size_t selection_idx = 0;
if (menu_entries_list_search(core_info->display_name, &selection_idx))
{
menu_st->selection_ptr = selection_idx;
if (menu_st->driver_ctx->navigation_set)
menu_st->driver_ctx->navigation_set(menu_st->userdata, false);
}
}
}
break;
case DISPLAYLIST_CORE_INFO:
{
/* The number of items in the core info menu:
* - *May* (possibly) change after performing a
* core restore operation (i.e. the core info
* files are reloaded, and if an unknown error
* occurs then info entries may not be available
* upon popping the stack)
* - *Will* change when toggling the core lock
* status
* To prevent the menu selection from going out
* of bounds, we therefore have to check that the
* current selection index is less than the current
* number of menu entries - if not, we reset the
* navigation pointer */
size_t selection = menu_st->selection_ptr;
menu_entries_clear(info->list);
count = menu_displaylist_parse_core_info(info->list, info->type,
info->path, settings);
if (selection >= count)
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_NAVIGATION_CLEAR;
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_CORE_RESTORE_BACKUP_LIST:
menu_entries_clear(info->list);
count = menu_displaylist_parse_core_backup_list(
info->list, info->path,
settings->paths.directory_core_assets,
(enum core_backup_date_separator_type)
settings->uints.menu_timedate_date_separator,
true);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_CORE_DELETE_BACKUP_LIST:
menu_entries_clear(info->list);
count = menu_displaylist_parse_core_backup_list(
info->list, info->path,
settings->paths.directory_core_assets,
(enum core_backup_date_separator_type)
settings->uints.menu_timedate_date_separator,
false);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_NAVIGATION_CLEAR;
break;
case DISPLAYLIST_CORE_MANAGER_LIST:
{
/* When a core is deleted, the number of items in
* the core manager list will change. We therefore
* have to cache the last set menu size, and reset
* the navigation pointer if the current size is
* different */
static size_t prev_count = 0;
size_t selection = menu_st->selection_ptr;
menu_entries_clear(info->list);
count = menu_displaylist_parse_core_manager_list
(info->list, settings->bools.kiosk_mode_enable);
if (count == 0)
menu_entries_append(info->list,
msg_hash_to_str(
MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY_STR,
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL);
if ( (count != prev_count)
|| (selection >= count))
{
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_NAVIGATION_CLEAR;
prev_count = count;
}
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
#ifdef HAVE_MIST
case DISPLAYLIST_CORE_MANAGER_STEAM_LIST:
menu_entries_clear(info->list);
count = menu_displaylist_parse_core_manager_steam_list(info->list);
info->flags &= ~MD_FLAG_NEED_REFRESH;
info->flags |= MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_NAVIGATION_CLEAR;
/* No core dlcs were found */
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
break;
case DISPLAYLIST_CORE_INFORMATION_STEAM_LIST:
menu_entries_clear(info->list);
info->flags &= ~MD_FLAG_NEED_REFRESH;
info->flags |= MD_FLAG_NEED_PUSH
| MD_FLAG_NEED_NAVIGATION_CLEAR;
count =
menu_displaylist_parse_core_information_steam(info->list, info->path);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
break;
#endif
case DISPLAYLIST_CONTENTLESS_CORES:
{
size_t contentless_core_ptr = menu_st->contentless_core_ptr;
menu_entries_clear(info->list);
count = menu_displaylist_contentless_cores(info->list,
(enum menu_contentless_cores_display_type)
settings->uints.menu_content_show_contentless_cores);
/* TODO/FIXME: Selecting an entry in the
* contentless cores list will cause the
* quick menu to be pushed on the subsequent
* frame via the RARCH_MENU_CTL_SET_PENDING_QUICK_MENU
* command. The way this is implemented 'breaks' the
* menu stack record, so when leaving the quick
* menu via a 'cancel' operation, the last selected
* menu index is lost. We therefore have to apply
* a cached index value after rebuilding the list... */
if (contentless_core_ptr < count)
menu_st->selection_ptr = contentless_core_ptr;
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_SAVESTATE_LIST:
{
bool savestates_enabled = core_info_current_supports_savestate();
menu_entries_clear(info->list);
if ( savestates_enabled
&& settings->bools.quick_menu_show_save_load_state)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_STATE_SLOT, PARSE_ONLY_INT, true) == 0)
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SAVE_STATE),
MENU_ENUM_LABEL_SAVE_STATE_STR,
MENU_ENUM_LABEL_SAVE_STATE,
MENU_SETTING_ACTION_SAVESTATE, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_STATE),
MENU_ENUM_LABEL_LOAD_STATE_STR,
MENU_ENUM_LABEL_LOAD_STATE,
MENU_SETTING_ACTION_LOADSTATE, 0, 0, NULL))
count++;
}
if ( savestates_enabled
&& settings->bools.quick_menu_show_save_load_state
&& settings->bools.quick_menu_show_undo_save_load_state)
{
#ifdef HAVE_CHEEVOS
if (!rcheevos_hardcore_active())
#endif
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNDO_LOAD_STATE),
MENU_ENUM_LABEL_UNDO_LOAD_STATE_STR,
MENU_ENUM_LABEL_UNDO_LOAD_STATE,
MENU_SETTING_ACTION_LOADSTATE, 0, 0, NULL))
count++;
}
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UNDO_SAVE_STATE),
MENU_ENUM_LABEL_UNDO_SAVE_STATE_STR,
MENU_ENUM_LABEL_UNDO_SAVE_STATE,
MENU_SETTING_ACTION_LOADSTATE, 0, 0, NULL))
count++;
}
#ifdef HAVE_BSV_MOVIE
if ( savestates_enabled
&& settings->bools.quick_menu_show_replay)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_REPLAY_SLOT, PARSE_ONLY_INT, true) == 0)
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_RECORD_REPLAY),
MENU_ENUM_LABEL_RECORD_REPLAY_STR,
MENU_ENUM_LABEL_RECORD_REPLAY,
MENU_SETTING_ACTION_RECORDREPLAY, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAY_REPLAY),
MENU_ENUM_LABEL_PLAY_REPLAY_STR,
MENU_ENUM_LABEL_PLAY_REPLAY,
MENU_SETTING_ACTION_PLAYREPLAY, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_HALT_REPLAY),
MENU_ENUM_LABEL_HALT_REPLAY_STR,
MENU_ENUM_LABEL_HALT_REPLAY,
MENU_SETTING_ACTION_HALTREPLAY, 0, 0, NULL))
count++;
}
#endif
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_STATE_SLOT_RUN:
{
bool savestates_enabled = core_info_current_supports_savestate();
playlist_t *playlist = playlist_get_cached();
runloop_state_t *runloop_st = runloop_state_get_ptr();
int state_slot = settings->ints.state_slot;
/* Load the core for getting the final state path for thumbnails */
if (playlist && !(runloop_st->flags & RUNLOOP_FLAG_CORE_RUNNING))
{
struct menu_state *menu_st = menu_state_get_ptr();
const struct playlist_entry *entry = NULL;
if (menu_st && menu_st->driver_data)
playlist_get_index(playlist, menu_st->driver_data->rpl_entry_selection_ptr, &entry);
if (entry && *entry->path)
{
runtime_log_t *runtime_log = NULL;
path_set(RARCH_PATH_CORE, entry->core_path);
command_event(CMD_EVENT_LOAD_CORE, NULL);
runloop_set_current_core_type(CORE_TYPE_PLAIN, true);
/* Reinit runtime log and read current state slot */
savestates_enabled = core_info_current_supports_savestate();
if (savestates_enabled)
{
runtime_update_playlist(playlist,
menu_st->driver_data->rpl_entry_selection_ptr);
runtime_log = runtime_log_init(entry->path,
entry->core_path,
settings->paths.directory_runtime_log,
settings->paths.directory_playlist,
true);
if (runtime_log)
{
if (path_is_valid(runtime_log->path) && runtime_log->state_slot < 1000)
state_slot = runtime_log->state_slot;
free(runtime_log);
}
}
}
}
menu_entries_clear(info->list);
/* Build the dropdown selector */
if ( core_info_current_supports_savestate()
&& settings->bools.quick_menu_show_save_load_state)
{
int i;
int i_max = count = 1000;
for (i = -1; i < i_max; i++)
{
char val[8];
if (i < 0)
strlcpy_lit(val, "Auto", sizeof(val));
else
snprintf(val, sizeof(val), "%u", i);
menu_entries_append(info->list,
val,
MENU_ENUM_LABEL_STATE_SLOT_RUN_STR,
MSG_UNKNOWN,
MENU_SETTING_ACTION_STATE_SLOT_RUN,
0, 0, NULL);
}
/* Pre-select last slot from the runtime log */
menu_st->selection_ptr = state_slot + 1;
}
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_CORE_OPTIONS:
{
/* Number of displayed options is dynamic. If user opens
* 'Quick Menu > Core Options', toggles something
* that changes the number of displayed items, then
* toggles the Quick Menu off and on again (returning
* to the Core Options menu) the menu must be refreshed
* (or undefined behaviour occurs).
* To prevent the menu selection from going out of bounds,
* we therefore have to check that the current selection
* index is less than the current number of menu entries
* - if not, we reset the navigation pointer */
size_t selection = menu_st->selection_ptr;
runloop_state_t *runloop_st = runloop_state_get_ptr();
menu_entries_clear(info->list);
if (runloop_st->core_options)
{
bool game_specific_options = settings->bools.game_specific_options;
const char *category = info->path;
bool is_category = category && *category;
core_option_manager_t *coreopts = NULL;
if (game_specific_options && !is_category)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_OPTION_OVERRIDE_LIST),
MENU_ENUM_LABEL_CORE_OPTION_OVERRIDE_LIST_STR,
MENU_ENUM_LABEL_CORE_OPTION_OVERRIDE_LIST,
MENU_SETTING_ACTION_CORE_OPTION_OVERRIDE_LIST, 0, 0, NULL))
count++;
if (retroarch_ctl(RARCH_CTL_CORE_OPTIONS_LIST_GET, &coreopts))
{
size_t i;
nested_list_t *option_list = NULL;
/* Empty 'category' string signifies top
* level core options menu */
if (!is_category)
option_list = coreopts->option_map;
else
{
nested_list_item_t *category_item = nested_list_get_item(coreopts->option_map,
category, NULL);
if (category_item)
option_list = nested_list_item_get_children(category_item);
}
if (option_list)
{
/* Loop over child options */
for (i = 0; i < nested_list_get_size(option_list); i++)
{
nested_list_item_t *option_item = nested_list_get_item_idx(option_list, i);
const struct core_option *option = (const struct core_option *)
nested_list_item_get_value(option_item);
/* Check whether this is an option or a
* subcategory */
if (option)
{
/* This is a regular option */
size_t opt_idx = option->opt_idx;
if (core_option_manager_get_visible(coreopts, opt_idx))
if (menu_entries_append(info->list,
core_option_manager_get_desc(coreopts, opt_idx, true),
"", MENU_ENUM_LABEL_CORE_OPTION_ENTRY,
(unsigned)(MENU_SETTINGS_CORE_OPTION_START + opt_idx),
0, 0, NULL))
count++;
}
else if (option_item)
{
/* This is a subcategory */
const char *category_id = nested_list_item_get_id(option_item);
bool category_visible = core_option_manager_get_category_visible(
coreopts, category_id);
/* Note: We use nested_list_item_get_id() because we
* guarantee that the list can only be two levels
* deep. If we supported arbitrary nesting, would
* have to use nested_list_item_get_address() here */
if ( category_visible
&& (category_id && *category_id))
{
if (menu_entries_append(info->list,
category_id,
MENU_ENUM_LABEL_CORE_OPTIONS_STR,
MENU_ENUM_LABEL_CORE_OPTIONS,
MENU_SETTING_ACTION_CORE_OPTIONS, 0, 0, NULL))
count++;
}
}
}
}
}
}
if (count == 0)
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE),
MENU_ENUM_LABEL_NO_CORE_OPTIONS_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_CORE_OPTIONS_AVAILABLE,
MENU_SETTINGS_CORE_OPTION_NONE, 0, 0, NULL);
if (selection >= count)
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_NAVIGATION_CLEAR;
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_CORE_OPTION_OVERRIDE_LIST:
{
/* The number of items in the core option override
* list will vary depending upon whether game or
* content directory overrides are currently active.
* To prevent the menu selection from going out
* of bounds, we therefore have to check that the
* current selection index is less than the current
* number of menu entries - if not, we reset the
* navigation pointer */
size_t selection = menu_st->selection_ptr;
menu_entries_clear(info->list);
count = menu_displaylist_parse_core_option_override_list(info->list,
settings->bools.quick_menu_show_core_options_flush);
/* Fallback, in case we open this menu while running
* a core without options */
if (count == 0)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND),
MENU_ENUM_LABEL_NO_SETTINGS_FOUND_STR,
MENU_ENUM_LABEL_NO_SETTINGS_FOUND,
0, 0, 0, NULL))
count++;
if (selection >= count)
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_NAVIGATION_CLEAR;
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_REMAP_FILE_MANAGER:
{
/* The number of items in the remap file manager
* list will vary depending upon which remap type
* is currently active (if any).
* To prevent the menu selection from going out
* of bounds, we therefore have to check that the
* current selection index is less than the current
* number of menu entries - if not, we reset the
* navigation pointer */
size_t selection = menu_st->selection_ptr;
menu_entries_clear(info->list);
count = menu_displaylist_parse_remap_file_manager_list(info->list,
settings->bools.remap_save_on_exit);
/* Fallback */
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
if (selection >= count)
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_NAVIGATION_CLEAR;
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_ARCHIVE_ACTION:
menu_entries_clear(info->list);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE),
MENU_ENUM_LABEL_LOAD_ARCHIVE_STR,
MENU_ENUM_LABEL_LOAD_ARCHIVE,
0, 0, 0, NULL))
count++;
#ifdef HAVE_COMPRESSION
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE),
MENU_ENUM_LABEL_OPEN_ARCHIVE_STR,
MENU_ENUM_LABEL_OPEN_ARCHIVE,
0, 0, 0, NULL))
count++;
#endif
info->flags |= MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_ARCHIVE_ACTION_DETECT_CORE:
menu_entries_clear(info->list);
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE),
MENU_ENUM_LABEL_LOAD_ARCHIVE_DETECT_CORE_STR,
MENU_ENUM_LABEL_LOAD_ARCHIVE_DETECT_CORE,
0, 0, 0, NULL))
count++;
#ifdef HAVE_COMPRESSION
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE),
MENU_ENUM_LABEL_OPEN_ARCHIVE_DETECT_CORE_STR,
MENU_ENUM_LABEL_OPEN_ARCHIVE_DETECT_CORE,
0, 0, 0, NULL))
count++;
#endif
info->flags |= MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_PLAYLIST_MANAGER_LIST:
menu_entries_clear(info->list);
count = menu_displaylist_parse_playlist_manager_list(info->list, settings);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_ADD_TO_PLAYLIST_LIST:
case DISPLAYLIST_ADD_TO_PLAYLIST_QUICKMENU:
{
enum msg_hash_enums lbl = (type == DISPLAYLIST_ADD_TO_PLAYLIST_LIST ?
MENU_ENUM_LABEL_CREATE_NEW_PLAYLIST : MENU_ENUM_LABEL_CREATE_NEW_PLAYLIST_QUICKMENU);
menu_entries_clear(info->list);
/* add new list button here */
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CREATE_NEW_PLAYLIST),
msg_hash_to_str(lbl),
lbl,
MENU_SETTING_ACTION, 0, 0, NULL);
count = menu_displaylist_parse_add_to_playlist_list(info->list,
type,
settings->paths.directory_playlist,
settings->bools.show_hidden_files);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_PLAYLIST_MANAGER_SETTINGS:
menu_entries_clear(info->list);
if (!menu_displaylist_parse_playlist_manager_settings(menu,
settings,
info->list, info->path))
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY_STR,
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL);
info->flags |= MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST_VIDEO_SHADER_PARAMETER:
menu_entries_clear(info->list);
count = menu_displaylist_build_shader_parameter(
info->list, info->type,
MENU_SETTINGS_SHADER_PARAMETER_0,
MENU_SETTING_DROPDOWN_ITEM_VIDEO_SHADER_PARAM);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST_VIDEO_SHADER_PRESET_PARAMETER:
menu_entries_clear(info->list);
count = menu_displaylist_build_shader_parameter(
info->list, info->type,
MENU_SETTINGS_SHADER_PRESET_PARAMETER_0,
MENU_SETTING_DROPDOWN_ITEM_VIDEO_SHADER_PRESET_PARAM);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST_INPUT_RETROPAD_BIND:
menu_entries_clear(info->list);
count = menu_displaylist_parse_input_retropad_bind_list(
info->list, info->path, settings);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST_INPUT_DEVICE_TYPE:
menu_entries_clear(info->list);
count = menu_displaylist_parse_input_device_type_list(info->list, info->path);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST_INPUT_SELECT_RESERVED_DEVICE:
menu_entries_clear(info->list);
count = menu_displaylist_parse_input_select_reserved_device_list(
info->list, info->path, settings);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
#ifdef ANDROID
case DISPLAYLIST_DROPDOWN_LIST_INPUT_SELECT_PHYSICAL_KEYBOARD:
menu_entries_clear(info->list);
count = menu_displaylist_parse_input_select_physical_keyboard_list(
info->list, info->path, settings);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
#endif
case DISPLAYLIST_DROPDOWN_LIST_INPUT_DESCRIPTION:
menu_entries_clear(info->list);
count = menu_displaylist_parse_input_description_list(
info, settings);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST_INPUT_DESCRIPTION_KBD:
menu_entries_clear(info->list);
count = menu_displaylist_parse_input_description_kbd_list(
info->list, info->type, settings);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST_AUDIO_DEVICE:
menu_entries_clear(info->list);
count = menu_displaylist_parse_audio_device_list(info->list, info->path);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST_MIDI_DEVICE:
menu_entries_clear(info->list);
count = menu_displaylist_parse_midi_device_list(info->list, info->path);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
#ifdef HAVE_MICROPHONE
case DISPLAYLIST_DROPDOWN_LIST_MICROPHONE_DEVICE:
menu_entries_clear(info->list);
count = menu_displaylist_parse_microphone_device_list(info->list,
info->path);
count = menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
#endif
#ifdef HAVE_NETWORKING
case DISPLAYLIST_DROPDOWN_LIST_NETPLAY_MITM_SERVER:
menu_entries_clear(info->list);
count = menu_displaylist_parse_netplay_mitm_server_list(
info->list,
settings->arrays.netplay_mitm_server);
count = menu_displaylist_no_entries_fallback(info->list, count, 0);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
#endif
case DISPLAYLIST_SAVING_SETTINGS_LIST:
case DISPLAYLIST_CLOUD_SYNC_SETTINGS_LIST:
case DISPLAYLIST_DRIVER_SETTINGS_LIST:
case DISPLAYLIST_LOGGING_SETTINGS_LIST:
case DISPLAYLIST_FRAME_THROTTLE_SETTINGS_LIST:
case DISPLAYLIST_REWIND_SETTINGS_LIST:
case DISPLAYLIST_DIRECTORY_SETTINGS_LIST:
case DISPLAYLIST_CONFIGURATION_SETTINGS_LIST:
case DISPLAYLIST_CORE_SETTINGS_LIST:
case DISPLAYLIST_SETTINGS_VIEWS_SETTINGS_LIST:
case DISPLAYLIST_QUICK_MENU_VIEWS_SETTINGS_LIST:
case DISPLAYLIST_MENU_SOUNDS_LIST:
case DISPLAYLIST_UPDATER_SETTINGS_LIST:
case DISPLAYLIST_USER_SETTINGS_LIST:
case DISPLAYLIST_ONSCREEN_DISPLAY_SETTINGS_LIST:
case DISPLAYLIST_POWER_MANAGEMENT_SETTINGS_LIST:
case DISPLAYLIST_SETTINGS_ALL:
case DISPLAYLIST_PRIVACY_SETTINGS_LIST:
case DISPLAYLIST_CONFIGURATIONS_LIST:
case DISPLAYLIST_ONSCREEN_NOTIFICATIONS_SETTINGS_LIST:
case DISPLAYLIST_ONSCREEN_NOTIFICATIONS_VIEWS_SETTINGS_LIST:
case DISPLAYLIST_LATENCY_SETTINGS_LIST:
#if defined(HAVE_OVERLAY)
case DISPLAYLIST_ONSCREEN_OVERLAY_SETTINGS_LIST:
case DISPLAYLIST_OSK_OVERLAY_SETTINGS_LIST:
case DISPLAYLIST_OVERLAY_LIGHTGUN_SETTINGS_LIST:
case DISPLAYLIST_OVERLAY_MOUSE_SETTINGS_LIST:
#endif
case DISPLAYLIST_ACCOUNTS_CHEEVOS_LIST:
case DISPLAYLIST_ACCOUNTS_LIST:
case DISPLAYLIST_MENU_FILE_BROWSER_SETTINGS_LIST:
case DISPLAYLIST_MEDIA_PLAYER_SETTINGS_LIST:
case DISPLAYLIST_MENU_VIEWS_SETTINGS_LIST:
case DISPLAYLIST_LAKKA_SERVICES_LIST:
#ifdef HAVE_LAKKA_SWITCH
case DISPLAYLIST_LAKKA_SWITCH_OPTIONS_LIST:
#endif
case DISPLAYLIST_MIDI_SETTINGS_LIST:
case DISPLAYLIST_CRT_SWITCHRES_SETTINGS_LIST:
case DISPLAYLIST_VIDEO_FULLSCREEN_MODE_SETTINGS_LIST:
case DISPLAYLIST_VIDEO_WINDOWED_MODE_SETTINGS_LIST:
case DISPLAYLIST_VIDEO_OUTPUT_SETTINGS_LIST:
case DISPLAYLIST_VIDEO_HDR_SETTINGS_LIST:
case DISPLAYLIST_VIDEO_STEREO_SETTINGS_LIST:
case DISPLAYLIST_VIDEO_SYNCHRONIZATION_SETTINGS_LIST:
case DISPLAYLIST_VIDEO_SCALING_SETTINGS_LIST:
case DISPLAYLIST_OPTIONS_DISK:
case DISPLAYLIST_AI_SERVICE_SETTINGS_LIST:
case DISPLAYLIST_ACCESSIBILITY_SETTINGS_LIST:
case DISPLAYLIST_USER_INTERFACE_SETTINGS_LIST:
case DISPLAYLIST_ACCOUNTS_TWITCH_LIST:
case DISPLAYLIST_RETRO_ACHIEVEMENTS_SETTINGS_LIST:
case DISPLAYLIST_CHEEVOS_APPEARANCE_SETTINGS_LIST:
case DISPLAYLIST_CHEEVOS_VISIBILITY_SETTINGS_LIST:
case DISPLAYLIST_ACCOUNTS_YOUTUBE_LIST:
case DISPLAYLIST_ACCOUNTS_FACEBOOK_LIST:
case DISPLAYLIST_ACCOUNTS_KICK_LIST:
case DISPLAYLIST_RECORDING_SETTINGS_LIST:
case DISPLAYLIST_CHEAT_DETAILS_SETTINGS_LIST:
case DISPLAYLIST_CHEAT_SEARCH_SETTINGS_LIST:
case DISPLAYLIST_NETWORK_SETTINGS_LIST:
case DISPLAYLIST_NETPLAY_LOBBY_FILTERS_LIST:
case DISPLAYLIST_OPTIONS_CHEATS:
case DISPLAYLIST_NETWORK_INFO:
case DISPLAYLIST_DROPDOWN_LIST_RESOLUTION:
case DISPLAYLIST_DROPDOWN_LIST_CRT_SUPER_RESOLUTION:
case DISPLAYLIST_DROPDOWN_LIST_HEADSET_REFRESH_RATE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_DEFAULT_CORE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_LABEL_DISPLAY_MODE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_SORT_MODE:
case DISPLAYLIST_DROPDOWN_LIST_SCAN_METHOD:
case DISPLAYLIST_DROPDOWN_LIST_SCAN_USE_DB:
case DISPLAYLIST_DROPDOWN_LIST_SCAN_DB_SELECT:
case DISPLAYLIST_DROPDOWN_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME:
case DISPLAYLIST_DROPDOWN_LIST_MANUAL_CONTENT_SCAN_CORE_NAME:
case DISPLAYLIST_DROPDOWN_LIST_DISK_INDEX:
case DISPLAYLIST_PERFCOUNTERS_CORE:
case DISPLAYLIST_PERFCOUNTERS_FRONTEND:
case DISPLAYLIST_MENU_SETTINGS_LIST:
#ifdef _3DS
case DISPLAYLIST_MENU_BOTTOM_SETTINGS_LIST:
#endif
case DISPLAYLIST_ADD_CONTENT_LIST:
case DISPLAYLIST_INPUT_SETTINGS_LIST:
case DISPLAYLIST_INPUT_MENU_SETTINGS_LIST:
case DISPLAYLIST_FRAME_TIME_COUNTER_SETTINGS_LIST:
case DISPLAYLIST_BROWSE_URL_LIST:
case DISPLAYLIST_DISC_INFO:
case DISPLAYLIST_DUMP_DISC:
#ifdef HAVE_LAKKA
case DISPLAYLIST_EJECT_DISC:
#endif
case DISPLAYLIST_LOAD_CONTENT_LIST:
case DISPLAYLIST_LOAD_CONTENT_SPECIAL:
case DISPLAYLIST_OPTIONS_REMAPPINGS:
case DISPLAYLIST_VIDEO_SETTINGS_LIST:
case DISPLAYLIST_AUDIO_SETTINGS_LIST:
case DISPLAYLIST_AUDIO_OUTPUT_SETTINGS_LIST:
#ifdef HAVE_MICROPHONE
case DISPLAYLIST_MICROPHONE_SETTINGS_LIST:
#endif
case DISPLAYLIST_AUDIO_SYNCHRONIZATION_SETTINGS_LIST:
case DISPLAYLIST_INFORMATION_LIST:
case DISPLAYLIST_EXPLORE:
case DISPLAYLIST_SCAN_DIRECTORY_LIST:
case DISPLAYLIST_SYSTEM_INFO:
case DISPLAYLIST_DISPLAY_INFO:
case DISPLAYLIST_DISPLAY_EDID_INFO:
case DISPLAYLIST_INPUT_INFO:
case DISPLAYLIST_BLUETOOTH_SETTINGS_LIST:
case DISPLAYLIST_WIFI_SETTINGS_LIST:
case DISPLAYLIST_WIFI_NETWORKS_LIST:
case DISPLAYLIST_AUDIO_MIXER_SETTINGS_LIST:
case DISPLAYLIST_BROWSE_URL_START:
case DISPLAYLIST_CONTENT_SETTINGS:
case DISPLAYLIST_NETPLAY_ROOM_LIST:
case DISPLAYLIST_SHADER_PRESET_MANAGER:
case DISPLAYLIST_INPUT_RETROPAD_BINDS_LIST:
case DISPLAYLIST_INPUT_HOTKEY_BINDS_LIST:
case DISPLAYLIST_INPUT_TURBO_FIRE_SETTINGS_LIST:
case DISPLAYLIST_INPUT_HAPTIC_FEEDBACK_SETTINGS_LIST:
case DISPLAYLIST_INPUT_SENSOR_SETTINGS_LIST:
case DISPLAYLIST_NETPLAY_REQUEST_DEVICES_LIST:
case DISPLAYLIST_NETWORK_REMOTE_USERS_LIST:
case DISPLAYLIST_PLAYLIST_SETTINGS_LIST:
case DISPLAYLIST_SUBSYSTEM_SETTINGS_LIST:
#ifdef HAVE_MIST
case DISPLAYLIST_STEAM_SETTINGS_LIST:
#endif
#ifdef HAVE_GAME_AI
case DISPLAYLIST_OPTIONS_GAME_AI:
#endif
#ifdef HAVE_SMBCLIENT
case DISPLAYLIST_SMB_CLIENT_SETTINGS_LIST:
case DISPLAYLIST_OPTIONS_SMB_CLIENT:
#endif
#ifdef HAVE_NFSCLIENT
case DISPLAYLIST_NFS_CLIENT_SETTINGS_LIST:
case DISPLAYLIST_OPTIONS_NFS_CLIENT:
#endif
case DISPLAYLIST_OPTIONS_OVERRIDES:
menu_entries_clear(info->list);
count = menu_displaylist_build_list(info->list,
settings, type, false);
if (count == 0)
{
switch (type)
{
case DISPLAYLIST_DISC_INFO:
case DISPLAYLIST_DUMP_DISC:
#ifdef HAVE_LAKKA
case DISPLAYLIST_EJECT_DISC:
#endif
case DISPLAYLIST_MENU_SETTINGS_LIST:
#ifdef _3DS
case DISPLAYLIST_MENU_BOTTOM_SETTINGS_LIST:
#endif
case DISPLAYLIST_ADD_CONTENT_LIST:
case DISPLAYLIST_DROPDOWN_LIST_RESOLUTION:
case DISPLAYLIST_DROPDOWN_LIST_CRT_SUPER_RESOLUTION:
case DISPLAYLIST_DROPDOWN_LIST_HEADSET_REFRESH_RATE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_DEFAULT_CORE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_LABEL_DISPLAY_MODE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_RIGHT_THUMBNAIL_MODE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_LEFT_THUMBNAIL_MODE:
case DISPLAYLIST_DROPDOWN_LIST_PLAYLIST_SORT_MODE:
case DISPLAYLIST_DROPDOWN_LIST_SCAN_METHOD:
case DISPLAYLIST_DROPDOWN_LIST_SCAN_USE_DB:
case DISPLAYLIST_DROPDOWN_LIST_SCAN_DB_SELECT:
case DISPLAYLIST_DROPDOWN_LIST_MANUAL_CONTENT_SCAN_SYSTEM_NAME:
case DISPLAYLIST_DROPDOWN_LIST_MANUAL_CONTENT_SCAN_CORE_NAME:
case DISPLAYLIST_DROPDOWN_LIST_DISK_INDEX:
case DISPLAYLIST_INFORMATION_LIST:
case DISPLAYLIST_SCAN_DIRECTORY_LIST:
case DISPLAYLIST_INPUT_INFO:
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ENTRIES_TO_DISPLAY),
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY_STR,
MENU_ENUM_LABEL_NO_ENTRIES_TO_DISPLAY,
FILE_TYPE_NONE, 0, 0, NULL);
break;
case DISPLAYLIST_PERFCOUNTERS_CORE:
case DISPLAYLIST_PERFCOUNTERS_FRONTEND:
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS),
MENU_ENUM_LABEL_NO_PERFORMANCE_COUNTERS_STR,
MENU_ENUM_LABEL_NO_PERFORMANCE_COUNTERS,
0, 0, 0, NULL);
break;
case DISPLAYLIST_BLUETOOTH_SETTINGS_LIST:
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_BT_DEVICES_FOUND),
MENU_ENUM_LABEL_NO_BT_DEVICES_FOUND_STR,
MENU_ENUM_LABEL_NO_BT_DEVICES_FOUND,
0, 0, 0, NULL);
break;
case DISPLAYLIST_WIFI_NETWORKS_LIST:
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_NETWORKS_FOUND),
MENU_ENUM_LABEL_NO_NETWORKS_FOUND_STR,
MENU_ENUM_LABEL_NO_NETWORKS_FOUND,
0, 0, 0, NULL);
break;
case DISPLAYLIST_NETPLAY_ROOM_LIST:
break;
default:
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND),
MENU_ENUM_LABEL_NO_SETTINGS_FOUND_STR,
MENU_ENUM_LABEL_NO_SETTINGS_FOUND,
0, 0, 0, NULL);
break;
}
}
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
/* Special pass */
switch (type)
{
case DISPLAYLIST_DISC_INFO:
case DISPLAYLIST_DUMP_DISC:
#ifdef HAVE_LAKKA
case DISPLAYLIST_EJECT_DISC:
#endif
info->flags |= MD_FLAG_NEED_CLEAR;
break;
default:
break;
}
break;
case DISPLAYLIST_HORIZONTAL:
menu_entries_clear(info->list);
ret = menu_displaylist_parse_horizontal_list(menu,
menu_st, settings, info);
/* Playlists themselves are sorted
* > Display lists generated from playlists
* must never be sorted */
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_HORIZONTAL_CONTENT_ACTIONS:
menu_entries_clear(info->list);
ret = menu_displaylist_parse_horizontal_content_actions(menu,
settings, info->list);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_OPTIONS:
menu_entries_clear(info->list);
{
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
gfx_ctx_flags_t flags;
flags.flags = 0;
video_context_driver_get_flags(&flags);
#endif
#ifdef HAVE_LAKKA
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_LAKKA),
MENU_ENUM_LABEL_UPDATE_LAKKA_STR,
MENU_ENUM_LABEL_UPDATE_LAKKA,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT),
MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS_STR,
MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PL_THUMBNAILS_UPDATER_LIST),
MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST_STR,
MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#elif defined(HAVE_NETWORKING)
#ifdef HAVE_UPDATE_CORES
if (settings->bools.menu_show_core_updater)
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST),
MENU_ENUM_LABEL_CORE_UPDATER_LIST_STR,
MENU_ENUM_LABEL_CORE_UPDATER_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
/* Only show 'update installed cores' if
* one or more cores are installed */
if (core_info_count() > 0)
{
#if defined(ANDROID)
/* When using Play Store builds, cores are
* updated automatically - the 'update
* installed cores' option is therefore
* irrelevant/useless, so we instead present
* an option for switching any existing buildbot
* or sideloaded cores to the latest Play Store
* version */
if (play_feature_delivery_enabled())
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_SWITCH_INSTALLED_CORES_PFD),
MENU_ENUM_LABEL_SWITCH_INSTALLED_CORES_PFD_STR,
MENU_ENUM_LABEL_SWITCH_INSTALLED_CORES_PFD,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
else
#endif
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_INSTALLED_CORES),
MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES_STR,
MENU_ENUM_LABEL_UPDATE_INSTALLED_CORES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
#endif /* HAVE_UPDATE_CORES */
#if defined(HAVE_COMPRESSION) && !defined(HAVE_MIST)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_SYSTEM_FILES),
MENU_ENUM_LABEL_DOWNLOAD_CORE_SYSTEM_FILES_STR,
MENU_ENUM_LABEL_DOWNLOAD_CORE_SYSTEM_FILES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT),
MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS_STR,
MENU_ENUM_LABEL_DOWNLOAD_CORE_CONTENT_DIRS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#ifdef HAVE_ONLINE_UPDATER
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_UPDATER_SETTINGS,
PARSE_ACTION, false) == 0)
count++;
#endif
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PL_THUMBNAILS_UPDATER_LIST),
MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST_STR,
MENU_ENUM_LABEL_PL_THUMBNAILS_UPDATER_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#ifdef HAVE_NETWORKING
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_NETWORK_ON_DEMAND_THUMBNAILS,
PARSE_ONLY_BOOL, false) != -1)
count++;
#endif
#ifdef HAVE_COMPRESSION
#ifdef HAVE_UPDATE_CORE_INFO
if (settings->bools.menu_show_core_updater)
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES),
MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES_STR,
MENU_ENUM_LABEL_UPDATE_CORE_INFO_FILES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#endif
#ifdef HAVE_UPDATE_ASSETS
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS),
MENU_ENUM_LABEL_UPDATE_ASSETS_STR,
MENU_ENUM_LABEL_UPDATE_ASSETS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
#if !defined(_3DS)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES),
MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES_STR,
MENU_ENUM_LABEL_UPDATE_AUTOCONFIG_PROFILES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS),
MENU_ENUM_LABEL_UPDATE_CHEATS_STR,
MENU_ENUM_LABEL_UPDATE_CHEATS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
#ifdef HAVE_LIBRETRODB
#if !defined(VITA)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES),
MENU_ENUM_LABEL_UPDATE_DATABASES_STR,
MENU_ENUM_LABEL_UPDATE_DATABASES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#endif
#endif /* HAVE_LIBRETRODB */
#if !defined(_3DS)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS),
MENU_ENUM_LABEL_UPDATE_OVERLAYS_STR,
MENU_ENUM_LABEL_UPDATE_OVERLAYS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG))
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS),
MENU_ENUM_LABEL_UPDATE_CG_SHADERS_STR,
MENU_ENUM_LABEL_UPDATE_CG_SHADERS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL))
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS),
MENU_ENUM_LABEL_UPDATE_GLSL_SHADERS_STR,
MENU_ENUM_LABEL_UPDATE_GLSL_SHADERS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG))
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_UPDATE_SLANG_SHADERS),
MENU_ENUM_LABEL_UPDATE_SLANG_SHADERS_STR,
MENU_ENUM_LABEL_UPDATE_SLANG_SHADERS,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
#endif
#endif /* !defined(_3DS) */
#endif /* HAVE_COMPRESSION */
#endif
}
if (count == 0)
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ITEMS),
MENU_ENUM_LABEL_NO_ITEMS_STR,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_NO_ITEM, 0, 0, NULL);
ret = 0;
info->flags |= MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_SHADER_PARAMETERS:
case DISPLAYLIST_SHADER_PARAMETERS_PRESET:
menu_entries_clear(info->list);
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
video_shader_ctx_t shader_info;
if (video_shader_driver_get_current_shader(&shader_info))
{
unsigned i;
struct video_shader *shader = shader_info.data;
size_t list_size = shader ? shader->num_parameters : 0;
unsigned base_parameter = (type == DISPLAYLIST_SHADER_PARAMETERS)
? MENU_SETTINGS_SHADER_PARAMETER_0
: MENU_SETTINGS_SHADER_PRESET_PARAMETER_0;
for (i = 0; i < list_size; i++)
if (menu_entries_append(info->list, shader->parameters[i].desc,
info->label, MENU_ENUM_LABEL_SHADER_PARAMETERS_ENTRY,
base_parameter + i, 0, 0, NULL))
count++;
}
}
#endif
if (count == 0)
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS),
MENU_ENUM_LABEL_NO_SHADER_PARAMETERS_STR,
MENU_ENUM_LABEL_NO_SHADER_PARAMETERS,
0, 0, 0, NULL);
ret = 0;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_MAIN_MENU:
menu_entries_clear(info->list);
{
rarch_system_info_t *sys_info = &runloop_state_get_ptr()->system;
const char *menu_ident = menu_driver_ident();
uint32_t flags = runloop_get_flags();
bool show_playlists = settings->bools.menu_content_show_playlists;
bool show_add_content = (settings->uints.menu_content_show_add_entry ==
MENU_ADD_CONTENT_ENTRY_DISPLAY_MAIN_TAB)
&& !settings->bools.kiosk_mode_enable;
bool show_settings = settings->bools.menu_content_show_settings
&& !settings->bools.kiosk_mode_enable
&& menu_history_in_main_menu(menu_ident, settings);
if ( !strcmp(menu_ident, "glui")
&& settings->bools.menu_materialui_show_nav_bar
&& settings->bools.menu_content_show_playlist_tabs)
show_playlists = false;
if (flags & RUNLOOP_FLAG_CORE_RUNNING)
{
if (!retroarch_ctl(RARCH_CTL_IS_DUMMY_CORE, NULL))
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_CONTENT_SETTINGS,
PARSE_ACTION, false) == 0)
count++;
}
else
{
if (sys_info && sys_info->load_no_content)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_START_CORE, PARSE_ACTION, false) == 0)
count++;
#ifndef HAVE_DYNAMIC
if (frontend_driver_has_fork())
#endif
{
if (settings->bools.menu_show_load_core)
{
#ifdef HAVE_DYNAMIC
if ( sys_info->info.library_name
&& *sys_info->info.library_name)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_CORE_LIST_UNLOAD, PARSE_ACTION, false) == 0)
count++;
}
else
#endif
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_CORE_LIST, PARSE_ACTION, false) == 0)
count++;
}
}
}
}
if (settings->bools.menu_show_load_content)
{
/* Core not loaded completely, use the data we
* peeked on load core */
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_LOAD_CONTENT_LIST,
PARSE_ACTION, false) == 0)
count++;
if (menu_displaylist_has_subsystems())
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_SUBSYSTEM_SETTINGS,
PARSE_ACTION, false) == 0)
count++;
}
}
/* Show History and Favorites in menus without sidebar/tabs */
if (menu_history_in_main_menu(menu_ident, settings))
{
if (settings->bools.menu_content_show_favorites_first)
{
if (settings->bools.menu_content_show_favorites)
if (menu_entries_append(info->list,
playlist_get_conf_path(g_defaults.content_favorites),
MENU_ENUM_LABEL_GOTO_FAVORITES_STR,
MENU_ENUM_LABEL_GOTO_FAVORITES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (settings->bools.menu_content_show_history && g_defaults.content_history)
if (menu_entries_append(info->list,
playlist_get_conf_path(g_defaults.content_history),
MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY_STR,
MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
else
{
if (settings->bools.menu_content_show_history && g_defaults.content_history)
if (menu_entries_append(info->list,
playlist_get_conf_path(g_defaults.content_history),
MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY_STR,
MENU_ENUM_LABEL_LOAD_CONTENT_HISTORY,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (settings->bools.menu_content_show_favorites)
if (menu_entries_append(info->list,
playlist_get_conf_path(g_defaults.content_favorites),
MENU_ENUM_LABEL_GOTO_FAVORITES_STR,
MENU_ENUM_LABEL_GOTO_FAVORITES,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
}
}
#ifdef HAVE_CDROM
if (settings->bools.menu_show_load_disc)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_LOAD_DISC,
PARSE_ACTION, false) == 0)
count++;
}
if (settings->bools.menu_show_dump_disc)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_DUMP_DISC,
PARSE_ACTION, false) == 0)
count++;
}
#ifdef HAVE_LAKKA
if (settings->bools.menu_show_eject_disc)
{
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_EJECT_DISC,
PARSE_ACTION, false) == 0)
count++;
}
#endif /* HAVE_LAKKA */
#endif /* HAVE_CDROM */
#if defined(HAVE_CLOUDSYNC)
if (settings->bools.cloud_sync_enable)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info->list,
MENU_ENUM_LABEL_CLOUD_SYNC_SYNC_NOW,
PARSE_ACTION, false) == 0)
count++;
#endif
if (show_playlists)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_PLAYLISTS_TAB),
MENU_ENUM_LABEL_PLAYLISTS_TAB_STR,
MENU_ENUM_LABEL_PLAYLISTS_TAB,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
if (show_add_content)
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST),
MENU_ENUM_LABEL_ADD_CONTENT_LIST_STR,
MENU_ENUM_LABEL_ADD_CONTENT_LIST,
MENU_SETTING_ACTION, 0, 0, NULL))
count++;
#ifdef HAVE_NETWORKING
if (settings->uints.menu_content_show_netplay
== MENU_ADD_CONTENT_ENTRY_DISPLAY_MAIN_TAB)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_NETPLAY,
PARSE_ACTION, false) == 0)
count++;
#ifdef HAVE_ONLINE_UPDATER
if ( settings->bools.menu_show_online_updater
&& !settings->bools.kiosk_mode_enable)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_ONLINE_UPDATER,
PARSE_ACTION, false) == 0)
count++;
#endif /* HAVE_ONLINE_UPDATER */
#endif /* HAVE_NETWORKING */
#ifdef HAVE_MIST
if ( settings->bools.menu_show_core_manager_steam
&& !settings->bools.kiosk_mode_enable)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_CORE_MANAGER_STEAM_LIST,
PARSE_ACTION, false) == 0)
count++;
#endif
if (show_settings)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_SETTINGS, PARSE_ACTION, false) == 0)
count++;
/* Move password-hidden enablers under Information if visible */
if (!settings->bools.menu_show_information)
{
if ( !settings->bools.menu_content_show_settings
&& !settings->bools.kiosk_mode_enable
&& !( !strcmp(menu_ident, "glui")
&& settings->bools.menu_materialui_show_nav_bar)
&& settings->paths.menu_content_show_settings_password[0] != '\0')
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info->list,
MENU_ENUM_LABEL_XMB_MAIN_MENU_ENABLE_SETTINGS,
PARSE_ACTION,
false) == 0)
count++;
if ( settings->bools.kiosk_mode_enable
&& *settings->paths.kiosk_mode_password)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info->list,
MENU_ENUM_LABEL_MENU_DISABLE_KIOSK_MODE,
PARSE_ACTION,
false) == 0)
count++;
}
if (settings->bools.menu_show_information)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_INFORMATION_LIST,
PARSE_ACTION, false) == 0)
count++;
#ifdef HAVE_CONFIGFILE
if ( settings->bools.menu_show_configurations
&& !settings->bools.kiosk_mode_enable)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_CONFIGURATIONS_LIST,
PARSE_ACTION, false) == 0)
count++;
#endif
#ifdef HAVE_COMPANION_WIMP
if (settings->bools.desktop_menu_enable)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info->list,
MENU_ENUM_LABEL_SHOW_WIMP,
PARSE_ACTION,
false) == 0)
count++;
#endif
#if defined(HAVE_LIBNX)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info->list,
MENU_ENUM_LABEL_SWITCH_CPU_PROFILE,
PARSE_ACTION, false) == 0)
count++;
#endif
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info->list,
MENU_ENUM_LABEL_SWITCH_GPU_PROFILE,
PARSE_ACTION, false) == 0)
count++;
#if !TARGET_OS_IPHONE
if (settings->bools.menu_show_restart_retroarch)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info->list,
MENU_ENUM_LABEL_RESTART_RETROARCH,
PARSE_ACTION, false) == 0)
count++;
if (settings->bools.menu_show_quit_retroarch)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(
info->list,
MENU_ENUM_LABEL_QUIT_RETROARCH,
PARSE_ACTION, false) == 0)
count++;
#endif
#if defined(HAVE_LAKKA)
if (settings->bools.menu_show_reboot)
{
/* What the Reboot entry's value shows. */
lakka_update_check();
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_REBOOT,
PARSE_ACTION, false) == 0)
count++;
}
if (settings->bools.menu_show_shutdown)
if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(info->list,
MENU_ENUM_LABEL_SHUTDOWN,
PARSE_ACTION, false) == 0)
count++;
#endif
if (!count)
{
menu_entries_clear(info->list);
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ITEMS),
MENU_ENUM_LABEL_NO_ITEMS_STR,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_NO_ITEM, 0, 0, NULL);
info->flags |= MD_FLAG_NEED_REFRESH;
}
info->flags |= MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_HELP:
if (menu_entries_append(info->list, info->path,
info->label, MSG_UNKNOWN, info->type, info->directory_ptr, 0,
NULL))
count++;
p_dialog->pending_push = false;
break;
case DISPLAYLIST_INFO:
if (menu_entries_append(info->list, info->path,
info->label, MSG_UNKNOWN, info->type, info->directory_ptr, 0,
NULL))
count++;
break;
case DISPLAYLIST_FILE_BROWSER_SCAN_DIR:
case DISPLAYLIST_FILE_BROWSER_SELECT_DIR:
case DISPLAYLIST_FILE_BROWSER_SELECT_FILE:
case DISPLAYLIST_FILE_BROWSER_SELECT_CORE:
case DISPLAYLIST_FILE_BROWSER_SELECT_COLLECTION:
case DISPLAYLIST_GENERIC:
info->flags |= MD_FLAG_NEED_NAVIGATION_CLEAR;
/* fall-through */
case DISPLAYLIST_PENDING_CLEAR:
if (menu_st->driver_ctx && menu_st->driver_ctx->list_cache)
menu_st->driver_ctx->list_cache(menu_st->userdata,
MENU_LIST_PLAIN, MENU_ACTION_NOOP);
if (menu_entries_append(info->list, info->path,
info->label, MSG_UNKNOWN, info->type, info->directory_ptr, 0,
NULL))
count++;
info->flags |= MD_FLAG_NEED_ENTRIES_REFRESH;
break;
case DISPLAYLIST_USER_BINDS_LIST:
menu_entries_clear(info->list);
{
unsigned val = atoi(info->path);
const char *temp_val = msg_hash_to_str(
(enum msg_hash_enums)(MENU_ENUM_LABEL_INPUT_USER_1_BINDS + (val-1)));
ret = MENU_DISPLAYLIST_PARSE_SETTINGS(info->list,
temp_val, PARSE_NONE, true, MENU_SETTINGS_INPUT_BEGIN);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_DATABASES:
menu_entries_clear(info->list);
filebrowser_clear_type();
if (info->exts && *info->exts)
free(info->exts);
if (info->path)
free(info->path);
info->type_default = FILE_TYPE_RDB;
info->exts = strldup(".rdb", sizeof(".rdb"));
info->enum_idx = MENU_ENUM_LABEL_PLAYLISTS_TAB;
info->path = strdup(settings->paths.path_content_database);
load_content = false;
use_filebrowser = true;
break;
case DISPLAYLIST_SHADER_PASS:
case DISPLAYLIST_SHADER_PRESET:
menu_entries_clear(info->list);
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
char new_exts[128];
gfx_ctx_flags_t flags;
size_t _len = 0;
new_exts[0] = '\0';
flags.flags = 0;
filebrowser_clear_type();
video_context_driver_get_flags(&flags);
switch (type)
{
case DISPLAYLIST_SHADER_PRESET:
{
info->type_default = FILE_TYPE_SHADER_PRESET;
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG))
_len += strlcpy_lit(new_exts + _len, "cgp", sizeof(new_exts) - _len);
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL))
{
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
_len += strlcpy_lit(new_exts + _len, "glslp", sizeof(new_exts) - _len);
}
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG))
{
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
strlcpy_lit(new_exts + _len, "slangp", sizeof(new_exts) - _len);
}
}
break;
case DISPLAYLIST_SHADER_PASS:
{
info->type_default = FILE_TYPE_SHADER;
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG))
_len += strlcpy_lit(new_exts + _len, "cg", sizeof(new_exts) - _len);
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL))
{
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
_len += strlcpy_lit(new_exts + _len, "glsl", sizeof(new_exts) - _len);
}
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG))
{
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
strlcpy_lit(new_exts + _len, "slang", sizeof(new_exts) - _len);
}
}
break;
default:
break;
}
if (info->exts && *info->exts)
free(info->exts);
info->exts = strdup(new_exts);
use_filebrowser = true;
}
#endif
break;
case DISPLAYLIST_SHADER_PRESET_PREPEND:
case DISPLAYLIST_SHADER_PRESET_APPEND:
menu_entries_clear(info->list);
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
char new_exts[128];
gfx_ctx_flags_t flags;
size_t _len = 0;
flags.flags = 0;
new_exts[0] = '\0';
filebrowser_clear_type();
video_context_driver_get_flags(&flags);
info->type_default = FILE_TYPE_SHADER_PRESET;
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_CG))
_len += strlcpy_lit(new_exts + _len, "cgp", sizeof(new_exts) - _len);
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_GLSL))
{
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
_len += strlcpy_lit(new_exts + _len, "glslp", sizeof(new_exts) - _len);
}
if (BIT32_GET(flags.flags, GFX_CTX_FLAGS_SHADERS_SLANG))
{
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
strlcpy_lit(new_exts + _len, "slangp", sizeof(new_exts) - _len);
}
if (info->exts && *info->exts)
free(info->exts);
info->exts = strdup(new_exts);
use_filebrowser = true;
}
#endif
break;
case DISPLAYLIST_IMAGES:
menu_entries_clear(info->list);
if ( (filebrowser_get_type() != FILEBROWSER_SELECT_FILE)
&& (filebrowser_get_type() != FILEBROWSER_SELECT_IMAGE))
filebrowser_clear_type();
info->type_default = FILE_TYPE_IMAGE;
{
char new_exts[128];
size_t _len = 0;
new_exts[0] = '\0';
#ifdef HAVE_RBMP
_len += strlcpy_lit(new_exts + _len, "bmp", sizeof(new_exts) - _len);
#endif
#ifdef HAVE_RPNG
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
_len += strlcpy_lit(new_exts + _len, "png", sizeof(new_exts) - _len);
#endif
#ifdef HAVE_RJPEG
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
_len += strlcpy_lit(new_exts + _len, "jpeg", sizeof(new_exts) - _len);
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
_len += strlcpy_lit(new_exts + _len, "jpg", sizeof(new_exts) - _len);
#endif
#ifdef HAVE_RTGA
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
strlcpy_lit(new_exts + _len, "tga", sizeof(new_exts) - _len);
#endif
#ifdef HAVE_RWEBP
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
_len += strlcpy_lit(new_exts + _len, "webp", sizeof(new_exts) - _len);
#endif
#ifdef HAVE_RDDS
if (_len > 0)
_len += strlcpy_lit(new_exts + _len, "|", sizeof(new_exts) - _len);
_len += strlcpy_lit(new_exts + _len, "dds", sizeof(new_exts) - _len);
#endif
if (info->exts && *info->exts)
free(info->exts);
info->exts = strdup(new_exts);
}
use_filebrowser = true;
break;
case DISPLAYLIST_PLAYLIST:
{
const char *_msg = path_basename_nocompression(info->path);
menu_entries_clear(info->list);
count = menu_displaylist_parse_playlist_generic(
menu,
info,
settings,
_msg,
strlen(_msg),
info->path,
true, /* Is a collection */
true, /* Enable sorting (if allowed by user config) */
&ret);
ret = 0; /* Why do we do this...? */
/* Playlists themselves are sorted
* > Display lists generated from playlists
* must never be sorted */
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_IMAGES_HISTORY:
menu_entries_clear(info->list);
#if defined(HAVE_IMAGEVIEWER) || defined(HAVE_MENU)
{
bool history_list_enable = settings->bools.history_list_enable;
const char *path_content_image_history = settings->paths.path_content_image_history;
if (history_list_enable)
count = menu_displaylist_parse_playlist_generic(menu, info,
settings,
"images_history",
STRLEN_CONST("images_history"),
path_content_image_history,
false, /* Not a collection */
false, /* Do not sort */
&ret);
}
#endif
if (count == 0)
{
if (menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_IMAGES_AVAILABLE),
MENU_ENUM_LABEL_NO_IMAGES_AVAILABLE_STR,
MENU_ENUM_LABEL_NO_IMAGES_AVAILABLE,
MENU_INFO_MESSAGE, 0, 0, NULL))
count++;
info->flags &= ~MD_FLAG_NEED_PUSH_NO_PLAYLIST_ENTRIES;
}
ret = 0;
/* Playlists themselves are sorted
* > Display lists generated from playlists
* must never be sorted */
info->flags &= ~MD_FLAG_NEED_SORT;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
#if defined(HAVE_IMAGEVIEWER) || defined(HAVE_MENU)
if (history_needs_navigation_clear(menu, g_defaults.image_history))
info->flags |= MD_FLAG_NEED_NAVIGATION_CLEAR;
#endif
break;
case DISPLAYLIST_VIDEO_FILTERS:
case DISPLAYLIST_CONFIG_FILES:
case DISPLAYLIST_REMAP_FILES:
case DISPLAYLIST_RGUI_THEME_PRESETS:
case DISPLAYLIST_STREAM_CONFIG_FILES:
case DISPLAYLIST_RECORD_CONFIG_FILES:
case DISPLAYLIST_OVERLAYS:
case DISPLAYLIST_OSK_OVERLAYS:
case DISPLAYLIST_FONTS:
case DISPLAYLIST_VIDEO_FONTS:
case DISPLAYLIST_AUDIO_FILTERS:
case DISPLAYLIST_CHEAT_FILES:
case DISPLAYLIST_MANUAL_CONTENT_SCAN_DAT_FILES:
case DISPLAYLIST_FILE_BROWSER_SELECT_SIDELOAD_CORE:
menu_entries_clear(info->list);
filebrowser_clear_type();
if (info->exts && *info->exts)
free(info->exts);
switch (type)
{
case DISPLAYLIST_VIDEO_FILTERS:
info->type_default = FILE_TYPE_VIDEOFILTER;
info->exts = strldup("filt", sizeof("filt"));
break;
case DISPLAYLIST_CONFIG_FILES:
info->type_default = FILE_TYPE_CONFIG;
info->exts = strldup("cfg", sizeof("cfg"));
break;
case DISPLAYLIST_REMAP_FILES:
info->type_default = FILE_TYPE_REMAP;
info->exts = strldup("rmp", sizeof("rmp"));
break;
case DISPLAYLIST_RGUI_THEME_PRESETS:
info->type_default = FILE_TYPE_RGUI_THEME_PRESET;
info->exts = strldup("cfg", sizeof("cfg"));
break;
case DISPLAYLIST_STREAM_CONFIG_FILES:
info->type_default = FILE_TYPE_STREAM_CONFIG;
info->exts = strldup("cfg", sizeof("cfg"));
break;
case DISPLAYLIST_RECORD_CONFIG_FILES:
info->type_default = FILE_TYPE_RECORD_CONFIG;
info->exts = strldup("cfg", sizeof("cfg"));
break;
case DISPLAYLIST_OVERLAYS:
info->type_default = FILE_TYPE_OVERLAY;
info->exts = strldup("cfg", sizeof("cfg"));
filebrowser_set_type(FILEBROWSER_SELECT_OVERLAY);
break;
case DISPLAYLIST_OSK_OVERLAYS:
info->type_default = FILE_TYPE_OSK_OVERLAY;
info->exts = strldup("cfg", sizeof("cfg"));
break;
case DISPLAYLIST_FONTS:
info->type_default = FILE_TYPE_FONT;
info->exts = strldup("ttf", sizeof("ttf"));
break;
case DISPLAYLIST_VIDEO_FONTS:
info->type_default = FILE_TYPE_VIDEO_FONT;
info->exts = strldup("ttf", sizeof("ttf"));
break;
case DISPLAYLIST_AUDIO_FILTERS:
info->type_default = FILE_TYPE_AUDIOFILTER;
info->exts = strldup("dsp", sizeof("dsp"));
break;
case DISPLAYLIST_CHEAT_FILES:
info->type_default = FILE_TYPE_CHEAT;
info->exts = strldup("cht", sizeof("cht"));
break;
case DISPLAYLIST_MANUAL_CONTENT_SCAN_DAT_FILES:
info->type_default = FILE_TYPE_MANUAL_SCAN_DAT;
info->exts = strldup("dat|xml", sizeof("dat|xml"));
break;
case DISPLAYLIST_FILE_BROWSER_SELECT_SIDELOAD_CORE:
{
size_t _len;
char ext_names[32];
info->type_default = FILE_TYPE_SIDELOAD_CORE;
_len = frontend_driver_get_core_extension(ext_names, sizeof(ext_names));
if (_len > 0)
{
_len += strlcpy_lit(ext_names + _len, "|", sizeof(ext_names) - _len);
strlcpy(ext_names + _len, FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT, sizeof(ext_names) - _len);
}
else
strlcpy(ext_names, FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT, sizeof(ext_names));
info->exts = strdup(ext_names);
}
break;
default:
break;
}
load_content = false;
use_filebrowser = true;
break;
case DISPLAYLIST_DATABASE_PLAYLISTS:
case DISPLAYLIST_DATABASE_PLAYLISTS_HORIZONTAL:
{
bool is_horizontal =
(type == DISPLAYLIST_DATABASE_PLAYLISTS_HORIZONTAL);
menu_entries_clear(info->list);
count = menu_displaylist_parse_playlists(info->list,
info->type_default, info->path,
settings, is_horizontal);
if (count == 0 && !is_horizontal)
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_PLAYLISTS),
MENU_ENUM_LABEL_NO_PLAYLISTS_STR,
MENU_ENUM_LABEL_NO_PLAYLISTS,
MENU_SETTING_NO_ITEM, 0, 0, NULL);
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_CORES:
menu_entries_clear(info->list);
{
char ext_name[16];
filebrowser_clear_type();
info->type_default = FILE_TYPE_PLAIN;
if (frontend_driver_get_core_extension(
ext_name, sizeof(ext_name)))
{
if (info->exts && *info->exts)
free(info->exts);
info->exts = strdup(ext_name);
}
}
count = menu_displaylist_parse_cores(menu,
settings->bools.show_hidden_files, info);
if (count == 0)
menu_entries_append(info->list,
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_NO_ITEMS),
MENU_ENUM_LABEL_NO_ITEMS_STR,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_NO_ITEM, 0, 0, NULL);
if (string_is_equal(info->label, MENU_ENUM_LABEL_CORE_LIST_STR))
info->flags |= MD_FLAG_PUSH_BUILTIN_CORES;
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DEFAULT:
menu_entries_clear(info->list);
load_content = false;
use_filebrowser = true;
break;
case DISPLAYLIST_CORES_DETECTED:
menu_entries_clear(info->list);
use_filebrowser = true;
break;
case DISPLAYLIST_MANUAL_CONTENT_SCAN_LIST:
menu_entries_clear(info->list);
count = menu_displaylist_parse_manual_content_scan_list(info->list);
menu_displaylist_no_entries_fallback(info->list, count, FILE_TYPE_NONE);
info->flags |= MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_DROPDOWN_LIST:
menu_entries_clear(info->list);
{
if (string_starts_with_size(info->path, "core_option_",
STRLEN_CONST("core_option_")))
count = menu_displaylist_parse_core_option_dropdown_list(info->list, info->path);
else
{
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info->path);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
if (setting)
{
switch (setting->type)
{
case ST_STRING_OPTIONS:
{
char val_d[16];
char val_s[NAME_MAX_LENGTH];
char orig_val[NAME_MAX_LENGTH];
const char *values = setting->aux.values;
const char *p = values;
unsigned i = 0;
bool checked_found = false;
unsigned checked = 0;
int has_repr = (setting->actions->repr != NULL);
snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx);
if (has_repr)
strlcpy(orig_val, setting->value.target.string, sizeof(orig_val));
while (*p)
{
const char *end = p;
size_t len;
while (*end && *end != '|')
end++;
len = (size_t)(end - p);
if (has_repr)
{
if (len < setting->size)
{
memcpy(setting->value.target.string, p, len);
setting->value.target.string[len] = '\0';
}
else
strlcpy(setting->value.target.string, p, setting->size);
setting->actions->repr(setting,
val_s, sizeof(val_s));
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_SETTING_STRING_OPTIONS_ITEM,
i, 0, NULL))
count++;
}
else
{
if (len < sizeof(val_s))
{
memcpy(val_s, p, len);
val_s[len] = '\0';
}
else
{
memcpy(val_s, p, sizeof(val_s) - 1);
val_s[sizeof(val_s) - 1] = '\0';
}
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_SETTING_STRING_OPTIONS_ITEM,
i, 0, NULL))
count++;
}
if (!checked_found)
{
const char *cur = has_repr ? orig_val : setting->value.target.string;
size_t cur_len = strlen(cur);
if (cur_len == len && memcmp(p, cur, len) == 0)
{
checked = i;
checked_found = true;
}
}
i++;
p = *end ? end + 1 : end;
}
if (has_repr)
strlcpy(setting->value.target.string, orig_val, setting->size);
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)
info->list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
}
break;
case ST_INT:
{
int32_t i;
int32_t i_min;
int32_t i_max;
int32_t i_step;
char val_d[16];
int32_t orig_value = setting_int_get(setting);
unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_INT_ITEM;
float step = setting->step;
float min = (setting->flags & SD_FLAG_ENFORCE_MINRANGE) ? setting->min : 0.00f;
float max = (setting->flags & SD_FLAG_ENFORCE_MAXRANGE) ? setting->max : 99999.00f;
bool checked_found = false;
unsigned checked = 0;
unsigned entry_index = 0;
snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx);
/* Integer settings iterate with an integer counter: a float
* accumulator is exact only while the range and step are
* representable, and would silently drop the final entry or
* emit duplicates once they are not. */
i_min = (int32_t)min;
i_max = (int32_t)max;
i_step = (int32_t)step;
if (i_step < 1)
i_step = 1;
if (setting->actions->repr)
{
for (i = i_min; i <= i_max; i += i_step)
{
char val_s[NAME_MAX_LENGTH];
int val = i;
setting_int_set(setting, val);
setting->actions->repr(setting,
val_s, sizeof(val_s));
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, val, 0, NULL))
count++;
if (!checked_found && val == orig_value)
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
setting_int_set(setting, orig_value);
}
else
{
for (i = i_min; i <= i_max; i += i_step)
{
char val_s[16];
int val = i;
snprintf(val_s, sizeof(val_s), "%d", val);
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, val, 0, NULL))
count++;
if (!checked_found && val == orig_value)
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
}
break;
case ST_FLOAT:
{
float i;
char val_d[16];
float orig_value = *setting->value.target.fraction;
unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_FLOAT_ITEM;
float step = setting->step;
float half_step = step * 0.5f;
float min = (setting->flags & SD_FLAG_ENFORCE_MINRANGE) ? setting->min : 0.00f;
float max = (setting->flags & SD_FLAG_ENFORCE_MAXRANGE) ? setting->max : 9999.00f;
bool checked_found = false;
unsigned checked = 0;
unsigned entry_index = 0;
snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx);
if (setting->actions->repr)
{
for (i = min; i <= max + half_step; i += step)
{
char val_s[NAME_MAX_LENGTH];
*setting->value.target.fraction = i;
setting->actions->repr(setting,
val_s, sizeof(val_s));
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, 0, 0, NULL))
count++;
if (!checked_found && (fabs(i - orig_value) < half_step))
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
*setting->value.target.fraction = orig_value;
}
else
{
for (i = min; i <= max + half_step; i += step)
{
char val_s[16];
snprintf(val_s, sizeof(val_s), "%.2f", i);
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, 0, 0, NULL))
count++;
if (!checked_found && (fabs(i - orig_value) < half_step))
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
}
break;
case ST_UINT:
{
int32_t i;
int32_t i_min;
int32_t i_max;
int32_t i_step;
char val_d[16];
unsigned orig_value = setting_uint_get(setting);
unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_UINT_ITEM;
float step = setting->step;
float min = (setting->flags & SD_FLAG_ENFORCE_MINRANGE) ? setting->min : 0.00f;
float max = (setting->flags & SD_FLAG_ENFORCE_MAXRANGE) ? setting->max : 9999.00f;
bool checked_found = false;
unsigned checked = 0;
unsigned entry_index = 0;
snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx);
/* Integer settings iterate with an integer counter: a float
* accumulator is exact only while the range and step are
* representable, and would silently drop the final entry or
* emit duplicates once they are not. */
i_min = (int32_t)min;
i_max = (int32_t)max;
i_step = (int32_t)step;
if (i_step < 1)
i_step = 1;
if (setting->actions->repr)
{
for (i = i_min; i <= i_max; i += i_step)
{
char val_s[NAME_MAX_LENGTH];
int val = i;
/* Mouse Index: the mice there are,
* and the one chosen now whatever
* it is */
if ( setting->enum_idx >= MENU_ENUM_LABEL_INPUT_MOUSE_INDEX
&& setting->enum_idx <= MENU_ENUM_LABEL_INPUT_MOUSE_INDEX_LAST
&& val != (int)orig_value
&& !input_config_mouse_offered((unsigned)val))
continue;
/* Keyboard Index: "All" and the
* keyboards there are */
if (menu_displaylist_keyboard_index(setting))
{
if ( val > 0 && val != (int)orig_value
&& !input_config_get_keyboard_display_name(val - 1))
continue;
if (val != (int)orig_value)
menu_setting_keyboard_index_name(val,
val_s, sizeof(val_s));
}
setting_uint_set(setting, val);
if ( val == (int)orig_value
|| !menu_displaylist_keyboard_index(setting))
setting->actions->repr(setting,
val_s, sizeof(val_s));
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, val, 0, NULL))
count++;
if (!checked_found && val == (int)orig_value)
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
setting_uint_set(setting, orig_value);
}
else
{
for (i = i_min; i <= i_max; i += i_step)
{
char val_s[16];
int val = i;
snprintf(val_s, sizeof(val_s), "%d", val);
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, val, 0, NULL))
count++;
if (!checked_found && val == (int)orig_value)
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
}
break;
default:
break;
}
}
}
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
}
break;
case DISPLAYLIST_DROPDOWN_LIST_VIDEO_SHADER_NUM_PASSES:
menu_entries_clear(info->list);
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
{
unsigned i;
struct video_shader *shader = menu_shader_get();
unsigned pass_count = shader ? shader->passes : 0;
menu_entries_clear(info->list);
for (i = 0; i < GFX_MAX_SHADERS+1; i++)
{
char val_d[16];
snprintf(val_d, sizeof(val_d), "%d", i);
if (menu_entries_append(info->list,
val_d,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_ITEM_VIDEO_SHADER_NUM_PASS, i, 0, NULL))
count++;
if (i == pass_count)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[i].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = i;
}
}
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
}
#endif
break;
case DISPLAYLIST_DROPDOWN_LIST_SPECIAL:
menu_entries_clear(info->list);
if (string_starts_with_size(info->path, "core_option_",
STRLEN_CONST("core_option_")))
count = menu_displaylist_parse_core_option_dropdown_list(info->list, info->path);
else
{
enum msg_hash_enums enum_idx = (enum msg_hash_enums)atoi(info->path);
rarch_setting_t *setting = menu_setting_find_enum(enum_idx);
if (setting)
{
switch (setting->type)
{
case ST_STRING_OPTIONS:
{
char val_d[16];
const char *p = setting->aux.values;
unsigned i = 0;
int checked_found = 0;
unsigned checked = 0;
size_t tok_len;
snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx);
while (p && *p)
{
const char *delim = strchr(p, '|');
char tmp[256];
if (delim)
tok_len = (size_t)(delim - p);
else
tok_len = strlen(p);
if (tok_len >= sizeof(tmp))
tok_len = sizeof(tmp) - 1;
memcpy(tmp, p, tok_len);
tmp[tok_len] = '\0';
if (menu_entries_append(info->list,
tmp,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
MENU_SETTING_DROPDOWN_SETTING_STRING_OPTIONS_ITEM_SPECIAL, i, 0, NULL))
count++;
if (!checked_found
&& tok_len == strlen(setting->value.target.string)
&& memcmp(tmp, setting->value.target.string, tok_len) == 0)
{
checked = i;
checked_found = 1;
}
i++;
p = delim ? delim + 1 : NULL;
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)
info->list->list[checked].actiondata;
if (cbs)
cbs->checked = 1;
menu_st->selection_ptr = checked;
}
}
break;
case ST_INT:
{
int32_t i;
int32_t i_min;
int32_t i_max;
int32_t i_step;
char val_d[16];
int32_t orig_value = setting_int_get(setting);
unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_INT_ITEM_SPECIAL;
float step = setting->step;
float min = (setting->flags & SD_FLAG_ENFORCE_MINRANGE) ? setting->min : 0.00f;
float max = (setting->flags & SD_FLAG_ENFORCE_MAXRANGE) ? setting->max : 9999.00f;
bool checked_found = false;
unsigned checked = 0;
unsigned entry_index = 0;
snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx);
/* Integer settings iterate with an integer counter: a float
* accumulator is exact only while the range and step are
* representable, and would silently drop the final entry or
* emit duplicates once they are not. */
i_min = (int32_t)min;
i_max = (int32_t)max;
i_step = (int32_t)step;
if (i_step < 1)
i_step = 1;
if (setting->actions->repr)
{
for (i = i_min; i <= i_max; i += i_step)
{
char val_s[NAME_MAX_LENGTH];
int val = i;
setting_int_set(setting, val);
setting->actions->repr(setting,
val_s, sizeof(val_s));
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, val, 0, NULL))
count++;
if (!checked_found && val == orig_value)
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
setting_int_set(setting, orig_value);
}
else
{
for (i = i_min; i <= i_max; i += i_step)
{
char val_s[16];
int val = i;
snprintf(val_s, sizeof(val_s), "%d", val);
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, val, 0, NULL))
count++;
if (!checked_found && val == orig_value)
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
}
break;
case ST_FLOAT:
{
float i;
char val_d[16];
float orig_value = *setting->value.target.fraction;
unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_FLOAT_ITEM_SPECIAL;
float step = setting->step;
float half_step = step * 0.5f;
float min = (setting->flags & SD_FLAG_ENFORCE_MINRANGE) ? setting->min : 0.00f;
float max = (setting->flags & SD_FLAG_ENFORCE_MAXRANGE) ? setting->max : 9999.00f;
bool checked_found = false;
unsigned checked = 0;
unsigned entry_index = 0;
snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx);
if (setting->actions->repr)
{
for (i = min; i <= max + half_step; i += step)
{
char val_s[NAME_MAX_LENGTH];
*setting->value.target.fraction = i;
setting->actions->repr(setting,
val_s, sizeof(val_s));
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, 0, 0, NULL))
count++;
if (!checked_found && (fabs(i - orig_value) < half_step))
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
*setting->value.target.fraction = orig_value;
}
else
{
for (i = min; i <= max + half_step; i += step)
{
char val_s[16];
snprintf(val_s, sizeof(val_s), "%.2f", i);
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, 0, 0, NULL))
count++;
if (!checked_found && (fabs(i - orig_value) < half_step))
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
}
break;
case ST_UINT:
{
int32_t i;
int32_t i_min;
int32_t i_max;
int32_t i_step;
char val_d[16];
unsigned orig_value = setting_uint_get(setting);
unsigned setting_type = MENU_SETTING_DROPDOWN_SETTING_UINT_ITEM_SPECIAL;
float step = setting->step;
float min = (setting->flags & SD_FLAG_ENFORCE_MINRANGE) ? setting->min : 0.00f;
float max = (setting->flags & SD_FLAG_ENFORCE_MAXRANGE) ? setting->max : 9999.00f;
bool checked_found = false;
unsigned checked = 0;
unsigned entry_index = 0;
snprintf(val_d, sizeof(val_d), "%d", setting->enum_idx);
/* Integer settings iterate with an integer counter: a float
* accumulator is exact only while the range and step are
* representable, and would silently drop the final entry or
* emit duplicates once they are not. */
i_min = (int32_t)min;
i_max = (int32_t)max;
i_step = (int32_t)step;
if (i_step < 1)
i_step = 1;
if (setting->actions->repr)
{
for (i = i_min; i <= i_max; i += i_step)
{
char val_s[NAME_MAX_LENGTH];
int val = i;
/* Mouse Index: the mice there are, and
* the one chosen now whatever it is */
if ( setting->enum_idx >= MENU_ENUM_LABEL_INPUT_MOUSE_INDEX
&& setting->enum_idx <= MENU_ENUM_LABEL_INPUT_MOUSE_INDEX_LAST
&& val != (int)orig_value
&& !input_config_mouse_offered((unsigned)val))
continue;
/* Keyboard Index: "All" and the
* keyboards there are */
if (menu_displaylist_keyboard_index(setting))
{
if ( val > 0 && val != (int)orig_value
&& !input_config_get_keyboard_display_name(val - 1))
continue;
if (val != (int)orig_value)
menu_setting_keyboard_index_name(val,
val_s, sizeof(val_s));
}
setting_uint_set(setting, val);
if ( val == (int)orig_value
|| !menu_displaylist_keyboard_index(setting))
setting->actions->repr(setting,
val_s, sizeof(val_s));
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, val, 0, NULL))
count++;
if (!checked_found && val == (int)orig_value)
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
setting_uint_set(setting, orig_value);
}
else
{
for (i = i_min; i <= i_max; i += i_step)
{
char val_s[16];
int val = i;
snprintf(val_s, sizeof(val_s), "%d", val);
if (menu_entries_append(info->list,
val_s,
val_d,
MENU_ENUM_LABEL_NO_ITEMS,
setting_type, val, 0, NULL))
count++;
if (!checked_found && val == (int)orig_value)
{
checked = entry_index;
checked_found = true;
}
entry_index++;
}
}
if (checked_found)
{
menu_file_list_cbs_t *cbs = (menu_file_list_cbs_t*)info->list->list[checked].actiondata;
if (cbs)
cbs->checked = true;
menu_st->selection_ptr = checked;
}
}
break;
default:
break;
}
}
}
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
break;
case DISPLAYLIST_NONE:
break;
}
if (use_filebrowser)
{
if (!info->path || !*info->path)
{
if (frontend_driver_parse_drive_list(info->list, load_content) != 0)
if (menu_entries_append(info->list, "/", "",
load_content ?
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY,
FILE_TYPE_DIRECTORY, 0, 0, NULL))
count++;
#ifdef HAVE_SMBCLIENT
{
char smb_root[PATH_MAX_LENGTH];
if (menu_displaylist_build_smb_root(smb_root, sizeof(smb_root)))
if (menu_entries_append(info->list, smb_root, "",
load_content ?
MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR :
MENU_ENUM_LABEL_FILE_BROWSER_DIRECTORY,
FILE_TYPE_DIRECTORY, 0, 0, NULL))
count++;
}
#endif
}
else
{
const char *pending_selection = menu_st->pending_selection;
bool show_hidden_files = settings->bools.show_hidden_files;
bool multimedia_builtin_mediaplayer_enable = settings->bools.multimedia_builtin_mediaplayer_enable;
bool multimedia_builtin_imageviewer_enable = settings->bools.multimedia_builtin_imageviewer_enable;
bool filter_supported_extensions_enable = settings->bools.menu_navigation_browser_filter_supported_extensions_enable;
filebrowser_parse(info->list, info->path, info->exts, info->label,
info->type_default, type, show_hidden_files,
multimedia_builtin_mediaplayer_enable,
multimedia_builtin_imageviewer_enable,
filter_supported_extensions_enable
);
/* Apply pending selection */
if (pending_selection && *pending_selection)
{
size_t selection_idx = 0;
if (menu_entries_list_search(pending_selection, &selection_idx))
{
menu_st->selection_ptr = selection_idx;
if (menu_st->driver_ctx->navigation_set)
menu_st->driver_ctx->navigation_set(menu_st->userdata, true);
}
menu_driver_set_pending_selection(NULL);
}
}
info->flags |= MD_FLAG_NEED_REFRESH
| MD_FLAG_NEED_PUSH;
}
if (ret != 0)
return false;
}
return true;
}
/* Over-budget watchdog (debug builds): with Threaded Tasks off,
* every displaylist build runs on the thread that drives the UI, so
* a build past the frame-scale budget is a user-visible hitch that
* the walks above were converted to prevent. Flag any that slip
* through - a newly added blocking walk, a playlist parse on a cold
* cache, an archive listing - with the displaylist type so the site
* is identifiable. Threaded queues are exempt: their heavy lifting
* is off-thread by construction, and the callback-side cost is
* already covered by the same budget the tasks step under. */
#define MENU_DISPLAYLIST_BUILD_WARN_USEC 16000
bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
menu_displaylist_info_t *info,
settings_t *settings)
{
#ifdef DEBUG
retro_time_t t0 = cpu_features_get_time_usec();
bool ret = menu_displaylist_ctl_internal(type, info, settings);
retro_time_t dt = cpu_features_get_time_usec() - t0;
if ( (dt > MENU_DISPLAYLIST_BUILD_WARN_USEC)
&& !task_queue_is_threaded())
RARCH_WARN(
"[Menu] Displaylist %d spent %u.%03u ms on the main thread"
" (budget %u ms).\n",
(int)type,
(unsigned)(dt / 1000), (unsigned)(dt % 1000),
(unsigned)(MENU_DISPLAYLIST_BUILD_WARN_USEC / 1000));
return ret;
#else
return menu_displaylist_ctl_internal(type, info, settings);
#endif
}