mirror of
https://github.com/libretro/RetroArch
synced 2025-04-18 05:43:34 +00:00
Add option to selectively 'lock' (prevent modification of) installed cores
This commit is contained in:
parent
4ed7ad8465
commit
80f36e16d0
175
core_info.c
175
core_info.c
@ -19,6 +19,7 @@
|
|||||||
#include <string/stdstring.h>
|
#include <string/stdstring.h>
|
||||||
#include <file/config_file.h>
|
#include <file/config_file.h>
|
||||||
#include <file/file_path.h>
|
#include <file/file_path.h>
|
||||||
|
#include <streams/file_stream.h>
|
||||||
#include <lists/dir_list.h>
|
#include <lists/dir_list.h>
|
||||||
#include <file/archive_file.h>
|
#include <file/archive_file.h>
|
||||||
|
|
||||||
@ -240,6 +241,36 @@ static config_file_t *core_info_list_iterate(
|
|||||||
return conf;
|
return conf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returned path must be free()'d */
|
||||||
|
static char *core_info_get_core_lock_file_path(const char *core_path)
|
||||||
|
{
|
||||||
|
char *lock_file_path = NULL;
|
||||||
|
const char *lock_file_ext = file_path_str(FILE_PATH_LOCK_EXTENSION);
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (string_is_empty(core_path))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Note: We follow the common 'core_info' trend of
|
||||||
|
* allocating all strings dynamically... */
|
||||||
|
|
||||||
|
/* Get path length */
|
||||||
|
len = (strlen(core_path) + strlen(lock_file_ext) + 1) * sizeof(char);
|
||||||
|
|
||||||
|
/* Allocate string */
|
||||||
|
lock_file_path = (char*)malloc(len);
|
||||||
|
if (!lock_file_path)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
lock_file_path[0] = '\0';
|
||||||
|
|
||||||
|
/* Lock file is just core path + 'lock' extension */
|
||||||
|
strlcpy(lock_file_path, core_path, len);
|
||||||
|
strlcat(lock_file_path, lock_file_ext, len);
|
||||||
|
|
||||||
|
return lock_file_path;
|
||||||
|
}
|
||||||
|
|
||||||
static core_info_list_t *core_info_list_new(const char *path,
|
static core_info_list_t *core_info_list_new(const char *path,
|
||||||
const char *libretro_info_dir,
|
const char *libretro_info_dir,
|
||||||
const char *exts,
|
const char *exts,
|
||||||
@ -523,6 +554,9 @@ static core_info_list_t *core_info_list_new(const char *path,
|
|||||||
core_info[i].display_name = strdup(core_filename);
|
core_info[i].display_name = strdup(core_filename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get core lock status */
|
||||||
|
core_info[i].is_locked = core_info_get_core_lock(core_info[i].path, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (core_info_list)
|
if (core_info_list)
|
||||||
@ -1505,3 +1539,144 @@ bool core_info_hw_api_supported(core_info_t *info)
|
|||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sets 'locked' status of specified core
|
||||||
|
* > Returns true if successful
|
||||||
|
* > Like all functions that access the cached
|
||||||
|
* core info list this is *not* thread safe */
|
||||||
|
bool core_info_set_core_lock(const char *core_path, bool lock)
|
||||||
|
{
|
||||||
|
char *lock_file_path = NULL;
|
||||||
|
RFILE *lock_file = NULL;
|
||||||
|
bool lock_file_exists = false;
|
||||||
|
core_info_ctx_find_t core_info;
|
||||||
|
|
||||||
|
if (string_is_empty(core_path))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Search for specified core */
|
||||||
|
core_info.inf = NULL;
|
||||||
|
core_info.path = core_path;
|
||||||
|
|
||||||
|
if (!core_info_find(&core_info))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Get associated lock file path */
|
||||||
|
lock_file_path = core_info_get_core_lock_file_path(core_info.inf->path);
|
||||||
|
|
||||||
|
if (string_is_empty(lock_file_path))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Check whether lock file exists */
|
||||||
|
lock_file_exists = path_is_valid(lock_file_path);
|
||||||
|
|
||||||
|
/* Create or delete lock file, as required */
|
||||||
|
if (lock && !lock_file_exists)
|
||||||
|
{
|
||||||
|
lock_file = filestream_open(
|
||||||
|
lock_file_path,
|
||||||
|
RETRO_VFS_FILE_ACCESS_WRITE,
|
||||||
|
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||||
|
|
||||||
|
if (!lock_file)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* We have to write something - just output
|
||||||
|
* a single character */
|
||||||
|
if (filestream_putc(lock_file, 0) != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
filestream_close(lock_file);
|
||||||
|
lock_file = NULL;
|
||||||
|
}
|
||||||
|
else if (!lock && lock_file_exists)
|
||||||
|
if (filestream_delete(lock_file_path) != 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
free(lock_file_path);
|
||||||
|
lock_file_path = NULL;
|
||||||
|
|
||||||
|
/* File operations were successful - update
|
||||||
|
* core info entry */
|
||||||
|
core_info.inf->is_locked = lock;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (lock_file_path)
|
||||||
|
{
|
||||||
|
free(lock_file_path);
|
||||||
|
lock_file_path = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lock_file)
|
||||||
|
{
|
||||||
|
filestream_close(lock_file);
|
||||||
|
lock_file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetches 'locked' status of specified core
|
||||||
|
* > If 'validate_path' is 'true', will search
|
||||||
|
* cached core info list for a corresponding
|
||||||
|
* 'sanitised' core file path. This is *not*
|
||||||
|
* thread safe
|
||||||
|
* > If 'validate_path' is 'false', performs a
|
||||||
|
* direct filesystem check. This *is* thread
|
||||||
|
* safe, but validity of specified core path
|
||||||
|
* must be checked externally */
|
||||||
|
bool core_info_get_core_lock(const char *core_path, bool validate_path)
|
||||||
|
{
|
||||||
|
const char *core_file_path = NULL;
|
||||||
|
char *lock_file_path = NULL;
|
||||||
|
bool is_locked = false;
|
||||||
|
core_info_ctx_find_t core_info;
|
||||||
|
|
||||||
|
if (string_is_empty(core_path))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* Check whether core path is to be validated */
|
||||||
|
if (validate_path)
|
||||||
|
{
|
||||||
|
core_info.inf = NULL;
|
||||||
|
core_info.path = core_path;
|
||||||
|
|
||||||
|
if (core_info_find(&core_info))
|
||||||
|
core_file_path = core_info.inf->path;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
core_file_path = core_path;
|
||||||
|
|
||||||
|
/* A core cannot be locked if it does not exist... */
|
||||||
|
if (string_is_empty(core_file_path) ||
|
||||||
|
!path_is_valid(core_file_path))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* Get lock file path */
|
||||||
|
lock_file_path = core_info_get_core_lock_file_path(core_file_path);
|
||||||
|
|
||||||
|
if (string_is_empty(lock_file_path))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* Check whether lock file exists */
|
||||||
|
is_locked = path_is_valid(lock_file_path);
|
||||||
|
|
||||||
|
/* If core path has been validated (and a
|
||||||
|
* core info object is available), ensure
|
||||||
|
* that core info 'is_locked' field is
|
||||||
|
* up to date */
|
||||||
|
if (validate_path && core_info.inf)
|
||||||
|
core_info.inf->is_locked = is_locked;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (lock_file_path)
|
||||||
|
{
|
||||||
|
free(lock_file_path);
|
||||||
|
lock_file_path = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return is_locked;
|
||||||
|
}
|
||||||
|
17
core_info.h
17
core_info.h
@ -57,6 +57,7 @@ typedef struct
|
|||||||
bool supports_no_game;
|
bool supports_no_game;
|
||||||
bool database_match_archive_member;
|
bool database_match_archive_member;
|
||||||
bool is_experimental;
|
bool is_experimental;
|
||||||
|
bool is_locked;
|
||||||
size_t firmware_count;
|
size_t firmware_count;
|
||||||
char *path;
|
char *path;
|
||||||
void *config_data;
|
void *config_data;
|
||||||
@ -201,6 +202,22 @@ bool core_info_list_get_info(core_info_list_t *core_info_list,
|
|||||||
|
|
||||||
bool core_info_hw_api_supported(core_info_t *info);
|
bool core_info_hw_api_supported(core_info_t *info);
|
||||||
|
|
||||||
|
/* Sets 'locked' status of specified core
|
||||||
|
* > Returns true if successful
|
||||||
|
* > Like all functions that access the cached
|
||||||
|
* core info list this is *not* thread safe */
|
||||||
|
bool core_info_set_core_lock(const char *core_path, bool lock);
|
||||||
|
/* Fetches 'locked' status of specified core
|
||||||
|
* > If 'validate_path' is 'true', will search
|
||||||
|
* cached core info list for a corresponding
|
||||||
|
* 'sanitised' core file path. This is *not*
|
||||||
|
* thread safe
|
||||||
|
* > If 'validate_path' is 'false', performs a
|
||||||
|
* direct filesystem check. This *is* thread
|
||||||
|
* safe, but validity of specified core path
|
||||||
|
* must be checked externally */
|
||||||
|
bool core_info_get_core_lock(const char *core_path, bool validate_path);
|
||||||
|
|
||||||
core_info_state_t *coreinfo_get_ptr(void);
|
core_info_state_t *coreinfo_get_ptr(void);
|
||||||
|
|
||||||
RETRO_END_DECLS
|
RETRO_END_DECLS
|
||||||
|
@ -98,7 +98,8 @@ enum file_path_enum
|
|||||||
FILE_PATH_EVENT_LOG_EXTENSION,
|
FILE_PATH_EVENT_LOG_EXTENSION,
|
||||||
FILE_PATH_DISK_CONTROL_INDEX_EXTENSION,
|
FILE_PATH_DISK_CONTROL_INDEX_EXTENSION,
|
||||||
FILE_PATH_CORE_BACKUP_EXTENSION,
|
FILE_PATH_CORE_BACKUP_EXTENSION,
|
||||||
FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT
|
FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT,
|
||||||
|
FILE_PATH_LOCK_EXTENSION
|
||||||
};
|
};
|
||||||
|
|
||||||
enum application_special_type
|
enum application_special_type
|
||||||
|
@ -236,6 +236,9 @@ const char *file_path_str(enum file_path_enum enum_idx)
|
|||||||
case FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT:
|
case FILE_PATH_CORE_BACKUP_EXTENSION_NO_DOT:
|
||||||
str = "lcbk";
|
str = "lcbk";
|
||||||
break;
|
break;
|
||||||
|
case FILE_PATH_LOCK_EXTENSION:
|
||||||
|
str = ".lck";
|
||||||
|
break;
|
||||||
case FILE_PATH_UNKNOWN:
|
case FILE_PATH_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -3540,6 +3540,10 @@ MSG_HASH(
|
|||||||
MENU_ENUM_LABEL_MENU_SCROLL_FAST,
|
MENU_ENUM_LABEL_MENU_SCROLL_FAST,
|
||||||
"menu_scroll_fast"
|
"menu_scroll_fast"
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_CORE_LOCK,
|
||||||
|
"core_lock"
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MENU_ENUM_LABEL_CORE_DELETE,
|
MENU_ENUM_LABEL_CORE_DELETE,
|
||||||
"core_delete"
|
"core_delete"
|
||||||
|
@ -449,6 +449,14 @@ MSG_HASH(
|
|||||||
MENU_ENUM_LABEL_VALUE_REQUIRED,
|
MENU_ENUM_LABEL_VALUE_REQUIRED,
|
||||||
"Required"
|
"Required"
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_LABEL_VALUE_CORE_LOCK,
|
||||||
|
"Lock Installed Core"
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MENU_ENUM_SUBLABEL_CORE_LOCK,
|
||||||
|
"Prevent modification of the currently installed core. May be used to avoid unwanted updates when content requires a specific core version (e.g. Arcade ROM sets)."
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MENU_ENUM_LABEL_VALUE_CORE_DELETE,
|
MENU_ENUM_LABEL_VALUE_CORE_DELETE,
|
||||||
"Delete Core"
|
"Delete Core"
|
||||||
@ -9726,6 +9734,14 @@ MSG_HASH(
|
|||||||
MSG_NUM_CORES_UPDATED,
|
MSG_NUM_CORES_UPDATED,
|
||||||
"cores updated: "
|
"cores updated: "
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_NUM_CORES_LOCKED,
|
||||||
|
"cores skipped: "
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_CORE_UPDATE_DISABLED,
|
||||||
|
"Core update disabled - core is locked: "
|
||||||
|
)
|
||||||
MSG_HASH(
|
MSG_HASH(
|
||||||
MSG_PLAYLIST_MANAGER_RESETTING_CORES,
|
MSG_PLAYLIST_MANAGER_RESETTING_CORES,
|
||||||
"Resetting cores: "
|
"Resetting cores: "
|
||||||
@ -10934,6 +10950,26 @@ MSG_HASH(
|
|||||||
MSG_CORE_INSTALLATION_FAILED,
|
MSG_CORE_INSTALLATION_FAILED,
|
||||||
"Core installation failed: "
|
"Core installation failed: "
|
||||||
)
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_CORE_RESTORATION_DISABLED,
|
||||||
|
"Core restoration disabled - core is locked: "
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_CORE_INSTALLATION_DISABLED,
|
||||||
|
"Core installation disabled - core is locked: "
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_CORE_LOCK_FAILED,
|
||||||
|
"Failed to lock core: "
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_CORE_UNLOCK_FAILED,
|
||||||
|
"Failed to unlock core: "
|
||||||
|
)
|
||||||
|
MSG_HASH(
|
||||||
|
MSG_CORE_DELETE_DISABLED,
|
||||||
|
"Core deletion disabled - core is locked: "
|
||||||
|
)
|
||||||
|
|
||||||
/* Lakka */
|
/* Lakka */
|
||||||
|
|
||||||
|
@ -464,8 +464,17 @@ static void menu_action_setting_disp_set_label_core_updater_entry(
|
|||||||
|
|
||||||
if (core_info_find(&core_info))
|
if (core_info_find(&core_info))
|
||||||
{
|
{
|
||||||
strlcpy(s, "[#]", len);
|
/* Highlight locked cores */
|
||||||
*w = (unsigned)STRLEN_CONST("[#]");
|
if (core_info.inf->is_locked)
|
||||||
|
{
|
||||||
|
strlcpy(s, "[#!]", len);
|
||||||
|
*w = (unsigned)STRLEN_CONST("[#!]");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strlcpy(s, "[#]", len);
|
||||||
|
*w = (unsigned)STRLEN_CONST("[#]");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -480,6 +489,7 @@ static void menu_action_setting_disp_set_label_core_manager_entry(
|
|||||||
char *s2, size_t len2)
|
char *s2, size_t len2)
|
||||||
{
|
{
|
||||||
const char *alt = NULL;
|
const char *alt = NULL;
|
||||||
|
core_info_ctx_find_t core_info;
|
||||||
|
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
*w = 0;
|
*w = 0;
|
||||||
@ -490,10 +500,55 @@ static void menu_action_setting_disp_set_label_core_manager_entry(
|
|||||||
if (alt)
|
if (alt)
|
||||||
strlcpy(s2, alt, len2);
|
strlcpy(s2, alt, len2);
|
||||||
|
|
||||||
/* TODO: Once core-specific 'block online updates'
|
/* Check whether core is locked
|
||||||
* settings are implemented, the 'value' string will
|
* > Note: We search core_info here instead of
|
||||||
* be used to indicate whether updates are enabled
|
* calling core_info_get_core_lock() since we
|
||||||
* or disabled */
|
* don't want to perform disk access every frame */
|
||||||
|
core_info.inf = NULL;
|
||||||
|
core_info.path = path;
|
||||||
|
|
||||||
|
if (core_info_find(&core_info) &&
|
||||||
|
core_info.inf->is_locked)
|
||||||
|
{
|
||||||
|
strlcpy(s, "[!]", len);
|
||||||
|
*w = (unsigned)STRLEN_CONST("[!]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menu_action_setting_disp_set_label_core_lock(
|
||||||
|
file_list_t* list,
|
||||||
|
unsigned *w, unsigned type, unsigned i,
|
||||||
|
const char *label,
|
||||||
|
char *s, size_t len,
|
||||||
|
const char *path,
|
||||||
|
char *s2, size_t len2)
|
||||||
|
{
|
||||||
|
const char *alt = NULL;
|
||||||
|
core_info_ctx_find_t core_info;
|
||||||
|
|
||||||
|
*s = '\0';
|
||||||
|
*w = 0;
|
||||||
|
|
||||||
|
menu_entries_get_at_offset(list, i, NULL,
|
||||||
|
NULL, NULL, NULL, &alt);
|
||||||
|
|
||||||
|
if (alt)
|
||||||
|
strlcpy(s2, alt, len2);
|
||||||
|
|
||||||
|
/* Check whether core is locked
|
||||||
|
* > Note: We search core_info here instead of
|
||||||
|
* calling core_info_get_core_lock() since we
|
||||||
|
* don't want to perform disk access every frame */
|
||||||
|
core_info.inf = NULL;
|
||||||
|
core_info.path = path;
|
||||||
|
|
||||||
|
if (core_info_find(&core_info) &&
|
||||||
|
core_info.inf->is_locked)
|
||||||
|
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_ON), len);
|
||||||
|
else
|
||||||
|
strlcpy(s, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF), len);
|
||||||
|
|
||||||
|
*w = (unsigned)strlen(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void menu_action_setting_disp_set_label_input_desc(
|
static void menu_action_setting_disp_set_label_input_desc(
|
||||||
@ -1622,7 +1677,7 @@ static int menu_cbs_init_bind_get_string_representation_compare_label(
|
|||||||
menu_action_setting_disp_set_label_core_manager_entry);
|
menu_action_setting_disp_set_label_core_manager_entry);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return - 1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1821,6 +1876,10 @@ static int menu_cbs_init_bind_get_string_representation_compare_type(
|
|||||||
case MENU_SETTING_NO_ITEM:
|
case MENU_SETTING_NO_ITEM:
|
||||||
BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_no_items);
|
BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_no_items);
|
||||||
break;
|
break;
|
||||||
|
case MENU_SETTING_ACTION_CORE_LOCK:
|
||||||
|
BIND_ACTION_GET_VALUE(cbs,
|
||||||
|
menu_action_setting_disp_set_label_core_lock);
|
||||||
|
break;
|
||||||
case 32: /* Recent history entry */
|
case 32: /* Recent history entry */
|
||||||
case 65535: /* System info entry */
|
case 65535: /* System info entry */
|
||||||
BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_entry);
|
BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label_entry);
|
||||||
|
@ -46,6 +46,9 @@
|
|||||||
#define BIND_ACTION_LEFT(cbs, name) (cbs)->action_left = (name)
|
#define BIND_ACTION_LEFT(cbs, name) (cbs)->action_left = (name)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Forward declarations */
|
||||||
|
int action_ok_core_lock(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx);
|
||||||
|
|
||||||
extern struct key_desc key_descriptors[RARCH_MAX_KEYS];
|
extern struct key_desc key_descriptors[RARCH_MAX_KEYS];
|
||||||
|
|
||||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||||
@ -680,6 +683,12 @@ static int core_setting_left(unsigned type, const char *label,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int action_left_core_lock(unsigned type, const char *label,
|
||||||
|
bool wraparound)
|
||||||
|
{
|
||||||
|
return action_ok_core_lock(label, label, type, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int disk_options_disk_idx_left(unsigned type, const char *label,
|
static int disk_options_disk_idx_left(unsigned type, const char *label,
|
||||||
bool wraparound)
|
bool wraparound)
|
||||||
{
|
{
|
||||||
@ -1066,6 +1075,9 @@ static int menu_cbs_init_bind_left_compare_type(menu_file_list_cbs_t *cbs,
|
|||||||
case FILE_TYPE_CONTENTLIST_ENTRY:
|
case FILE_TYPE_CONTENTLIST_ENTRY:
|
||||||
BIND_ACTION_LEFT(cbs, action_left_mainmenu);
|
BIND_ACTION_LEFT(cbs, action_left_mainmenu);
|
||||||
break;
|
break;
|
||||||
|
case MENU_SETTING_ACTION_CORE_LOCK:
|
||||||
|
BIND_ACTION_LEFT(cbs, action_left_core_lock);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -6360,17 +6360,122 @@ static int action_ok_core_delete_backup(const char *path,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do not declare this static - it is also used
|
||||||
|
* in menu_cbs_left.c and menu_cbs_right.c */
|
||||||
|
int action_ok_core_lock(const char *path,
|
||||||
|
const char *label, unsigned type, size_t idx, size_t entry_idx)
|
||||||
|
{
|
||||||
|
const char *core_path = path;
|
||||||
|
bool lock = false;
|
||||||
|
bool refresh = false;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (string_is_empty(core_path))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Simply toggle current lock status */
|
||||||
|
lock = !core_info_get_core_lock(core_path, true);
|
||||||
|
|
||||||
|
if (!core_info_set_core_lock(core_path, lock))
|
||||||
|
{
|
||||||
|
const char *core_name = NULL;
|
||||||
|
core_info_ctx_find_t core_info;
|
||||||
|
char msg[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
msg[0] = '\0';
|
||||||
|
|
||||||
|
/* Need to fetch core name for error message */
|
||||||
|
core_info.inf = NULL;
|
||||||
|
core_info.path = core_path;
|
||||||
|
|
||||||
|
/* If core is found, use display name */
|
||||||
|
if (core_info_find(&core_info) &&
|
||||||
|
core_info.inf->display_name)
|
||||||
|
core_name = core_info.inf->display_name;
|
||||||
|
/* If not, use core file name */
|
||||||
|
else
|
||||||
|
core_name = path_basename(core_path);
|
||||||
|
|
||||||
|
/* Build error message */
|
||||||
|
strlcpy(
|
||||||
|
msg,
|
||||||
|
msg_hash_to_str(lock ?
|
||||||
|
MSG_CORE_LOCK_FAILED : MSG_CORE_UNLOCK_FAILED),
|
||||||
|
sizeof(msg));
|
||||||
|
|
||||||
|
if (!string_is_empty(core_name))
|
||||||
|
strlcat(msg, core_name, sizeof(msg));
|
||||||
|
|
||||||
|
/* Generate log + notification */
|
||||||
|
RARCH_ERR("%s\n", msg);
|
||||||
|
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg,
|
||||||
|
1, 100, true,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Whenever lock status is changed, menu must be
|
||||||
|
* refreshed - do this even in the event of an error,
|
||||||
|
* since we don't want to leave the menu in an
|
||||||
|
* undefined state */
|
||||||
|
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
|
||||||
|
menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int action_ok_core_delete(const char *path,
|
static int action_ok_core_delete(const char *path,
|
||||||
const char *label, unsigned type, size_t idx, size_t entry_idx)
|
const char *label, unsigned type, size_t idx, size_t entry_idx)
|
||||||
{
|
{
|
||||||
const char *core_path = label;
|
const char *core_path = label;
|
||||||
const char *core = NULL;
|
const char *core = NULL;
|
||||||
const char *loaded_core_path = NULL;
|
const char *loaded_core_path = NULL;
|
||||||
const char *loaded_core = NULL;
|
const char *loaded_core = NULL;
|
||||||
|
|
||||||
if (string_is_empty(core_path))
|
if (string_is_empty(core_path))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
/* Check whether core is locked */
|
||||||
|
if (core_info_get_core_lock(core_path, true))
|
||||||
|
{
|
||||||
|
const char *core_name = NULL;
|
||||||
|
core_info_ctx_find_t core_info;
|
||||||
|
char msg[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
msg[0] = '\0';
|
||||||
|
|
||||||
|
/* Need to fetch core name for notification */
|
||||||
|
core_info.inf = NULL;
|
||||||
|
core_info.path = core_path;
|
||||||
|
|
||||||
|
/* If core is found, use display name */
|
||||||
|
if (core_info_find(&core_info) &&
|
||||||
|
core_info.inf->display_name)
|
||||||
|
core_name = core_info.inf->display_name;
|
||||||
|
/* If not, use core file name */
|
||||||
|
else
|
||||||
|
core_name = path_basename(core_path);
|
||||||
|
|
||||||
|
/* Build notification message */
|
||||||
|
strlcpy(msg, msg_hash_to_str(MSG_CORE_DELETE_DISABLED), sizeof(msg));
|
||||||
|
|
||||||
|
if (!string_is_empty(core_name))
|
||||||
|
strlcat(msg, core_name, sizeof(msg));
|
||||||
|
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg,
|
||||||
|
1, 100, true,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
|
||||||
|
/* We do not consider this an 'error' - we are
|
||||||
|
* merely telling the user that this operation
|
||||||
|
* is not currently supported */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get core file name */
|
/* Get core file name */
|
||||||
core = path_basename(core_path);
|
core = path_basename(core_path);
|
||||||
if (string_is_empty(core))
|
if (string_is_empty(core))
|
||||||
@ -7409,6 +7514,9 @@ static int menu_cbs_init_bind_ok_compare_type(menu_file_list_cbs_t *cbs,
|
|||||||
case MENU_SETTING_ITEM_CORE_DELETE_BACKUP:
|
case MENU_SETTING_ITEM_CORE_DELETE_BACKUP:
|
||||||
BIND_ACTION_OK(cbs, action_ok_core_delete_backup);
|
BIND_ACTION_OK(cbs, action_ok_core_delete_backup);
|
||||||
break;
|
break;
|
||||||
|
case MENU_SETTING_ACTION_CORE_LOCK:
|
||||||
|
BIND_ACTION_OK(cbs, action_ok_core_lock);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,9 @@
|
|||||||
#define BIND_ACTION_RIGHT(cbs, name) (cbs)->action_right = (name)
|
#define BIND_ACTION_RIGHT(cbs, name) (cbs)->action_right = (name)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Forward declarations */
|
||||||
|
int action_ok_core_lock(const char *path, const char *label, unsigned type, size_t idx, size_t entry_idx);
|
||||||
|
|
||||||
extern struct key_desc key_descriptors[RARCH_MAX_KEYS];
|
extern struct key_desc key_descriptors[RARCH_MAX_KEYS];
|
||||||
|
|
||||||
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
#if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL)
|
||||||
@ -804,6 +807,12 @@ int core_setting_right(unsigned type, const char *label,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int action_right_core_lock(unsigned type, const char *label,
|
||||||
|
bool wraparound)
|
||||||
|
{
|
||||||
|
return action_ok_core_lock(label, label, type, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static int disk_options_disk_idx_right(unsigned type, const char *label,
|
static int disk_options_disk_idx_right(unsigned type, const char *label,
|
||||||
bool wraparound)
|
bool wraparound)
|
||||||
{
|
{
|
||||||
@ -923,6 +932,9 @@ static int menu_cbs_init_bind_right_compare_type(menu_file_list_cbs_t *cbs,
|
|||||||
case FILE_TYPE_CONTENTLIST_ENTRY:
|
case FILE_TYPE_CONTENTLIST_ENTRY:
|
||||||
BIND_ACTION_RIGHT(cbs, action_right_mainmenu);
|
BIND_ACTION_RIGHT(cbs, action_right_mainmenu);
|
||||||
break;
|
break;
|
||||||
|
case MENU_SETTING_ACTION_CORE_LOCK:
|
||||||
|
BIND_ACTION_RIGHT(cbs, action_right_core_lock);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include "../../managers/core_option_manager.h"
|
#include "../../managers/core_option_manager.h"
|
||||||
#include "../../managers/cheat_manager.h"
|
#include "../../managers/cheat_manager.h"
|
||||||
#include "../../retroarch.h"
|
#include "../../retroarch.h"
|
||||||
|
#include "../../verbosity.h"
|
||||||
#include "../../performance_counters.h"
|
#include "../../performance_counters.h"
|
||||||
#include "../../playlist.h"
|
#include "../../playlist.h"
|
||||||
#include "../../manual_content_scan.h"
|
#include "../../manual_content_scan.h"
|
||||||
@ -495,6 +496,70 @@ static int action_start_core_updater_entry(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int action_start_core_lock(
|
||||||
|
const char *path, const char *label,
|
||||||
|
unsigned type, size_t idx, size_t entry_idx)
|
||||||
|
{
|
||||||
|
const char *core_path = path;
|
||||||
|
bool refresh = false;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (string_is_empty(core_path))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* Core should be unlocked by default
|
||||||
|
* > If it is currently unlocked, do nothing */
|
||||||
|
if (!core_info_get_core_lock(core_path, true))
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* ...Otherwise, attempt to unlock it */
|
||||||
|
if (!core_info_set_core_lock(core_path, false))
|
||||||
|
{
|
||||||
|
const char *core_name = NULL;
|
||||||
|
core_info_ctx_find_t core_info;
|
||||||
|
char msg[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
msg[0] = '\0';
|
||||||
|
|
||||||
|
/* Need to fetch core name for error message */
|
||||||
|
core_info.inf = NULL;
|
||||||
|
core_info.path = core_path;
|
||||||
|
|
||||||
|
/* If core is found, use display name */
|
||||||
|
if (core_info_find(&core_info) &&
|
||||||
|
core_info.inf->display_name)
|
||||||
|
core_name = core_info.inf->display_name;
|
||||||
|
/* If not, use core file name */
|
||||||
|
else
|
||||||
|
core_name = path_basename(core_path);
|
||||||
|
|
||||||
|
/* Build error message */
|
||||||
|
strlcpy(msg, msg_hash_to_str(MSG_CORE_UNLOCK_FAILED), sizeof(msg));
|
||||||
|
|
||||||
|
if (!string_is_empty(core_name))
|
||||||
|
strlcat(msg, core_name, sizeof(msg));
|
||||||
|
|
||||||
|
/* Generate log + notification */
|
||||||
|
RARCH_ERR("%s\n", msg);
|
||||||
|
|
||||||
|
runloop_msg_queue_push(
|
||||||
|
msg,
|
||||||
|
1, 100, true,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Whenever lock status is changed, menu must be
|
||||||
|
* refreshed - do this even in the event of an error,
|
||||||
|
* since we don't want to leave the menu in an
|
||||||
|
* undefined state */
|
||||||
|
menu_entries_ctl(MENU_ENTRIES_CTL_SET_REFRESH, &refresh);
|
||||||
|
menu_driver_ctl(RARCH_MENU_CTL_SET_PREVENT_POPULATE, NULL);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int action_start_lookup_setting(
|
static int action_start_lookup_setting(
|
||||||
const char *path, const char *label,
|
const char *path, const char *label,
|
||||||
unsigned type, size_t idx, size_t entry_idx)
|
unsigned type, size_t idx, size_t entry_idx)
|
||||||
@ -636,6 +701,9 @@ static int menu_cbs_init_bind_start_compare_type(menu_file_list_cbs_t *cbs,
|
|||||||
BIND_ACTION_START(cbs, action_start_core_updater_entry);
|
BIND_ACTION_START(cbs, action_start_core_updater_entry);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
case MENU_SETTING_ACTION_CORE_LOCK:
|
||||||
|
BIND_ACTION_START(cbs, action_start_core_lock);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -753,6 +753,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_x,
|
|||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_y, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_y, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_Y)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_use_mitm_server, MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_use_mitm_server, MENU_ENUM_SUBLABEL_NETPLAY_USE_MITM_SERVER)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_mitm_server, MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_netplay_mitm_server, MENU_ENUM_SUBLABEL_NETPLAY_MITM_SERVER)
|
||||||
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_lock, MENU_ENUM_SUBLABEL_CORE_LOCK)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_delete, MENU_ENUM_SUBLABEL_CORE_DELETE)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_core_delete, MENU_ENUM_SUBLABEL_CORE_DELETE)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_pause_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_pause_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_PAUSE)
|
||||||
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_resume_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME)
|
DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_resume_hardcode_mode, MENU_ENUM_SUBLABEL_ACHIEVEMENT_RESUME)
|
||||||
@ -3468,6 +3469,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
|
|||||||
case MENU_ENUM_LABEL_NETPLAY_MITM_SERVER:
|
case MENU_ENUM_LABEL_NETPLAY_MITM_SERVER:
|
||||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_mitm_server);
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_netplay_mitm_server);
|
||||||
break;
|
break;
|
||||||
|
case MENU_ENUM_LABEL_CORE_LOCK:
|
||||||
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_lock);
|
||||||
|
break;
|
||||||
case MENU_ENUM_LABEL_CORE_DELETE:
|
case MENU_ENUM_LABEL_CORE_DELETE:
|
||||||
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_delete);
|
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_delete);
|
||||||
break;
|
break;
|
||||||
|
@ -9119,6 +9119,7 @@ static void materialui_list_insert(
|
|||||||
case FILE_TYPE_DOWNLOAD_CORE:
|
case FILE_TYPE_DOWNLOAD_CORE:
|
||||||
case FILE_TYPE_CORE:
|
case FILE_TYPE_CORE:
|
||||||
case MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS:
|
case MENU_SETTING_ACTION_CORE_MANAGER_OPTIONS:
|
||||||
|
case MENU_SETTING_ACTION_CORE_LOCK:
|
||||||
node->icon_texture_index = MUI_TEXTURE_CORES;
|
node->icon_texture_index = MUI_TEXTURE_CORES;
|
||||||
node->has_icon = true;
|
node->has_icon = true;
|
||||||
break;
|
break;
|
||||||
|
@ -239,6 +239,8 @@ uintptr_t ozone_entries_icon_get_texture(ozone_handle_t *ozone,
|
|||||||
case MENU_ENUM_LABEL_DELETE_PLAYLIST:
|
case MENU_ENUM_LABEL_DELETE_PLAYLIST:
|
||||||
case MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST:
|
case MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST:
|
||||||
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOSE];
|
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CLOSE];
|
||||||
|
case MENU_ENUM_LABEL_CORE_LOCK:
|
||||||
|
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_CORE];
|
||||||
case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS:
|
case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS:
|
||||||
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_OSD];
|
return ozone->icons_textures[OZONE_ENTRIES_ICONS_TEXTURE_OSD];
|
||||||
case MENU_ENUM_LABEL_SHOW_WIMP:
|
case MENU_ENUM_LABEL_SHOW_WIMP:
|
||||||
|
@ -2644,6 +2644,8 @@ static uintptr_t xmb_icon_get_id(xmb_handle_t *xmb,
|
|||||||
case MENU_ENUM_LABEL_DELETE_PLAYLIST:
|
case MENU_ENUM_LABEL_DELETE_PLAYLIST:
|
||||||
case MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST:
|
case MENU_ENUM_LABEL_CORE_DELETE_BACKUP_LIST:
|
||||||
return xmb->textures.list[XMB_TEXTURE_CLOSE];
|
return xmb->textures.list[XMB_TEXTURE_CLOSE];
|
||||||
|
case MENU_ENUM_LABEL_CORE_LOCK:
|
||||||
|
return xmb->textures.list[XMB_TEXTURE_CORE];
|
||||||
case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS:
|
case MENU_ENUM_LABEL_ONSCREEN_DISPLAY_SETTINGS:
|
||||||
return xmb->textures.list[XMB_TEXTURE_OSD];
|
return xmb->textures.list[XMB_TEXTURE_OSD];
|
||||||
case MENU_ENUM_LABEL_SHOW_WIMP:
|
case MENU_ENUM_LABEL_SHOW_WIMP:
|
||||||
|
@ -367,6 +367,26 @@ end:
|
|||||||
#if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
#if !(defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
||||||
if (!string_is_empty(core_path) && !kiosk_mode_enable)
|
if (!string_is_empty(core_path) && !kiosk_mode_enable)
|
||||||
{
|
{
|
||||||
|
/* Check whether core is currently locked */
|
||||||
|
bool core_locked = core_info_get_core_lock(core_path, true);
|
||||||
|
|
||||||
|
/* 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_enum(info->list,
|
||||||
|
core_path,
|
||||||
|
core_path,
|
||||||
|
MENU_ENUM_LABEL_CORE_LOCK,
|
||||||
|
MENU_SETTING_ACTION_CORE_LOCK, 0, 0))
|
||||||
|
{
|
||||||
|
file_list_set_alt_at_offset(
|
||||||
|
info->list, count, msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LOCK));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
/* Backup core */
|
/* Backup core */
|
||||||
if (menu_entries_append_enum(info->list,
|
if (menu_entries_append_enum(info->list,
|
||||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_CREATE_BACKUP),
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_CREATE_BACKUP),
|
||||||
@ -376,12 +396,13 @@ end:
|
|||||||
count++;
|
count++;
|
||||||
|
|
||||||
/* Restore core from backup */
|
/* Restore core from backup */
|
||||||
if (menu_entries_append_enum(info->list,
|
if (!core_locked)
|
||||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_RESTORE_BACKUP_LIST),
|
if (menu_entries_append_enum(info->list,
|
||||||
core_path,
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_RESTORE_BACKUP_LIST),
|
||||||
MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_LIST,
|
core_path,
|
||||||
MENU_SETTING_ACTION_CORE_RESTORE_BACKUP, 0, 0))
|
MENU_ENUM_LABEL_CORE_RESTORE_BACKUP_LIST,
|
||||||
count++;
|
MENU_SETTING_ACTION_CORE_RESTORE_BACKUP, 0, 0))
|
||||||
|
count++;
|
||||||
|
|
||||||
/* Delete core backup */
|
/* Delete core backup */
|
||||||
if (menu_entries_append_enum(info->list,
|
if (menu_entries_append_enum(info->list,
|
||||||
@ -397,7 +418,7 @@ end:
|
|||||||
* up in a situation where a core cannot be
|
* up in a situation where a core cannot be
|
||||||
* restored */
|
* restored */
|
||||||
#if defined(HAVE_NETWORKING) && defined(HAVE_ONLINE_UPDATER)
|
#if defined(HAVE_NETWORKING) && defined(HAVE_ONLINE_UPDATER)
|
||||||
if (menu_show_core_updater)
|
if (menu_show_core_updater && !core_locked)
|
||||||
if (menu_entries_append_enum(info->list,
|
if (menu_entries_append_enum(info->list,
|
||||||
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_DELETE),
|
msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_DELETE),
|
||||||
core_path,
|
core_path,
|
||||||
@ -9641,26 +9662,30 @@ bool menu_displaylist_ctl(enum menu_displaylist_ctl_state type,
|
|||||||
break;
|
break;
|
||||||
case DISPLAYLIST_CORE_INFO:
|
case DISPLAYLIST_CORE_INFO:
|
||||||
{
|
{
|
||||||
/* There is a (infinitesimally small) chance that
|
/* The number of items in the core info menu:
|
||||||
* the number of items in the core info menu will
|
* - *May* (possibly) change after performing a
|
||||||
* change after performing a core restore operation
|
* core restore operation (i.e. the core info
|
||||||
* (i.e. the core info files are reloaded, and if
|
* files are reloaded, and if an unknown error
|
||||||
* an unknown error occurs then info entries may
|
* occurs then info entries may not be available
|
||||||
* not be available upon popping the stack). We
|
* upon popping the stack)
|
||||||
* therefore have to cache the last set menu size,
|
* - *Will* change when toggling the core lock
|
||||||
* and reset the navigation pointer if the current
|
* status
|
||||||
* size is different */
|
* To prevent the menu selection from going out
|
||||||
static size_t prev_count = 0;
|
* of bounds, we therefore have to check that the
|
||||||
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
|
* current selection index is less than the current
|
||||||
count = menu_displaylist_parse_core_info(info);
|
* number of menu entries - if not, we reset the
|
||||||
|
* navigation pointer */
|
||||||
|
size_t selection = menu_navigation_get_selection();
|
||||||
|
|
||||||
if (count != prev_count)
|
menu_entries_ctl(MENU_ENTRIES_CTL_CLEAR, info->list);
|
||||||
|
count = menu_displaylist_parse_core_info(info);
|
||||||
|
|
||||||
|
if (selection >= count)
|
||||||
{
|
{
|
||||||
info->need_refresh = true;
|
info->need_refresh = true;
|
||||||
info->need_navigation_clear = true;
|
info->need_navigation_clear = true;
|
||||||
prev_count = count;
|
|
||||||
}
|
}
|
||||||
info->need_push = true;
|
info->need_push = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DISPLAYLIST_CORE_RESTORE_BACKUP_LIST:
|
case DISPLAYLIST_CORE_RESTORE_BACKUP_LIST:
|
||||||
|
@ -108,6 +108,7 @@ enum menu_settings_type
|
|||||||
MENU_SETTING_ACTION_SCREENSHOT,
|
MENU_SETTING_ACTION_SCREENSHOT,
|
||||||
MENU_SETTING_ACTION_DELETE_ENTRY,
|
MENU_SETTING_ACTION_DELETE_ENTRY,
|
||||||
MENU_SETTING_ACTION_RESET,
|
MENU_SETTING_ACTION_RESET,
|
||||||
|
MENU_SETTING_ACTION_CORE_LOCK,
|
||||||
MENU_SETTING_ACTION_CORE_DELETE,
|
MENU_SETTING_ACTION_CORE_DELETE,
|
||||||
MENU_SETTING_STRING_OPTIONS,
|
MENU_SETTING_STRING_OPTIONS,
|
||||||
MENU_SETTING_GROUP,
|
MENU_SETTING_GROUP,
|
||||||
|
@ -1995,8 +1995,13 @@ enum msg_hash_enums
|
|||||||
MENU_LABEL(ACHIEVEMENT_RESUME),
|
MENU_LABEL(ACHIEVEMENT_RESUME),
|
||||||
MENU_LABEL(CORE_INFORMATION),
|
MENU_LABEL(CORE_INFORMATION),
|
||||||
MENU_LABEL(DISC_INFORMATION),
|
MENU_LABEL(DISC_INFORMATION),
|
||||||
|
MENU_LABEL(CORE_LOCK),
|
||||||
MENU_LABEL(CORE_DELETE),
|
MENU_LABEL(CORE_DELETE),
|
||||||
|
|
||||||
|
MSG_CORE_LOCK_FAILED,
|
||||||
|
MSG_CORE_UNLOCK_FAILED,
|
||||||
|
MSG_CORE_DELETE_DISABLED,
|
||||||
|
|
||||||
/* Core updater */
|
/* Core updater */
|
||||||
MENU_LABEL(UPDATE_INSTALLED_CORES),
|
MENU_LABEL(UPDATE_INSTALLED_CORES),
|
||||||
|
|
||||||
@ -2011,6 +2016,8 @@ enum msg_hash_enums
|
|||||||
MSG_CHECKING_CORE,
|
MSG_CHECKING_CORE,
|
||||||
MSG_ALL_CORES_UPDATED,
|
MSG_ALL_CORES_UPDATED,
|
||||||
MSG_NUM_CORES_UPDATED,
|
MSG_NUM_CORES_UPDATED,
|
||||||
|
MSG_NUM_CORES_LOCKED,
|
||||||
|
MSG_CORE_UPDATE_DISABLED,
|
||||||
|
|
||||||
/* Core backup/restore */
|
/* Core backup/restore */
|
||||||
MENU_LABEL(CORE_CREATE_BACKUP),
|
MENU_LABEL(CORE_CREATE_BACKUP),
|
||||||
@ -2037,6 +2044,8 @@ enum msg_hash_enums
|
|||||||
MSG_CORE_BACKUP_FAILED,
|
MSG_CORE_BACKUP_FAILED,
|
||||||
MSG_CORE_RESTORATION_FAILED,
|
MSG_CORE_RESTORATION_FAILED,
|
||||||
MSG_CORE_INSTALLATION_FAILED,
|
MSG_CORE_INSTALLATION_FAILED,
|
||||||
|
MSG_CORE_RESTORATION_DISABLED,
|
||||||
|
MSG_CORE_INSTALLATION_DISABLED,
|
||||||
|
|
||||||
MENU_LABEL(VIDEO_SHADER_PARAMETERS),
|
MENU_LABEL(VIDEO_SHADER_PARAMETERS),
|
||||||
MENU_LABEL(VIDEO_SHADER_PRESET_PARAMETERS),
|
MENU_LABEL(VIDEO_SHADER_PRESET_PARAMETERS),
|
||||||
|
@ -992,14 +992,6 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Concurrent backup/restore tasks for the same core
|
|
||||||
* are not allowed */
|
|
||||||
find_data.func = task_core_backup_finder;
|
|
||||||
find_data.userdata = (void*)core_path;
|
|
||||||
|
|
||||||
if (task_queue_find(&find_data))
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Get core name */
|
/* Get core name */
|
||||||
core_info.inf = NULL;
|
core_info.inf = NULL;
|
||||||
core_info.path = core_path;
|
core_info.path = core_path;
|
||||||
@ -1017,6 +1009,34 @@ bool task_push_core_restore(const char *backup_path, const char *dir_libretro,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether core is locked */
|
||||||
|
if (core_info_get_core_lock(core_path, true))
|
||||||
|
{
|
||||||
|
char msg[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
msg[0] = '\0';
|
||||||
|
|
||||||
|
strlcpy(msg,
|
||||||
|
(backup_type == CORE_BACKUP_TYPE_ARCHIVE) ?
|
||||||
|
msg_hash_to_str(MSG_CORE_RESTORATION_DISABLED) :
|
||||||
|
msg_hash_to_str(MSG_CORE_INSTALLATION_DISABLED),
|
||||||
|
sizeof(msg));
|
||||||
|
strlcat(msg, core_name, sizeof(msg));
|
||||||
|
|
||||||
|
RARCH_ERR("[core restore] Restoration disabled - core is locked: %s\n", core_path);
|
||||||
|
runloop_msg_queue_push(msg, 1, 100, true,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Concurrent backup/restore tasks for the same core
|
||||||
|
* are not allowed */
|
||||||
|
find_data.func = task_core_backup_finder;
|
||||||
|
find_data.userdata = (void*)core_path;
|
||||||
|
|
||||||
|
if (task_queue_find(&find_data))
|
||||||
|
goto error;
|
||||||
|
|
||||||
/* Configure handle */
|
/* Configure handle */
|
||||||
backup_handle = (core_backup_handle_t*)calloc(1, sizeof(core_backup_handle_t));
|
backup_handle = (core_backup_handle_t*)calloc(1, sizeof(core_backup_handle_t));
|
||||||
|
|
||||||
|
@ -123,6 +123,7 @@ typedef struct update_installed_cores_handle
|
|||||||
size_t list_index;
|
size_t list_index;
|
||||||
size_t installed_index;
|
size_t installed_index;
|
||||||
unsigned num_updated;
|
unsigned num_updated;
|
||||||
|
unsigned num_locked;
|
||||||
enum update_installed_cores_status status;
|
enum update_installed_cores_status status;
|
||||||
} update_installed_cores_handle_t;
|
} update_installed_cores_handle_t;
|
||||||
|
|
||||||
@ -962,14 +963,37 @@ void *task_push_core_updater_download(
|
|||||||
core_list, filename, &list_entry))
|
core_list, filename, &list_entry))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (string_is_empty(list_entry->remote_core_path))
|
if (string_is_empty(list_entry->remote_core_path) ||
|
||||||
|
string_is_empty(list_entry->local_core_path) ||
|
||||||
|
string_is_empty(list_entry->display_name))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (string_is_empty(list_entry->local_core_path))
|
/* Check whether core is locked
|
||||||
goto error;
|
* > Have to set validate_path to 'false' here,
|
||||||
|
* since this may not run on the main thread
|
||||||
|
* > Validation is not required anyway, since core
|
||||||
|
* updater list provides 'sane' core paths */
|
||||||
|
if (core_info_get_core_lock(list_entry->local_core_path, false))
|
||||||
|
{
|
||||||
|
RARCH_ERR("[core updater] Update disabled - core is locked: %s\n",
|
||||||
|
list_entry->local_core_path);
|
||||||
|
|
||||||
|
/* If task is not muted, generate notification */
|
||||||
|
if (!mute)
|
||||||
|
{
|
||||||
|
char msg[PATH_MAX_LENGTH];
|
||||||
|
|
||||||
|
msg[0] = '\0';
|
||||||
|
|
||||||
|
strlcpy(msg, msg_hash_to_str(MSG_CORE_UPDATE_DISABLED), sizeof(msg));
|
||||||
|
strlcat(msg, list_entry->display_name, sizeof(msg));
|
||||||
|
|
||||||
|
runloop_msg_queue_push(msg, 1, 100, true,
|
||||||
|
NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
if (string_is_empty(list_entry->display_name))
|
|
||||||
goto error;
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get local file download path */
|
/* Get local file download path */
|
||||||
if (string_is_empty(path_dir_libretro))
|
if (string_is_empty(path_dir_libretro))
|
||||||
@ -1206,6 +1230,24 @@ static void task_update_installed_cores_handler(retro_task_t *task)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check whether core is locked
|
||||||
|
* > Have to set validate_path to 'false' here,
|
||||||
|
* since this does not run on the main thread
|
||||||
|
* > Validation is not required anyway, since core
|
||||||
|
* updater list provides 'sane' core paths */
|
||||||
|
if (core_info_get_core_lock(list_entry->local_core_path, false))
|
||||||
|
{
|
||||||
|
RARCH_LOG("[core updater] Skipping locked core: %s\n",
|
||||||
|
list_entry->display_name);
|
||||||
|
|
||||||
|
/* Core update is disabled
|
||||||
|
* > Just increment 'locked cores' counter and
|
||||||
|
* return to UPDATE_INSTALLED_CORES_ITERATE state */
|
||||||
|
update_installed_handle->num_locked++;
|
||||||
|
update_installed_handle->status = UPDATE_INSTALLED_CORES_ITERATE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get CRC of existing core */
|
/* Get CRC of existing core */
|
||||||
local_crc = task_core_updater_get_core_crc(
|
local_crc = task_core_updater_get_core_crc(
|
||||||
list_entry->local_core_path);
|
list_entry->local_core_path);
|
||||||
@ -1292,24 +1334,40 @@ static void task_update_installed_cores_handler(retro_task_t *task)
|
|||||||
* successfully */
|
* successfully */
|
||||||
if (update_installed_handle->list_size > 0)
|
if (update_installed_handle->list_size > 0)
|
||||||
{
|
{
|
||||||
/* > Check whether a non-zero number of cores
|
char task_title[PATH_MAX_LENGTH];
|
||||||
* were updated */
|
|
||||||
|
task_title[0] = '\0';
|
||||||
|
|
||||||
|
/* > Generate final status message based on number
|
||||||
|
* of cores that were updated/locked */
|
||||||
if (update_installed_handle->num_updated > 0)
|
if (update_installed_handle->num_updated > 0)
|
||||||
{
|
{
|
||||||
char task_title[PATH_MAX_LENGTH];
|
if (update_installed_handle->num_locked > 0)
|
||||||
|
snprintf(
|
||||||
task_title[0] = '\0';
|
task_title, sizeof(task_title), "%s [%s%u, %s%u]",
|
||||||
|
msg_hash_to_str(MSG_ALL_CORES_UPDATED),
|
||||||
|
msg_hash_to_str(MSG_NUM_CORES_UPDATED),
|
||||||
|
update_installed_handle->num_updated,
|
||||||
|
msg_hash_to_str(MSG_NUM_CORES_LOCKED),
|
||||||
|
update_installed_handle->num_locked);
|
||||||
|
else
|
||||||
|
snprintf(
|
||||||
|
task_title, sizeof(task_title), "%s [%s%u]",
|
||||||
|
msg_hash_to_str(MSG_ALL_CORES_UPDATED),
|
||||||
|
msg_hash_to_str(MSG_NUM_CORES_UPDATED),
|
||||||
|
update_installed_handle->num_updated);
|
||||||
|
}
|
||||||
|
else if (update_installed_handle->num_locked > 0)
|
||||||
snprintf(
|
snprintf(
|
||||||
task_title, sizeof(task_title), "%s [%s%u]",
|
task_title, sizeof(task_title), "%s [%s%u]",
|
||||||
msg_hash_to_str(MSG_ALL_CORES_UPDATED),
|
msg_hash_to_str(MSG_ALL_CORES_UPDATED),
|
||||||
msg_hash_to_str(MSG_NUM_CORES_UPDATED),
|
msg_hash_to_str(MSG_NUM_CORES_LOCKED),
|
||||||
update_installed_handle->num_updated);
|
update_installed_handle->num_locked);
|
||||||
|
|
||||||
task_set_title(task, strdup(task_title));
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
task_set_title(task, strdup(msg_hash_to_str(MSG_ALL_CORES_UPDATED)));
|
strlcpy(task_title, msg_hash_to_str(MSG_ALL_CORES_UPDATED),
|
||||||
|
sizeof(task_title));
|
||||||
|
|
||||||
|
task_set_title(task, strdup(task_title));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
task_set_title(task, strdup(msg_hash_to_str(MSG_CORE_LIST_FAILED)));
|
task_set_title(task, strdup(msg_hash_to_str(MSG_CORE_LIST_FAILED)));
|
||||||
@ -1370,6 +1428,7 @@ void task_push_update_installed_cores(
|
|||||||
update_installed_handle->list_index = 0;
|
update_installed_handle->list_index = 0;
|
||||||
update_installed_handle->installed_index = 0;
|
update_installed_handle->installed_index = 0;
|
||||||
update_installed_handle->num_updated = 0;
|
update_installed_handle->num_updated = 0;
|
||||||
|
update_installed_handle->num_locked = 0;
|
||||||
update_installed_handle->status = UPDATE_INSTALLED_CORES_BEGIN;
|
update_installed_handle->status = UPDATE_INSTALLED_CORES_BEGIN;
|
||||||
|
|
||||||
if (!update_installed_handle->core_list)
|
if (!update_installed_handle->core_list)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user