diff --git a/command.c b/command.c index 18cd052dbe..aa531be504 100644 --- a/command.c +++ b/command.c @@ -1624,14 +1624,7 @@ static void command_event_undo_save_state(char *s, size_t len) } if (!content_undo_save_state()) - { - snprintf(s, len, "%s \"%s\".", - msg_hash_to_str(MSG_FAILED_TO_UNDO_SAVE_STATE), - "RAM"); return; - } - - strlcpy(s, msg_hash_to_str(MSG_RESTORED_OLD_SAVE_STATE), len); } /** diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index f338cedb63..2f2a618d84 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -141,7 +141,7 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) "Complete by toggling eject again."); break; case RARCH_GRAB_MOUSE_TOGGLE: - snprintf(s, len, + snprintf(s, len, "Toggles mouse grab. \n" " \n" "When mouse is grabbed, RetroArch hides the \n" @@ -485,7 +485,7 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) "Hide input descriptors that were not set \n" "by the core."); break; - case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE: + case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE: snprintf(s, len, "Video refresh rate of your monitor. \n" "Used to calculate a suitable audio input rate."); @@ -634,7 +634,7 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) char u[501]; char t[501]; - strlcpy(t, + strlcpy(t, "RetroArch relies on an unique form of\n" "audio/video synchronization where it needs to be\n" "calibrated against the refresh rate of your\n" @@ -1500,7 +1500,7 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) " Possible values are [0.0, 1.0]."); break; case MENU_ENUM_LABEL_INPUT_TURBO_PERIOD: - snprintf(s, len, + snprintf(s, len, "Turbo period.\n" " \n" "Describes the period of which turbo-enabled\n" @@ -1510,7 +1510,7 @@ int menu_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) ); break; case MENU_ENUM_LABEL_INPUT_DUTY_CYCLE: - snprintf(s, len, + snprintf(s, len, "Duty cycle.\n" " \n" "Describes how long the period of a turbo-enabled\n" @@ -2602,7 +2602,7 @@ static const char *menu_hash_to_str_us_label_enum(enum msg_hash_enums msg) return "video_aspect_ratio_auto"; case MENU_ENUM_LABEL_VIDEO_FORCE_ASPECT: return "video_force_aspect"; - case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE: + case MENU_ENUM_LABEL_VIDEO_REFRESH_RATE: return "video_refresh_rate"; case MENU_ENUM_LABEL_VIDEO_FORCE_SRGB_DISABLE: return "video_force_srgb_disable"; @@ -3335,6 +3335,8 @@ const char *msg_hash_to_str_us(enum msg_hash_enums msg) return "to"; case MSG_SAVING_RAM_TYPE: return "Saving RAM type"; + case MSG_UNDOING_SAVE_STATE: + return "Undoing save state"; case MSG_SAVING_STATE: return "Saving state"; case MSG_LOADING_STATE: diff --git a/msg_hash.h b/msg_hash.h index f293ff5f82..2267279c99 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1,7 +1,7 @@ /* RetroArch - A frontend for libretro. * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2016 - Daniel De Matteis - * + * * 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. @@ -251,6 +251,7 @@ enum msg_hash_enums MSG_FAILED_TO_TAKE_SCREENSHOT, MSG_CUSTOM_TIMING_GIVEN, MSG_SAVING_STATE, + MSG_UNDOING_SAVE_STATE, MSG_LOADING_STATE, MSG_FAILED_TO_SAVE_STATE_TO, MSG_FAILED_TO_SAVE_SRAM, @@ -399,7 +400,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_CPU_CORES, /* Input */ - + MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE, MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE_LAST = MENU_ENUM_LABEL_INPUT_LIBRETRO_DEVICE + MAX_USERS, MENU_ENUM_LABEL_INPUT_PLAYER_ANALOG_DPAD_MODE, @@ -563,7 +564,7 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_WIDTH, MENU_ENUM_LABEL_VALUE_VIDEO_VIEWPORT_CUSTOM_HEIGHT, MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION, - + MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE, MENU_ENUM_LABEL_VALUE_PARENT_DIRECTORY, diff --git a/tasks/task_save.c b/tasks/task_save.c index 140f99fc1d..13fcb2a8cc 100644 --- a/tasks/task_save.c +++ b/tasks/task_save.c @@ -83,6 +83,7 @@ typedef struct ssize_t bytes_read; bool load_to_backup_buffer; bool autoload; + bool undo_save; } save_task_state_t; typedef save_task_state_t load_task_data_t; @@ -466,17 +467,9 @@ bool content_undo_load_state(void) return ret; } -/** - * undo_save_state: - * Reverts the last save operation - * - * Returns: true if successful, false otherwise. - **/ -bool content_undo_save_state(void) +static void undo_save_state_cb(void *task_data, + void *user_data, const char *error) { - bool ret = filestream_write_file(undo_save_buf.path, - undo_save_buf.data, undo_save_buf.size); - /* Wipe the save file buffer as it's intended to be one use only */ undo_save_buf.path[0] = '\0'; undo_save_buf.size = 0; @@ -485,15 +478,6 @@ bool content_undo_save_state(void) free(undo_save_buf.data); undo_save_buf.data = NULL; } - - if (!ret) - { - RARCH_ERR("%s \"%s\".\n", - msg_hash_to_str(MSG_FAILED_TO_UNDO_SAVE_STATE), - undo_save_buf.path); - } - - return ret; } /** @@ -514,33 +498,12 @@ static void task_save_handler_finished(retro_task_t *task, task->error = strdup("Task canceled"); if (state->data) + { + if (state->undo_save && state->data == undo_save_buf.data) + undo_save_buf.data = NULL; free(state->data); - - free(state); -} - -/** - * task_load_handler_finished: - * @task : the task to finish - * @state : the state associated with this task - * - * Close the loaded state file and finish the task. - **/ -static void task_load_handler_finished(retro_task_t *task, - save_task_state_t *state) -{ - load_task_data_t *task_data = NULL; - task->finished = true; - - filestream_close(state->file); - - if (!task->error && task->cancelled) - task->error = strdup("Task canceled"); - - task_data = (load_task_data_t*)calloc(1, sizeof(*task_data)); - memcpy(task_data, state, sizeof(*task_data)); - - task->task_data = task_data; + state->data = NULL; + } free(state); } @@ -575,7 +538,20 @@ static void task_save_handler(retro_task_t *task) if (task->cancelled || written != remaining) { char err[PATH_MAX_LENGTH] = {0}; - snprintf(err, sizeof(err), "%s %s", msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), state->path); + + if (state->undo_save) + { + RARCH_ERR("%s \"%s\".\n", + msg_hash_to_str(MSG_FAILED_TO_UNDO_SAVE_STATE), + undo_save_buf.path); + + snprintf(err, sizeof(err), "%s \"%s\".", + msg_hash_to_str(MSG_FAILED_TO_UNDO_SAVE_STATE), + "RAM"); + } + else + snprintf(err, sizeof(err), "%s %s", msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), state->path); + task->error = strdup(err); task_save_handler_finished(task, state); return; @@ -586,26 +562,106 @@ static void task_save_handler(retro_task_t *task) settings_t *settings = config_get_ptr(); char msg[1024] = {0}; - task_save_handler_finished(task, state); - if (task->title) free(task->title); task->title = NULL; - if (settings->state_slot < 0) - snprintf(msg, sizeof(msg), "%s #-1 (auto).", - msg_hash_to_str(MSG_SAVED_STATE_TO_SLOT)); + if (state->undo_save) + { + strlcpy(msg, msg_hash_to_str(MSG_RESTORED_OLD_SAVE_STATE), + sizeof(msg)); + } else - snprintf(msg, sizeof(msg), "%s #%d.", msg_hash_to_str(MSG_SAVED_STATE_TO_SLOT), - settings->state_slot); + { + if (settings->state_slot < 0) + snprintf(msg, sizeof(msg), "%s #-1 (auto).", + msg_hash_to_str(MSG_SAVED_STATE_TO_SLOT)); + else + snprintf(msg, sizeof(msg), "%s #%d.", msg_hash_to_str(MSG_SAVED_STATE_TO_SLOT), + settings->state_slot); + } runloop_msg_queue_push(msg, 2, 180, true); + task_save_handler_finished(task, state); return; } } +/** + * task_push_undo_save_state: + * @path : file path of the save state + * @data : the save state data to write + * @size : the total size of the save state + * + * Create a new task to undo the last save of the content state. + **/ +static void task_push_undo_save_state(const char *path, void *data, size_t size) +{ + retro_task_t *task = (retro_task_t*)calloc(1, sizeof(*task)); + save_task_state_t *state = (save_task_state_t*)calloc(1, sizeof(*state)); + + if (!task || !state) + { + if (data) + free(data); + return; + } + + strlcpy(state->path, path, sizeof(state->path)); + state->data = data; + state->size = size; + state->undo_save = true; + + task->state = state; + task->handler = task_save_handler; + task->callback = undo_save_state_cb; + task->title = strdup(msg_hash_to_str(MSG_UNDOING_SAVE_STATE)); + + task_queue_ctl(TASK_QUEUE_CTL_PUSH, task); +} + +/** + * undo_save_state: + * Reverts the last save operation + * + * Returns: true if successful, false otherwise. + **/ +bool content_undo_save_state(void) +{ + task_push_undo_save_state(undo_save_buf.path, + undo_save_buf.data, + undo_save_buf.size); + return true; +} + +/** + * task_load_handler_finished: + * @task : the task to finish + * @state : the state associated with this task + * + * Close the loaded state file and finish the task. + **/ +static void task_load_handler_finished(retro_task_t *task, + save_task_state_t *state) +{ + load_task_data_t *task_data = NULL; + task->finished = true; + + filestream_close(state->file); + + if (!task->error && task->cancelled) + task->error = strdup("Task canceled"); + + task_data = (load_task_data_t*)calloc(1, sizeof(*task_data)); + memcpy(task_data, state, sizeof(*task_data)); + + task->task_data = task_data; + + free(state); +} + /** * task_load_handler: * @task : the task being worked on